Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions .github/workflows/verifier-ray.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
name: verifier-ray

on:
pull_request:
branches:
- main
paths:
- 'verifier-ray/**'
- 'prover-ray/**'
- '.github/workflows/verifier-ray.yml'
push:
branches:
- main
paths:
- 'verifier-ray/**'
- 'prover-ray/**'
- '.github/workflows/verifier-ray.yml'
workflow_call:
workflow_dispatch:

permissions:
contents: read
actions: read

env:
GO_VERSION: '1.25.7'
GO_CORSET_VERSION: 'v1.2.14'
GO_CORSET_REF_FOR_ZKC: 'v1.2.14'
ZIG_VERSION: '0.17.0-dev.251+0db721ec2'

concurrency:
group: verifier-ray-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}

jobs:
test:
runs-on: gha-runner-scale-set-ubuntu-24-amd64-small
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
submodules: false

# Keep this aligned with .github/actions/setup-arithmetization-riscv, but use
# newer Go because verifier-ray/prover-ray modules declare go 1.25.7.
- name: Install Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: ${{ env.GO_VERSION }}
cache-dependency-path: "**/*.sum"

- name: Install Zig
uses: mlugg/setup-zig@d1434d08867e3ee9daa34448df10607b98908d29 # v2.2.1
with:
version: ${{ env.ZIG_VERSION }}

- name: Install riscv64-unknown-elf-as
run: sudo apt-get update && sudo apt-get install -y binutils-riscv64-unknown-elf

- name: Install go-corset and zkc
run: |
go install github.com/consensys/go-corset/cmd/go-corset@${GO_CORSET_VERSION}
go install github.com/consensys/go-corset/cmd/zkc@${GO_CORSET_REF_FOR_ZKC}
go-corset --version
go version -m "$(which zkc)"

- name: Verifier-ray format check
working-directory: verifier-ray
run: make fmt

- name: Verifier-ray generated testdata
working-directory: verifier-ray
run: make verify-testdata

- name: Verifier-ray build
working-directory: verifier-ray
run: make build

- name: Verifier-ray tests
working-directory: verifier-ray
run: make test

- name: ZKC verifier smoke test
working-directory: verifier-ray
run: make zkc-verify
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ tmp/
typechain/
typechain-types/
generated/
!/verifier-ray/src/generated/
!/verifier-ray/src/generated/**
!/verifier-ray/testdata/generated/
!/verifier-ray/testdata/generated/**
__pycache__/

/linea-besu/plugins/linea-sequencer/**/site
Expand Down
3 changes: 3 additions & 0 deletions verifier-ray/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.zig-cache/
zig-out/

54 changes: 54 additions & 0 deletions verifier-ray/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
SHELL := /bin/bash

.PHONY: ci fmt fmt-zig fmt-codegen fmt-testdata-generate build build-zig build-release test test-zig test-generated-zig test-codegen generate-testdata verify-testdata zkc-verify clean

ci: fmt build test zkc-verify

fmt: fmt-zig fmt-codegen fmt-testdata-generate

fmt-zig:
zig fmt --check build.zig src test testdata/generated

fmt-codegen:
@if [[ -n "$$(gofmt -l codegen)" ]]; then \
echo "please run gofmt"; \
gofmt -l codegen; \
exit 1; \
fi

fmt-testdata-generate:
@if [[ -n "$$(gofmt -l testdata/generate)" ]]; then \
echo "please run gofmt"; \
gofmt -l testdata/generate; \
exit 1; \
fi

build: build-zig

build-zig:
zig build

build-release:
zig build -Doptimize=ReleaseSmall -Dstrip=true

test: test-zig test-codegen

test-zig: verify-testdata
zig build test

test-generated-zig: test-zig

test-codegen:
cd codegen && go test ./...

generate-testdata:
cd testdata/generate && go run .

verify-testdata: generate-testdata
git diff --exit-code -- testdata/generated/vectors.zig

zkc-verify:
@echo "zkc verifier smoke test is not wired yet; skipping."

clean:
rm -rf .zig-cache zig-out
31 changes: 31 additions & 0 deletions verifier-ray/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# verifier-ray

`verifier-ray` is the initial Zig verifier package for Ray proofs.

The package is intentionally independent from `prover-ray` at the directory
level. The fixed verifier runtime, field arithmetic, cryptographic primitives,
and zkVM precompile interface live here. Code generation can also live here and
import `prover-ray` structures when needed.

## Layout

- `src/` contains the Zig verifier library and executable entry point.
- `src/generated/` contains generated verifier stubs.
- `codegen/` contains the Go code generation tool skeleton.
- `test/` contains Zig unit tests.
- `testdata/` holds fixtures exported from `prover-ray`.

## Local Checks

```bash
make fmt
make verify-testdata
make build
make build-release
make test
make zkc-verify
```

The current implementation covers Milestone 1 static field, extension,
polynomial, Poseidon2, and Fiat-Shamir primitives with prover-ray golden tests.
Vortex verification and zkVM `zkc` execution are still placeholders.
49 changes: 49 additions & 0 deletions verifier-ray/build.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
const std = @import("std");

pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const strip = b.option(bool, "strip", "Omit debug symbols") orelse (optimize == .ReleaseSmall);

const verifier_mod = b.addModule("verifier_ray", .{
.root_source_file = b.path("src/lib.zig"),
.target = target,
.optimize = optimize,
.strip = strip,
});
const test_vectors_mod = b.addModule("test_vectors", .{
.root_source_file = b.path("testdata/generated/vectors.zig"),
.target = target,
.optimize = optimize,
});

const exe = b.addExecutable(.{
.name = "verifier-ray",
.root_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
.strip = strip,
.imports = &.{
.{ .name = "verifier_ray", .module = verifier_mod },
},
}),
});
b.installArtifact(exe);

const unit_tests = b.addTest(.{
.root_module = b.createModule(.{
.root_source_file = b.path("test/all.zig"),
.target = target,
.optimize = optimize,
.imports = &.{
.{ .name = "verifier_ray", .module = verifier_mod },
.{ .name = "test_vectors", .module = test_vectors_mod },
},
}),
});

const run_unit_tests = b.addRunArtifact(unit_tests);
const test_step = b.step("test", "Run verifier-ray unit tests");
test_step.dependOn(&run_unit_tests.step);
}
15 changes: 15 additions & 0 deletions verifier-ray/build.zig.zon
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.{
.name = .verifier_ray,
.fingerprint = 0xd1f807a3b6cefe12,
.version = "0.1.0",
.minimum_zig_version = "0.16.0",
.dependencies = .{},
.paths = .{
"README.md",
"build.zig",
"build.zig.zon",
"src",
"test",
"testdata",
},
}
25 changes: 25 additions & 0 deletions verifier-ray/codegen/cmd/ray-zig-codegen/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package main

import (
"flag"
"fmt"
"os"

"github.com/consensys/linea-monorepo/verifier-ray/codegen/internal/generator"
)

func main() {
entryPoint := flag.String("entry", "verifyGenerated", "name of the generated Zig verifier entry point")
flag.Parse()

system := generator.System{
Rounds: []generator.Round{
{ID: 0, VerifierActions: []string{"stub"}},
},
}

if err := generator.Generate(system, generator.Options{EntryPoint: *entryPoint}, os.Stdout); err != nil {
fmt.Fprintf(os.Stderr, "ray-zig-codegen: %v\n", err)
os.Exit(1)
}
}
4 changes: 4 additions & 0 deletions verifier-ray/codegen/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module github.com/consensys/linea-monorepo/verifier-ray/codegen

go 1.25.7

4 changes: 4 additions & 0 deletions verifier-ray/codegen/internal/generator/emitters.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package generator

// This file is reserved for action-specific emitters once prover-ray verifier
// actions are connected to verifier-ray code generation.
57 changes: 57 additions & 0 deletions verifier-ray/codegen/internal/generator/generator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package generator

import (
"fmt"
"io"
)

// Options controls Zig verifier source generation.
type Options struct {
// EntryPoint is the generated verifier function name.
EntryPoint string
}

// System is the minimal codegen input used by the initial stub generator.
// It will be replaced with, or adapted from, prover-ray compiled IOP objects.
type System struct {
Rounds []Round
}

// Round describes one verifier round in generated output.
type Round struct {
ID int
VerifierActions []string
}

// Generate emits a compilable Zig verifier stub.
func Generate(system System, opts Options, dst io.Writer) error {
if opts.EntryPoint == "" {
opts.EntryPoint = defaultEntryPoint
}

w := &Writer{}
w.Line("// Code generated by verifier-ray/codegen. DO NOT EDIT.")
w.Line("const proof_mod = @import(\"../proof.zig\");")
w.Line("const runtime_mod = @import(\"../runtime.zig\");")
w.Line("const verifier = @import(\"../verifier.zig\");")
w.Blank()
w.Line("pub fn %s(rt: *runtime_mod.Runtime, p: proof_mod.Proof) verifier.VerifyError!void {", opts.EntryPoint)
w.In()
w.Line("_ = p;")
for _, round := range system.Rounds {
w.Line("// Round %d", round.ID)
for _, action := range round.VerifierActions {
w.Line("// verifier action: %s", action)
}
w.Line("rt.advanceRound();")
}
w.Line("return verifier.VerifyError.Unsupported;")
w.Out()
w.Line("}")

_, err := io.WriteString(dst, w.String())
if err != nil {
return fmt.Errorf("write generated Zig: %w", err)
}
return nil
}
42 changes: 42 additions & 0 deletions verifier-ray/codegen/internal/generator/generator_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package generator_test

import (
"bytes"
"strings"
"testing"

"github.com/consensys/linea-monorepo/verifier-ray/codegen/internal/generator"
)

func TestGenerate_DefaultEntryPoint(t *testing.T) {
var buf bytes.Buffer
err := generator.Generate(generator.System{
Rounds: []generator.Round{
{ID: 0, VerifierActions: []string{"commitment"}},
{ID: 1, VerifierActions: []string{"quotient"}},
},
}, generator.Options{}, &buf)
if err != nil {
t.Fatalf("Generate returned error: %v", err)
}

src := buf.String()
if !strings.Contains(src, "pub fn verifyGenerated") {
t.Fatalf("generated source is missing default entry point:\n%s", src)
}
if got := strings.Count(src, "rt.advanceRound();"); got != 2 {
t.Fatalf("expected one advance per round, got %d:\n%s", got, src)
}
}

func TestGenerate_CustomEntryPoint(t *testing.T) {
var buf bytes.Buffer
err := generator.Generate(generator.System{}, generator.Options{EntryPoint: "verifyFib"}, &buf)
if err != nil {
t.Fatalf("Generate returned error: %v", err)
}

if !strings.Contains(buf.String(), "pub fn verifyFib") {
t.Fatalf("generated source is missing custom entry point:\n%s", buf.String())
}
}
3 changes: 3 additions & 0 deletions verifier-ray/codegen/internal/generator/options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package generator

const defaultEntryPoint = "verifyGenerated"
Comment thread
cursor[bot] marked this conversation as resolved.
Loading
Loading