From 4b478ffb87cfb5f6cbdb29a78135e9d054bef7ae Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Mon, 31 Mar 2025 13:36:53 +0200 Subject: [PATCH] R1CS gen refactor --- Cargo.toml | 2 +- merkle-hash-bench/Cargo.toml | 2 +- noir-r1cs/src/main.rs | 8 +++- .../src/{compiler.rs => r1cs/acir_source.rs} | 38 ++++++++----------- noir-r1cs/src/r1cs/matrix_sink.rs | 36 ++++++++++++++++++ noir-r1cs/src/r1cs/mod.rs | 9 +++++ 6 files changed, 69 insertions(+), 26 deletions(-) rename noir-r1cs/src/{compiler.rs => r1cs/acir_source.rs} (85%) create mode 100644 noir-r1cs/src/r1cs/matrix_sink.rs create mode 100644 noir-r1cs/src/r1cs/mod.rs diff --git a/Cargo.toml b/Cargo.toml index ac099cfaa..19ad429e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +49,7 @@ tracing = "0.1.41" tracing-subscriber = { version = "0.3.18", features = ["env-filter", "ansi"] } base64 = "0.22.1" ruint = { version = "1.12.3", features = ["num-traits", "rand"] } -rand = "0.8.5" +rand = "0.9.0" subtle = "2.6.1" bytemuck = "1.19.0" hex-literal = "0.4.1" diff --git a/merkle-hash-bench/Cargo.toml b/merkle-hash-bench/Cargo.toml index a5ee5dd2f..0bd690420 100644 --- a/merkle-hash-bench/Cargo.toml +++ b/merkle-hash-bench/Cargo.toml @@ -67,7 +67,7 @@ icicle-bn254 = { git = "https://github.com/ingonyama-zk/icicle.git", branch = "m icicle-m31 = { git = "https://github.com/ingonyama-zk/icicle.git", branch = "main", optional = true } # ZKHash -zkhash = { git = "https://extgit.isec.tugraz.at/krypto/zkfriendlyhashzoo.git", commit = "f252d2b2767bc88659615601ac13e19f52c2c11f", optional = true } +zkhash = { git = "https://extgit.isec.tugraz.at/krypto/zkfriendlyhashzoo.git", rev = "f252d2b2767bc88659615601ac13e19f52c2c11f", optional = true } # Stwo stwo-prover = { git = "https://github.com/starkware-libs/stwo.git", version = "0.1.1", optional = true } diff --git a/noir-r1cs/src/main.rs b/noir-r1cs/src/main.rs index b0433a8c1..50205ce54 100644 --- a/noir-r1cs/src/main.rs +++ b/noir-r1cs/src/main.rs @@ -1,5 +1,6 @@ #![doc = include_str!("../README.md")] mod compiler; +mod r1cs_emitter; mod sparse_matrix; mod utils; @@ -119,6 +120,7 @@ fn noir(args: NoirCmd) -> AnyResult<()> { witness[2] = Some(FieldElement::from(5678_u32)); // b // Solve constraints (this is how Noir expects it to be done, judging from ACVM) + info!("Solving for witness."); for row in 0..r1cs.constraints { let [a, b, c] = [&r1cs.a, &r1cs.b, &r1cs.c].map(|mat| sparse_dot(mat.iter_row(row), &witness)); @@ -135,9 +137,10 @@ fn noir(args: NoirCmd) -> AnyResult<()> { let Some((col, val)) = solve_dot(mat.iter_row(row), &witness, val) else { panic!("Could not solve constraint {row}.") }; - eprintln!("Constraint {row}: Solved for witness[{col}] = {val}"); + // eprintln!("Constraint {row}: Solved for witness[{col}] = {val}"); witness[col] = Some(val); } + info!("Witness found."); // Complete witness with entropy. // TODO: Use better entropy source and proper sampling. @@ -147,7 +150,7 @@ fn noir(args: NoirCmd) -> AnyResult<()> { .map(|f| f.unwrap_or_else(|| FieldElement::from(rng.random::()))) .collect::>(); - dbg!(&witness); + // dbg!(&witness); // Verify let a = mat_mul(&r1cs.a, &witness); @@ -160,6 +163,7 @@ fn noir(args: NoirCmd) -> AnyResult<()> { .for_each(|(row, ((&a, &b), &c))| { assert_eq!(a * b, c, "Constraint {row} failed"); }); + info!("Witness verified."); // dbg!(&a); // dbg!(&b); diff --git a/noir-r1cs/src/compiler.rs b/noir-r1cs/src/r1cs/acir_source.rs similarity index 85% rename from noir-r1cs/src/compiler.rs rename to noir-r1cs/src/r1cs/acir_source.rs index 9ee6833a5..97e8e0f1e 100644 --- a/noir-r1cs/src/compiler.rs +++ b/noir-r1cs/src/r1cs/acir_source.rs @@ -1,5 +1,5 @@ use { - crate::SparseMatrix, + super::ConstraintSink, acir::{ circuit::{Circuit, Opcode}, native_types::{Expression, Witness}, @@ -8,30 +8,24 @@ use { std::collections::BTreeMap, }; -/// Represents a R1CS constraint system. +/// Represents a R1CS constraint source from ACIR. #[derive(Debug, Clone)] -pub struct R1CS { - pub a: SparseMatrix, - pub b: SparseMatrix, - pub c: SparseMatrix, - - // Remapping of witness indices to the r1cs_witness array - pub witnesses: usize, - pub remap: BTreeMap, - - pub constraints: usize, +pub struct AcirSource<'a> { + circuit: &'a Circuit, + witnesses: usize, + constraints: usize, + witness_map: Vec, } -impl R1CS { - pub fn new() -> Self { - Self { - a: SparseMatrix::new(0, 1, FieldElement::zero()), - b: SparseMatrix::new(0, 1, FieldElement::zero()), - c: SparseMatrix::new(0, 1, FieldElement::zero()), - witnesses: 1, - remap: BTreeMap::new(), - constraints: 0, - } +impl<'a> AcirSource<'a> { + pub fn new(circuit: &'a Circuit) -> Self { + let witness_map = vec![None; circuit.num_witnesses()]; + // Do a preprocessing pass to compute the dimensions and witness map. + Self {} + } + + pub fn emit(&self, sink: &mut impl ConstraintSink) { + todo!(); } pub fn add_circuit(&mut self, circuit: &Circuit) { diff --git a/noir-r1cs/src/r1cs/matrix_sink.rs b/noir-r1cs/src/r1cs/matrix_sink.rs new file mode 100644 index 000000000..e497dae59 --- /dev/null +++ b/noir-r1cs/src/r1cs/matrix_sink.rs @@ -0,0 +1,36 @@ +/// Represents a R1CS constraint system as Sparse Matrices. +#[derive(Debug, Clone)] +pub struct MatrixSink { + pub a: SparseMatrix, + pub b: SparseMatrix, + pub c: SparseMatrix, +} + +impl MatrixSink { + pub fn new(witnesses: usize, constraints: usize) -> Self { + Self { + a: SparseMatrix::new(constraints, witnesses, FieldElement::zero()), + b: SparseMatrix::new(constraints, witnesses, FieldElement::zero()), + c: SparseMatrix::new(constraints, witnesses, FieldElement::zero()), + } + } +} + +impl ConstraintSink for MatrixSink { + fn add_constraint( + &mut self, + a: &[(FieldElement, usize)], + b: &[(FieldElement, usize)], + c: &[(FieldElement, usize)], + ) { + for (c, col) in a.iter().copied() { + self.a.set(row, col, c) + } + for (c, col) in b.iter().copied() { + self.b.set(row, col, c) + } + for (c, col) in c.iter().copied() { + self.c.set(row, col, c) + } + } +} diff --git a/noir-r1cs/src/r1cs/mod.rs b/noir-r1cs/src/r1cs/mod.rs new file mode 100644 index 000000000..8f87e7c6f --- /dev/null +++ b/noir-r1cs/src/r1cs/mod.rs @@ -0,0 +1,9 @@ +pub trait ConstraintSink { + /// Add an R1CS constraint. + fn add_constraint( + &mut self, + a: &[(FieldElement, usize)], + b: &[(FieldElement, usize)], + c: &[(FieldElement, usize)], + ); +}