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
43 changes: 15 additions & 28 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,60 +2,47 @@ name: CI

on:
push:
branches: [ main, develop, yugo ]
branches: [ main, develop ]
pull_request:
branches: [ main ]

env:
CARGO_TERM_COLOR: always
RUSTFLAGS: ""

jobs:
# ---------- rustfmt ----------
lint:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with: { components: rustfmt }
- run: cargo fmt --all -- --check

- name: Install Rust (with rustfmt)
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt

- name: Cache dependencies
uses: actions/cache@v3
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}

- name: Check formatting with rustfmt
run: cargo fmt --all -- --check


# ---------- Tests (independent) ----------
test:
needs: lint
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Install Rust
uses: dtolnay/rust-toolchain@stable
# Rust toolchain
- uses: dtolnay/rust-toolchain@stable

- name: Cache dependencies
uses: actions/cache@v3
# Cache Cargo deps
- uses: actions/cache@v3
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}

# ---------- Build all Noir circuits ----------
- name: Generate proofs & VKs
run: tests/build_circuits.sh

# ---------- Run Rust tests ----------
- name: Run tests
run: cargo test --verbose

- name: Run tests with all features
run: cargo test --verbose --all-features
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
[package]
name = "ultrahonk_verifier"
name = "ultrahonk_rust_verifier"
version = "0.1.0"
edition = "2021"

license = "MIT"
description = "Rust verifier for UltraHonk proofs"
repository = "https://github.com/yugocabrio/ultrahonk-rust-verifier"

[dependencies]
sha3 = "0.10"

Expand Down
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2025 yugocabrio & indextree

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
6 changes: 6 additions & 0 deletions circuits/fib_chain/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "fib_chain"
type = "bin"
authors = [""]

[dependencies]
3 changes: 3 additions & 0 deletions circuits/fib_chain/Prover.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
a0 = "1"
a1 = "1"
out = "144"
15 changes: 15 additions & 0 deletions circuits/fib_chain/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
fn fib10(a0: Field, a1: Field) -> Field {
let mut prev = a0;
let mut curr = a1;
for _ in 0..10 {
let next = prev + curr;
prev = curr;
curr = next;
}
curr
}

pub fn main(a0: Field, a1: Field, out: pub Field) {
let result = fib10(a0, a1);
assert(result == out);
}
6 changes: 6 additions & 0 deletions circuits/poseidon2_demo/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "poseidon2_demo"
type = "bin"
authors = [""]

[dependencies]
3 changes: 3 additions & 0 deletions circuits/poseidon2_demo/Prover.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
secret = "123"
blinding = "456"
commit = "9294101456775059509749539201395100557982398719771580517121235895346398435934"
6 changes: 6 additions & 0 deletions circuits/poseidon2_demo/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
use std::hash::poseidon2::Poseidon2;

pub fn main(secret: Field, blinding: Field, commit: pub Field) {
let c = Poseidon2::hash([secret, blinding], 2);
assert(c == commit);
}
6 changes: 6 additions & 0 deletions circuits/simple_circuit/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "simple_circuit"
type = "bin"
authors = [""]

[dependencies]
2 changes: 2 additions & 0 deletions circuits/simple_circuit/Prover.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
x = "1"
y = "2"
11 changes: 11 additions & 0 deletions circuits/simple_circuit/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
fn main(x: Field, y: pub Field) {
assert(x != y);
}

#[test]
fn test_main() {
main(1, 2);

// Uncomment to make test fail
// main(1, 1);
}
14 changes: 0 additions & 14 deletions src/field.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// field.rs
//! Finite-field wrapper for BN254 Fr, compatible with Arkworks 0.5.

use ark_bn254::Fr as ArkFr;
use ark_ff::BigInteger256;
Expand All @@ -8,8 +7,6 @@ use ark_serialize::CanonicalSerialize;
use hex;
use std::ops::{Add, Mul, Neg, Sub};

/*──────────────────────────── Helper to avoid OddLength ──────────────────────────*/
/// Strip "0x..." and if odd digits, prepend '0' to **always make even digits**.
#[inline(always)]
fn normalize_hex(s: &str) -> String {
let raw = s.trim_start_matches("0x");
Expand All @@ -23,14 +20,10 @@ fn normalize_hex(s: &str) -> String {
}
}

/*──────────────────────────── Fr wrapper ──────────────────────────*/

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Fr(pub ArkFr);

impl Fr {
/*--------- constructors ---------*/

/// Construct from u64.
pub fn from_u64(x: u64) -> Self {
Fr(ArkFr::from(x))
Expand All @@ -54,8 +47,6 @@ impl Fr {
Fr(ArkFr::from_le_bytes_mod_order(&tmp))
}

/*--------- conversions ---------*/

/// Convert to 32-byte big-endian representation.
#[inline(always)]
pub fn to_bytes(&self) -> [u8; 32] {
Expand All @@ -67,13 +58,10 @@ impl Fr {
out
}

/// Convert to "0x..." hex string (always 64 digits) — for debugging.
pub fn to_hex(&self) -> String {
format!("0x{}", hex::encode(self.to_bytes()))
}

/*--------- math helpers ---------*/

pub fn inverse(&self) -> Self {
Fr(self.0.inverse().unwrap())
}
Expand Down Expand Up @@ -101,8 +89,6 @@ impl Fr {
}
}

/*──────────────────────────── Operators / Serialize ──────────────────────────*/

impl Add for Fr {
type Output = Fr;
fn add(self, rhs: Fr) -> Fr {
Expand Down
3 changes: 1 addition & 2 deletions src/crypto.rs → src/hash.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// crypto.rs
//! Keccak-256 hashing utilities.
// hash.rs

use sha3::{Digest, Keccak256};

Expand Down
41 changes: 3 additions & 38 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,49 +1,14 @@
// src/lib.rs

pub mod crypto;
pub mod debug;
pub mod field;
pub mod hash;
pub mod relations;
pub mod shplonk;
pub mod shplemini;
pub mod sumcheck;
pub mod transcript;
pub mod types;
pub mod utils;
pub mod verifier;
pub use utils::load_proof_and_public_inputs;
pub use verifier::HonkVerifier;

#[cfg(test)]
mod tests {
use super::*;
use std::fs::File;
use std::io::Read;
use std::path::Path;

#[test]
fn test_simple_proof() -> Result<(), String> {
// 1) Load proof+inputs
let fixtures = Path::new("tests/fixtures");
let mut buf = Vec::new();
File::open(fixtures.join("simple_proof.bin"))
.map_err(|e| e.to_string())?
.read_to_end(&mut buf)
.map_err(|e| e.to_string())?;
let (pub_inputs, proof_bytes) = load_proof_and_public_inputs(&buf);

// 2) Load VK JSON (hex strings)
let vk_path = fixtures.join("simple_vk.json");
// 3) Verify
let verifier = HonkVerifier::new(vk_path.to_str().unwrap());
// serialize pub inputs
let mut inp_bytes = Vec::new();
for fr in pub_inputs {
let mut b = [0u8; 32];
b.copy_from_slice(&fr.to_bytes());
inp_bytes.push(b.to_vec());
}
verifier.verify(&proof_bytes, &inp_bytes)?;
trace!("✅ Verification succeeded");
Ok(())
}
}
pub use verifier::UltraHonkVerifier;
2 changes: 1 addition & 1 deletion src/relations.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// relations.rs
//! Relation evaluation accumulation for UltraHonk.
// Relation evaluation accumulation for UltraHonk.
//!
//! This module accumulates all of the UltraHonk relations (arithmetic, permutation,
//! lookup, range, elliptic, auxiliary, Poseidon external/internal) into a single
Expand Down
11 changes: 7 additions & 4 deletions src/shplonk.rs → src/shplemini.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// src/shplonk.rs

//! Shplonk batch-opening verifier for BN254

use crate::debug::dbg_fr;
Expand Down Expand Up @@ -95,7 +94,7 @@ fn batch_mul(coms: &[G1Point], scalars: &[Fr]) -> Result<G1Affine, String> {
/// pairing check
/// This function checks the pairing condition for the given G1 points.
fn pairing_check(p0: &G1Affine, p1: &G1Affine) -> bool {
// fixed RHS G2 (TS inputValues[2-5])
// fixed RHS G2 (inputValues[2-5])
let rhs_g2 = {
let x = Fq2::new(
Fq::from_le_bytes_mod_order(&[
Expand Down Expand Up @@ -157,8 +156,12 @@ fn pairing_check(p0: &G1Affine, p1: &G1Affine) -> bool {
e1.0 * e2.0 == <Bn254 as Pairing>::TargetField::one()
}

/// Shplonk verification
pub fn verify_shplonk(proof: &Proof, vk: &VerificationKey, tx: &Transcript) -> Result<(), String> {
/// Shplemini verification
pub fn verify_shplemini(
proof: &Proof,
vk: &VerificationKey,
tx: &Transcript,
) -> Result<(), String> {
// 1) r^{2^i}
let log_n = vk.log_circuit_size as usize;
let n_sum = proof.sumcheck_evaluations.len();
Expand Down
5 changes: 2 additions & 3 deletions src/sumcheck.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
//! Sum-check verifier ― Ultra-/Plonk‐Honk compatible
//! -------------------------------------------------

// sumcheck.rs
//! Sum-check verifier
use crate::trace;
use crate::{
debug::{dbg_fr, dbg_vec},
Expand Down
Loading