From 77771dba0c6abd11491c375f84e3c4713f8d70f2 Mon Sep 17 00:00:00 2001 From: ashWhiteHat Date: Fri, 24 Nov 2023 13:16:09 +0900 Subject: [PATCH 1/9] refactor: circuit and gadget --- groth16/src/lib.rs | 2 +- nova/src/circuit.rs | 1 + .../circuit.rs => circuit/transcript.rs} | 41 +++---------------- nova/src/gadget.rs | 3 ++ nova/src/gadget/mimc.rs | 33 +++++++++++++++ nova/src/hash.rs | 3 +- nova/src/lib.rs | 4 +- r1cs/src/gadget.rs | 7 +++- 8 files changed, 51 insertions(+), 43 deletions(-) create mode 100644 nova/src/circuit.rs rename nova/src/{hash/circuit.rs => circuit/transcript.rs} (67%) create mode 100644 nova/src/gadget.rs create mode 100644 nova/src/gadget/mimc.rs diff --git a/groth16/src/lib.rs b/groth16/src/lib.rs index 10f11671..abf1a5dc 100644 --- a/groth16/src/lib.rs +++ b/groth16/src/lib.rs @@ -22,7 +22,7 @@ mod tests { use crate::error::Error; use crate::zksnark::ZkSnark; use bn_254::Fr as BnScalar; - use r1cs::gadget::field::FieldAssignment; + use r1cs::gadget::FieldAssignment; use r1cs::{GrumpkinDriver, R1cs}; use zkstd::common::OsRng; diff --git a/nova/src/circuit.rs b/nova/src/circuit.rs new file mode 100644 index 00000000..e24a4638 --- /dev/null +++ b/nova/src/circuit.rs @@ -0,0 +1 @@ +mod transcript; diff --git a/nova/src/hash/circuit.rs b/nova/src/circuit/transcript.rs similarity index 67% rename from nova/src/hash/circuit.rs rename to nova/src/circuit/transcript.rs index 3cdb1fe1..7809b006 100644 --- a/nova/src/hash/circuit.rs +++ b/nova/src/circuit/transcript.rs @@ -1,39 +1,9 @@ -use crate::hash::Mimc; -use r1cs::gadget::curve::PointAssignment; -use r1cs::gadget::field::FieldAssignment; +use crate::gadget::MimcAssignment; + +use r1cs::gadget::{FieldAssignment, PointAssignment}; use r1cs::{CircuitDriver, R1cs}; use zkstd::common::IntGroup; -pub(crate) struct MimcAssignment { - constants: [C::Scalar; ROUND], -} - -impl Default for MimcAssignment { - fn default() -> Self { - Self { - constants: Mimc::::default().constants, - } - } -} - -impl MimcAssignment { - pub(crate) fn hash( - &self, - cs: &mut R1cs, - mut xl: FieldAssignment, - mut xr: FieldAssignment, - ) -> FieldAssignment { - for c in self.constants.iter().map(|c| FieldAssignment::constant(c)) { - let cxl = &xl + &c; - let mut ccxl = FieldAssignment::square(cs, &cxl); - ccxl = &FieldAssignment::mul(cs, &ccxl, &cxl) + &xr; - xr = xl; - xl = ccxl; - } - xl - } -} - pub(crate) struct MimcROCircuit { hasher: MimcAssignment, state: Vec>, @@ -71,12 +41,11 @@ impl MimcROCircuit { #[cfg(test)] mod tests { - use crate::hash::circuit::MimcROCircuit; + use super::MimcROCircuit; use crate::hash::{MimcRO, MIMC_ROUNDS}; use bn_254::Fr; use grumpkin::Affine; - use r1cs::gadget::curve::PointAssignment; - use r1cs::gadget::field::FieldAssignment; + use r1cs::gadget::{FieldAssignment, PointAssignment}; use r1cs::{GrumpkinDriver, R1cs}; use rand_core::OsRng; use zkstd::common::{CurveGroup, Group}; diff --git a/nova/src/gadget.rs b/nova/src/gadget.rs new file mode 100644 index 00000000..ae5fc78c --- /dev/null +++ b/nova/src/gadget.rs @@ -0,0 +1,3 @@ +mod mimc; + +pub(crate) use mimc::MimcAssignment; diff --git a/nova/src/gadget/mimc.rs b/nova/src/gadget/mimc.rs new file mode 100644 index 00000000..db8738af --- /dev/null +++ b/nova/src/gadget/mimc.rs @@ -0,0 +1,33 @@ +use crate::hash::Mimc; +use r1cs::gadget::FieldAssignment; +use r1cs::{CircuitDriver, R1cs}; + +pub(crate) struct MimcAssignment { + constants: [C::Scalar; ROUND], +} + +impl Default for MimcAssignment { + fn default() -> Self { + Self { + constants: Mimc::::default().constants, + } + } +} + +impl MimcAssignment { + pub(crate) fn hash( + &self, + cs: &mut R1cs, + mut xl: FieldAssignment, + mut xr: FieldAssignment, + ) -> FieldAssignment { + for c in self.constants.iter().map(|c| FieldAssignment::constant(c)) { + let cxl = &xl + &c; + let mut ccxl = FieldAssignment::square(cs, &cxl); + ccxl = &FieldAssignment::mul(cs, &ccxl, &cxl) + &xr; + xr = xl; + xl = ccxl; + } + xl + } +} diff --git a/nova/src/hash.rs b/nova/src/hash.rs index 0a5dbafa..91ed5f98 100644 --- a/nova/src/hash.rs +++ b/nova/src/hash.rs @@ -1,4 +1,3 @@ -mod circuit; mod helper; use helper::BlakeHelper; @@ -9,7 +8,7 @@ use zkstd::common::{BNAffine, PrimeField}; pub(crate) const MIMC_ROUNDS: usize = 322; pub(crate) struct Mimc { - constants: [F; ROUND], + pub(crate) constants: [F; ROUND], } impl Default for Mimc { diff --git a/nova/src/lib.rs b/nova/src/lib.rs index 6fb6d939..247e999a 100644 --- a/nova/src/lib.rs +++ b/nova/src/lib.rs @@ -1,14 +1,14 @@ #![doc = include_str!("../README.md")] -#![allow(dead_code)] +mod circuit; mod function; +mod gadget; mod hash; mod ivc; mod pedersen; mod proof; mod prover; mod relaxed_r1cs; - mod verifier; #[cfg(test)] diff --git a/r1cs/src/gadget.rs b/r1cs/src/gadget.rs index 8bc200b4..570fd1a5 100644 --- a/r1cs/src/gadget.rs +++ b/r1cs/src/gadget.rs @@ -1,3 +1,6 @@ mod binary; -pub mod curve; -pub mod field; +mod curve; +mod field; + +pub use curve::*; +pub use field::*; From 9968811725838f39c9df162b2332912155ea2938 Mon Sep 17 00:00:00 2001 From: ashWhiteHat Date: Fri, 24 Nov 2023 14:05:06 +0900 Subject: [PATCH 2/9] feat: r1cs prelude --- groth16/src/circuit.rs | 2 +- groth16/src/lib.rs | 4 ++-- nova/Cargo.toml | 1 + nova/src/circuit.rs | 1 + nova/src/circuit/nifs.rs | 11 +++++++++++ nova/src/circuit/transcript.rs | 7 +++---- nova/src/function.rs | 2 +- nova/src/gadget.rs | 1 + nova/src/gadget/mimc.rs | 3 +-- nova/src/gadget/relaxed_r1cs.rs | 14 ++++++++++++++ nova/src/ivc.rs | 9 +++++++-- nova/src/proof.rs | 2 +- nova/src/prover.rs | 4 ++-- nova/src/relaxed_r1cs.rs | 8 ++++++-- nova/src/relaxed_r1cs/instance.rs | 2 +- nova/src/relaxed_r1cs/witness.rs | 2 +- nova/src/test.rs | 2 +- nova/src/verifier.rs | 2 +- r1cs/src/gadget/curve.rs | 19 +++++++++++++++++-- r1cs/src/gadget/field.rs | 2 +- r1cs/src/lib.rs | 8 +++++--- r1cs/src/prelude.rs | 3 +++ r1cs/src/test.rs | 26 ++++++++++++++++++++++++++ 23 files changed, 108 insertions(+), 27 deletions(-) create mode 100644 nova/src/circuit/nifs.rs create mode 100644 nova/src/gadget/relaxed_r1cs.rs create mode 100644 r1cs/src/prelude.rs diff --git a/groth16/src/circuit.rs b/groth16/src/circuit.rs index fa724da1..c4631865 100644 --- a/groth16/src/circuit.rs +++ b/groth16/src/circuit.rs @@ -1,6 +1,6 @@ use crate::error::Error; -use r1cs::{GrumpkinDriver, R1cs}; +use r1cs::prelude::{GrumpkinDriver, R1cs}; use zkstd::common::Debug; /// circuit trait diff --git a/groth16/src/lib.rs b/groth16/src/lib.rs index abf1a5dc..e85241dc 100644 --- a/groth16/src/lib.rs +++ b/groth16/src/lib.rs @@ -21,9 +21,9 @@ mod tests { use crate::circuit::Circuit; use crate::error::Error; use crate::zksnark::ZkSnark; + use bn_254::Fr as BnScalar; - use r1cs::gadget::FieldAssignment; - use r1cs::{GrumpkinDriver, R1cs}; + use r1cs::prelude::{FieldAssignment, GrumpkinDriver, R1cs}; use zkstd::common::OsRng; #[test] diff --git a/nova/Cargo.toml b/nova/Cargo.toml index 9a6aeac5..115c3751 100644 --- a/nova/Cargo.toml +++ b/nova/Cargo.toml @@ -14,6 +14,7 @@ keywords = ["zkp", "blockchain", "elliptic-curve"] r1cs = { path = "../r1cs", default-features = false } zkstd = { path = "../zkstd", default-features = false } bn-254 = { path = "../bn254", default-features = false } +grumpkin = { path = "../grumpkin", default-features = false } serde = { version = "1.0.102", default-features = false, features = ["derive"] } blake2b_simd = { version = "1", default-features = false } diff --git a/nova/src/circuit.rs b/nova/src/circuit.rs index e24a4638..8c7e3216 100644 --- a/nova/src/circuit.rs +++ b/nova/src/circuit.rs @@ -1 +1,2 @@ +mod nifs; mod transcript; diff --git a/nova/src/circuit/nifs.rs b/nova/src/circuit/nifs.rs new file mode 100644 index 00000000..ac8dc8e1 --- /dev/null +++ b/nova/src/circuit/nifs.rs @@ -0,0 +1,11 @@ +use core::marker::PhantomData; + +use r1cs::{prelude::CircuitDriver, R1cs}; + +pub(crate) struct NifsCircuit { + p: PhantomData, +} + +impl NifsCircuit { + pub(crate) fn verify(cs: &mut R1cs) {} +} diff --git a/nova/src/circuit/transcript.rs b/nova/src/circuit/transcript.rs index 7809b006..88ce6a6b 100644 --- a/nova/src/circuit/transcript.rs +++ b/nova/src/circuit/transcript.rs @@ -1,7 +1,6 @@ use crate::gadget::MimcAssignment; -use r1cs::gadget::{FieldAssignment, PointAssignment}; -use r1cs::{CircuitDriver, R1cs}; +use r1cs::prelude::{CircuitDriver, FieldAssignment, PointAssignment, R1cs}; use zkstd::common::IntGroup; pub(crate) struct MimcROCircuit { @@ -43,10 +42,10 @@ impl MimcROCircuit { mod tests { use super::MimcROCircuit; use crate::hash::{MimcRO, MIMC_ROUNDS}; + use bn_254::Fr; use grumpkin::Affine; - use r1cs::gadget::{FieldAssignment, PointAssignment}; - use r1cs::{GrumpkinDriver, R1cs}; + use r1cs::prelude::{FieldAssignment, GrumpkinDriver, PointAssignment, R1cs}; use rand_core::OsRng; use zkstd::common::{CurveGroup, Group}; diff --git a/nova/src/function.rs b/nova/src/function.rs index dcec74fe..c076542f 100644 --- a/nova/src/function.rs +++ b/nova/src/function.rs @@ -1,4 +1,4 @@ -use r1cs::{CircuitDriver, DenseVectors}; +use r1cs::{prelude::CircuitDriver, DenseVectors}; pub trait Function { fn invoke(z: &DenseVectors) -> DenseVectors; diff --git a/nova/src/gadget.rs b/nova/src/gadget.rs index ae5fc78c..30275c48 100644 --- a/nova/src/gadget.rs +++ b/nova/src/gadget.rs @@ -1,3 +1,4 @@ mod mimc; +mod relaxed_r1cs; pub(crate) use mimc::MimcAssignment; diff --git a/nova/src/gadget/mimc.rs b/nova/src/gadget/mimc.rs index db8738af..e66867aa 100644 --- a/nova/src/gadget/mimc.rs +++ b/nova/src/gadget/mimc.rs @@ -1,6 +1,5 @@ use crate::hash::Mimc; -use r1cs::gadget::FieldAssignment; -use r1cs::{CircuitDriver, R1cs}; +use r1cs::prelude::{CircuitDriver, FieldAssignment, R1cs}; pub(crate) struct MimcAssignment { constants: [C::Scalar; ROUND], diff --git a/nova/src/gadget/relaxed_r1cs.rs b/nova/src/gadget/relaxed_r1cs.rs new file mode 100644 index 00000000..813efb0a --- /dev/null +++ b/nova/src/gadget/relaxed_r1cs.rs @@ -0,0 +1,14 @@ +use r1cs::prelude::{CircuitDriver, FieldAssignment, PointAssignment, R1cs}; + +use crate::relaxed_r1cs::RelaxedR1csInstance; + +pub(crate) struct RelaxedR1csAssignment { + pub(crate) commit_w: PointAssignment, + pub(crate) commit_e: PointAssignment, + pub(crate) u: FieldAssignment, + pub(crate) x: Vec>, +} + +impl RelaxedR1csAssignment { + pub(crate) fn witness(cs: &mut R1cs, relaxed_r1cs: RelaxedR1csInstance) {} +} diff --git a/nova/src/ivc.rs b/nova/src/ivc.rs index 9baa6161..21feded1 100644 --- a/nova/src/ivc.rs +++ b/nova/src/ivc.rs @@ -2,7 +2,7 @@ use crate::function::Function; use crate::proof::RecursiveProof; use crate::{Prover, RelaxedR1cs}; -use r1cs::{CircuitDriver, DenseVectors, R1cs}; +use r1cs::{prelude::CircuitDriver, DenseVectors, R1cs}; use zkstd::common::RngCore; pub struct Ivc { @@ -71,7 +71,12 @@ impl Ivc { mod tests { use super::Ivc; use crate::test::ExampleFunction; - use r1cs::{test::example_r1cs, DenseVectors, GrumpkinDriver, R1cs}; + + use r1cs::{ + prelude::{GrumpkinDriver, R1cs}, + test::example_r1cs, + DenseVectors, + }; use rand_core::OsRng; #[test] diff --git a/nova/src/proof.rs b/nova/src/proof.rs index 31a35293..3e4c9b11 100644 --- a/nova/src/proof.rs +++ b/nova/src/proof.rs @@ -3,7 +3,7 @@ use crate::{ RelaxedR1cs, }; -use r1cs::{CircuitDriver, DenseVectors, R1cs}; +use r1cs::{prelude::CircuitDriver, DenseVectors, R1cs}; use zkstd::common::{Group, Ring}; #[allow(clippy::type_complexity)] diff --git a/nova/src/prover.rs b/nova/src/prover.rs index 063bf600..5f527e27 100644 --- a/nova/src/prover.rs +++ b/nova/src/prover.rs @@ -4,7 +4,7 @@ use crate::{ }; use crate::hash::{MimcRO, MIMC_ROUNDS}; -use r1cs::{CircuitDriver, DenseVectors, R1cs}; +use r1cs::{prelude::CircuitDriver, DenseVectors, R1cs}; use zkstd::common::{Ring, RngCore}; pub struct Prover { @@ -88,7 +88,7 @@ impl Prover { pub(crate) mod tests { use super::{Prover, RelaxedR1cs}; - use r1cs::{test::example_r1cs, GrumpkinDriver}; + use r1cs::{prelude::GrumpkinDriver, test::example_r1cs}; use zkstd::common::OsRng; pub(crate) fn example_prover() -> Prover { diff --git a/nova/src/relaxed_r1cs.rs b/nova/src/relaxed_r1cs.rs index b1b76aff..308f6755 100644 --- a/nova/src/relaxed_r1cs.rs +++ b/nova/src/relaxed_r1cs.rs @@ -3,7 +3,7 @@ mod witness; use crate::hash::MimcRO; pub(crate) use instance::RelaxedR1csInstance; -use r1cs::{CircuitDriver, DenseVectors, R1cs, SparseMatrix}; +use r1cs::{prelude::CircuitDriver, DenseVectors, R1cs, SparseMatrix}; pub(crate) use witness::RelaxedR1csWitness; #[derive(Clone, Debug)] @@ -144,7 +144,11 @@ impl RelaxedR1cs { #[cfg(test)] mod tests { use super::RelaxedR1cs; - use r1cs::{test::example_r1cs, GrumpkinDriver, R1cs}; + + use r1cs::{ + prelude::{GrumpkinDriver, R1cs}, + test::example_r1cs, + }; #[test] fn relaxed_r1cs_test() { diff --git a/nova/src/relaxed_r1cs/instance.rs b/nova/src/relaxed_r1cs/instance.rs index 94170306..b008d99c 100644 --- a/nova/src/relaxed_r1cs/instance.rs +++ b/nova/src/relaxed_r1cs/instance.rs @@ -1,5 +1,5 @@ use crate::hash::MimcRO; -use r1cs::{CircuitDriver, DenseVectors, R1cs}; +use r1cs::{prelude::CircuitDriver, DenseVectors, R1cs}; use zkstd::common::{Group, PrimeField, Ring}; #[derive(Clone, Debug, PartialEq, Eq)] diff --git a/nova/src/relaxed_r1cs/witness.rs b/nova/src/relaxed_r1cs/witness.rs index 0cf65221..47aaed4c 100644 --- a/nova/src/relaxed_r1cs/witness.rs +++ b/nova/src/relaxed_r1cs/witness.rs @@ -1,4 +1,4 @@ -use r1cs::{CircuitDriver, DenseVectors, R1cs}; +use r1cs::{prelude::CircuitDriver, DenseVectors, R1cs}; use zkstd::common::{IntGroup, PrimeField}; #[derive(Clone, Debug)] diff --git a/nova/src/test.rs b/nova/src/test.rs index 25389e8d..a476b180 100644 --- a/nova/src/test.rs +++ b/nova/src/test.rs @@ -2,7 +2,7 @@ use core::marker::PhantomData; use crate::function::Function; -use r1cs::{CircuitDriver, DenseVectors}; +use r1cs::{prelude::CircuitDriver, DenseVectors}; pub(crate) struct ExampleFunction { mark: PhantomData, diff --git a/nova/src/verifier.rs b/nova/src/verifier.rs index 465d37f6..c13ad46f 100644 --- a/nova/src/verifier.rs +++ b/nova/src/verifier.rs @@ -2,7 +2,7 @@ use crate::relaxed_r1cs::{RelaxedR1cs, RelaxedR1csInstance}; use crate::hash::{MimcRO, MIMC_ROUNDS}; use core::marker::PhantomData; -use r1cs::{CircuitDriver, R1cs}; +use r1cs::prelude::{CircuitDriver, R1cs}; pub struct Verifier { mark: PhantomData, diff --git a/r1cs/src/gadget/curve.rs b/r1cs/src/gadget/curve.rs index c60a3a38..929c755f 100644 --- a/r1cs/src/gadget/curve.rs +++ b/r1cs/src/gadget/curve.rs @@ -28,6 +28,21 @@ impl PointAssignment { Self { x, y, z } } + pub fn witness(cs: &mut R1cs, x: C::Scalar, y: C::Scalar, is_infinity: bool) -> Self { + let x = FieldAssignment::witness(cs, x); + let y = FieldAssignment::witness(cs, y); + let z = FieldAssignment::witness( + cs, + if is_infinity { + C::Scalar::zero() + } else { + C::Scalar::one() + }, + ); + + Self { x, y, z } + } + pub fn assert_equal_public_point( &self, cs: &mut R1cs, @@ -161,8 +176,8 @@ impl PointAssignment { #[cfg(test)] mod tests { use super::{PointAssignment, R1cs}; - use crate::driver::GrumpkinDriver; use crate::gadget::field::FieldAssignment; + use crate::test::GrumpkinDriver; use bn_254::{Fq, Fr}; use grumpkin::{Affine, Projective}; use zkstd::common::{BNAffine, BNProjective, CurveGroup, Group, OsRng, PrimeField}; @@ -181,7 +196,7 @@ mod tests { ) .double(&mut cs); - let expected = point.to_extended().double(); + let expected = point.double(); circuit_double.assert_equal_public_point(&mut cs, expected); diff --git a/r1cs/src/gadget/field.rs b/r1cs/src/gadget/field.rs index e116ec70..338406aa 100644 --- a/r1cs/src/gadget/field.rs +++ b/r1cs/src/gadget/field.rs @@ -191,7 +191,7 @@ impl Neg for &FieldAssignment { #[cfg(test)] mod tests { use super::{FieldAssignment, R1cs}; - use crate::driver::GrumpkinDriver; + use crate::test::GrumpkinDriver; use bn_254::{Fr as Scalar, Fr}; use zkstd::common::{Group, OsRng}; diff --git a/r1cs/src/lib.rs b/r1cs/src/lib.rs index ec28b86e..65340a96 100644 --- a/r1cs/src/lib.rs +++ b/r1cs/src/lib.rs @@ -1,12 +1,13 @@ #![doc = include_str!("../README.md")] mod driver; -pub mod gadget; +mod gadget; mod matrix; +pub mod prelude; pub mod test; mod wire; -pub use driver::{CircuitDriver, GrumpkinDriver}; +use driver::CircuitDriver; pub use matrix::{DenseVectors, SparseMatrix, SparseRow}; pub use wire::Wire; @@ -196,7 +197,8 @@ impl Index for R1cs { #[cfg(test)] mod tests { - use crate::{driver::GrumpkinDriver, test::example_r1cs, R1cs}; + use super::R1cs; + use crate::test::{example_r1cs, GrumpkinDriver}; #[test] fn r1cs_test() { diff --git a/r1cs/src/prelude.rs b/r1cs/src/prelude.rs new file mode 100644 index 00000000..082ce78e --- /dev/null +++ b/r1cs/src/prelude.rs @@ -0,0 +1,3 @@ +pub use super::R1cs; +pub use crate::driver::{CircuitDriver, GrumpkinDriver}; +pub use crate::gadget::{FieldAssignment, PointAssignment}; diff --git a/r1cs/src/test.rs b/r1cs/src/test.rs index ab3c50e7..3211d4d9 100644 --- a/r1cs/src/test.rs +++ b/r1cs/src/test.rs @@ -3,8 +3,34 @@ use crate::matrix::{DenseVectors, SparseMatrix, SparseRow}; use crate::wire::Wire; use crate::R1cs; +use bn_254::{Fq, Fr, G1Affine}; use zkstd::common::{vec, PrimeField, Vec}; +// bn curve b param +pub(crate) const PARAM_B: Fr = Fr::new_unchecked([ + 0xdd7056026000005a, + 0x223fa97acb319311, + 0xcc388229877910c0, + 0x034394632b724eaa, +]); +pub const PARAM_B3: Fr = PARAM_B.add_const(PARAM_B).add_const(PARAM_B); + +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub(crate) struct GrumpkinDriver; + +impl CircuitDriver for GrumpkinDriver { + const NUM_BITS: u16 = 254; + type Affine = G1Affine; + + type Base = Fq; + + type Scalar = Fr; + + fn b3() -> Self::Scalar { + PARAM_B3 + } +} + fn array_to_witnessess(witnesses: Vec) -> Vec { witnesses .iter() From 4df39c235d192a03b34c0e69b559e03d943feb31 Mon Sep 17 00:00:00 2001 From: ashWhiteHat Date: Fri, 24 Nov 2023 14:25:10 +0900 Subject: [PATCH 3/9] feat: zkstd circuit, r1cs and matrix --- zkstd/README.md | 2 +- zkstd/src/circuit.rs | 18 +++ zkstd/src/circuit/gadget.rs | 3 + zkstd/src/circuit/gadget/binary.rs | 26 ++++ zkstd/src/circuit/gadget/curve.rs | 174 +++++++++++++++++++++++++ zkstd/src/circuit/gadget/field.rs | 186 ++++++++++++++++++++++++++ zkstd/src/circuit/prelude.rs | 2 + zkstd/src/lib.rs | 3 + zkstd/src/matrix.rs | 49 +++++++ zkstd/src/matrix/row.rs | 203 +++++++++++++++++++++++++++++ zkstd/src/matrix/vector.rs | 114 ++++++++++++++++ zkstd/src/r1cs.rs | 189 +++++++++++++++++++++++++++ zkstd/src/r1cs/wire.rs | 43 ++++++ 13 files changed, 1011 insertions(+), 1 deletion(-) create mode 100644 zkstd/src/circuit.rs create mode 100644 zkstd/src/circuit/gadget.rs create mode 100644 zkstd/src/circuit/gadget/binary.rs create mode 100644 zkstd/src/circuit/gadget/curve.rs create mode 100644 zkstd/src/circuit/gadget/field.rs create mode 100644 zkstd/src/circuit/prelude.rs create mode 100644 zkstd/src/matrix.rs create mode 100644 zkstd/src/matrix/row.rs create mode 100644 zkstd/src/matrix/vector.rs create mode 100644 zkstd/src/r1cs.rs create mode 100644 zkstd/src/r1cs/wire.rs diff --git a/zkstd/README.md b/zkstd/README.md index 7feed278..7022f9b2 100644 --- a/zkstd/README.md +++ b/zkstd/README.md @@ -1,7 +1,7 @@ # ZkStd [![CI](https://github.com/KogarashiNetwork/zkstd/actions/workflows/ci.yml/badge.svg)](https://github.com/KogarashiNetwork/zkstd/actions/workflows/ci.yml) [![crates.io badge](https://img.shields.io/crates/v/zkstd.svg)](https://crates.io/crates/zkstd) [![Documentation](https://docs.rs/zkstd/badge.svg)](https://docs.rs/zkstd) [![GitHub license](https://img.shields.io/badge/license-GPL3%2FApache2-blue)](#LICENSE) [![codecov](https://codecov.io/gh/KogarashiNetwork/zkstd/branch/master/graph/badge.svg?token=801ESOH5ZV)](https://codecov.io/gh/KogarashiNetwork/zkstd) [![dependency status](https://deps.rs/crate/zkstd/latest/status.svg)](https://deps.rs/crate/zkstd/latest) -This crate provides basic cryptographic implementation as in `Field`, `Curve` and `Pairing`, `Fft`, `Kzg`, and also supports fully `no_std` and [`parity-scale-codec`](https://github.com/paritytech/parity-scale-codec). +This crate provides basic cryptographic implementation as in `Field`, `Curve`, `Pairing` and `Fft`, `Kzg`, `R1cs` and also supports fully `no_std` and [`parity-scale-codec`](https://github.com/paritytech/parity-scale-codec). ## Design diff --git a/zkstd/src/circuit.rs b/zkstd/src/circuit.rs new file mode 100644 index 00000000..c891083d --- /dev/null +++ b/zkstd/src/circuit.rs @@ -0,0 +1,18 @@ +mod gadget; +pub mod prelude; + +use crate::common::{BNAffine, Deserialize, PrimeField, Serialize}; + +pub trait CircuitDriver: Clone { + const NUM_BITS: u16; + // curve affine + type Affine: BNAffine; + + // curve base field + type Base: PrimeField + From + Serialize + for<'de> Deserialize<'de>; + + // curve scalar field + type Scalar: PrimeField + From + Serialize + for<'de> Deserialize<'de>; + // bn curve 3b param + fn b3() -> Self::Scalar; +} diff --git a/zkstd/src/circuit/gadget.rs b/zkstd/src/circuit/gadget.rs new file mode 100644 index 00000000..8bc200b4 --- /dev/null +++ b/zkstd/src/circuit/gadget.rs @@ -0,0 +1,3 @@ +mod binary; +pub mod curve; +pub mod field; diff --git a/zkstd/src/circuit/gadget/binary.rs b/zkstd/src/circuit/gadget/binary.rs new file mode 100644 index 00000000..e035b32c --- /dev/null +++ b/zkstd/src/circuit/gadget/binary.rs @@ -0,0 +1,26 @@ +use crate::circuit::CircuitDriver; +use crate::r1cs::{R1cs, Wire}; +use core::marker::PhantomData; + +#[derive(Clone)] +pub struct BinaryAssignment(Wire, PhantomData); + +impl BinaryAssignment { + pub fn instance(cs: &mut R1cs, bit: u8) -> Self { + let wire = cs.public_wire(); + cs.x.push(C::Scalar::from(bit as u64)); + + Self(wire, PhantomData::default()) + } + + pub fn witness(cs: &mut R1cs, bit: u8) -> Self { + let wire = cs.private_wire(); + cs.w.push(C::Scalar::from(bit as u64)); + + Self(wire, PhantomData::default()) + } + + pub fn inner(&self) -> &Wire { + &self.0 + } +} diff --git a/zkstd/src/circuit/gadget/curve.rs b/zkstd/src/circuit/gadget/curve.rs new file mode 100644 index 00000000..ac3ea55c --- /dev/null +++ b/zkstd/src/circuit/gadget/curve.rs @@ -0,0 +1,174 @@ +use super::binary::BinaryAssignment; +use super::field::FieldAssignment; + +use crate::circuit::CircuitDriver; +use crate::common::{BNProjective, CurveGroup, Group, IntGroup, Ring}; +use crate::r1cs::R1cs; + +#[derive(Clone)] +pub struct PointAssignment { + x: FieldAssignment, + y: FieldAssignment, + z: FieldAssignment, +} + +impl PointAssignment { + pub fn instance(cs: &mut R1cs, x: C::Scalar, y: C::Scalar, is_infinity: bool) -> Self { + let x = FieldAssignment::instance(cs, x); + let y = FieldAssignment::instance(cs, y); + let z = FieldAssignment::instance( + cs, + if is_infinity { + C::Scalar::zero() + } else { + C::Scalar::one() + }, + ); + + Self { x, y, z } + } + + pub fn witness(cs: &mut R1cs, x: C::Scalar, y: C::Scalar, is_infinity: bool) -> Self { + let x = FieldAssignment::witness(cs, x); + let y = FieldAssignment::witness(cs, y); + let z = FieldAssignment::witness( + cs, + if is_infinity { + C::Scalar::zero() + } else { + C::Scalar::one() + }, + ); + + Self { x, y, z } + } + + pub fn assert_equal_public_point( + &self, + cs: &mut R1cs, + point: impl BNProjective, + ) { + let point_x = FieldAssignment::constant(&point.get_x()); + let point_y = FieldAssignment::constant(&point.get_y()); + let point_z = FieldAssignment::constant(&point.get_z()); + + let xz1 = FieldAssignment::mul(cs, &self.x, &point_z); + let xz2 = FieldAssignment::mul(cs, &point_x, &self.z); + + FieldAssignment::eq(cs, &xz1, &xz2); + + let yz1 = FieldAssignment::mul(cs, &self.y, &point_z); + let yz2 = FieldAssignment::mul(cs, &point_y, &self.z); + + FieldAssignment::eq(cs, &yz1, &yz2); + } + + pub fn add(&self, rhs: &Self, cs: &mut R1cs) -> Self { + let b3 = FieldAssignment::::constant(&C::b3()); + let t0 = FieldAssignment::mul(cs, &self.x, &rhs.x); + let t1 = FieldAssignment::mul(cs, &self.y, &rhs.y); + let t2 = FieldAssignment::mul(cs, &self.z, &rhs.z); + let t3 = &self.x + &self.y; + let t4 = &rhs.x + &rhs.y; + let t3 = FieldAssignment::mul(cs, &t3, &t4); + let t4 = &t0 + &t1; + let t3 = &t3 - &t4; + let t4 = &self.y + &self.z; + let x3 = &rhs.y + &rhs.z; + let t4 = FieldAssignment::mul(cs, &t4, &x3); + let x3 = &t1 + &t2; + let t4 = &t4 - &x3; + let x3 = &self.x + &self.z; + let y3 = &rhs.x + &rhs.z; + let x3 = FieldAssignment::mul(cs, &x3, &y3); + let y3 = &t0 + &t2; + let y3 = &x3 - &y3; + let x3 = &t0 + &t0; + let t0 = &x3 + &t0; + let t2 = FieldAssignment::mul(cs, &t2, &b3); + let z3 = &t1 + &t2; + let t1 = &t1 - &t2; + let y3 = FieldAssignment::mul(cs, &y3, &b3); + let x3 = FieldAssignment::mul(cs, &t4, &y3); + let t2 = FieldAssignment::mul(cs, &t3, &t1); + let x3 = &t2 - &x3; + let y3 = FieldAssignment::mul(cs, &y3, &t0); + let t1 = FieldAssignment::mul(cs, &t1, &z3); + let y3 = &t1 + &y3; + let t0 = FieldAssignment::mul(cs, &t0, &t3); + let z3 = FieldAssignment::mul(cs, &z3, &t4); + let z3 = &z3 + &t0; + + Self { + x: x3, + y: y3, + z: z3, + } + } + + pub fn double(&self, cs: &mut R1cs) -> Self { + let b3 = FieldAssignment::::constant(&C::b3()); + let t0 = FieldAssignment::mul(cs, &self.y, &self.y); + let z3 = &t0 + &t0; + let z3 = &z3 + &z3; + let z3 = &z3 + &z3; + let t1 = FieldAssignment::mul(cs, &self.y, &self.z); + let t2 = FieldAssignment::mul(cs, &self.z, &self.z); + let t2 = FieldAssignment::mul(cs, &t2, &b3); + let x3 = FieldAssignment::mul(cs, &t2, &z3); + let y3 = &t0 + &t2; + let z3 = FieldAssignment::mul(cs, &t1, &z3); + let t1 = &t2 + &t2; + let t2 = &t1 + &t2; + let t0 = &t0 - &t2; + let y3 = FieldAssignment::mul(cs, &t0, &y3); + let y3 = &x3 + &y3; + let t1 = FieldAssignment::mul(cs, &self.x, &self.y); + let x3 = FieldAssignment::mul(cs, &t0, &t1); + let x3 = &x3 + &x3; + + Self { + x: x3, + y: y3, + z: z3, + } + } + + /// coordinate scalar + pub fn scalar_point(&self, cs: &mut R1cs, scalar: &FieldAssignment) -> Self { + let i = C::Affine::ADDITIVE_IDENTITY; + let mut res = + PointAssignment::instance(cs, i.get_x().into(), i.get_y().into(), i.is_identity()); + for bit in FieldAssignment::to_bits(cs, scalar).iter() { + res = res.double(cs); + let point_to_add = self.select_identity(cs, bit); + res = res.add(&point_to_add, cs); + } + + res + } + + pub fn select_identity(&self, cs: &mut R1cs, bit: &BinaryAssignment) -> Self { + let PointAssignment { x, y, z } = self.clone(); + let bit = FieldAssignment::from(bit); + Self { + x: FieldAssignment::mul(cs, &x, &bit), + y: &(&FieldAssignment::mul(cs, &y, &bit) + + &FieldAssignment::constant(&C::Scalar::one())) + - &bit, + z: FieldAssignment::mul(cs, &z, &bit), + } + } + + pub fn get_x(&self) -> FieldAssignment { + self.x.clone() + } + + pub fn get_y(&self) -> FieldAssignment { + self.y.clone() + } + + pub fn get_z(&self) -> FieldAssignment { + self.z.clone() + } +} diff --git a/zkstd/src/circuit/gadget/field.rs b/zkstd/src/circuit/gadget/field.rs new file mode 100644 index 00000000..22504819 --- /dev/null +++ b/zkstd/src/circuit/gadget/field.rs @@ -0,0 +1,186 @@ +use super::binary::BinaryAssignment; +use crate::circuit::CircuitDriver; +use crate::common::{vec, Add, IntGroup, Neg, PrimeField, Ring, Sub, Vec}; +use crate::matrix::SparseRow; +use crate::r1cs::{R1cs, Wire}; + +#[derive(Clone)] +pub struct FieldAssignment(SparseRow); + +impl FieldAssignment { + pub fn inner(&self) -> &SparseRow { + &self.0 + } + pub fn instance(cs: &mut R1cs, instance: C::Scalar) -> Self { + let wire = cs.public_wire(); + cs.x.push(instance); + + Self(SparseRow::from(wire)) + } + + pub fn witness(cs: &mut R1cs, witness: C::Scalar) -> Self { + let wire = cs.private_wire(); + cs.w.push(witness); + + Self(SparseRow::from(wire)) + } + + pub fn constant(constant: &C::Scalar) -> Self { + Self(SparseRow(vec![(Wire::ONE, *constant)])) + } + + pub fn square(cs: &mut R1cs, x: &Self) -> Self { + Self::mul(cs, x, x) + } + + pub fn mul(cs: &mut R1cs, x: &Self, y: &Self) -> Self { + if let Some(c) = x.0.as_constant() { + return Self(y.0.clone() * c); + } + if let Some(c) = y.0.as_constant() { + return Self(x.0.clone() * c); + } + + let witness = x.0.evaluate(&cs.x, &cs.w) * y.0.evaluate(&cs.x, &cs.w); + let z = Self::witness(cs, witness); + cs.mul_gate(&x.0, &y.0, &z.0); + + z + } + + pub fn add(cs: &mut R1cs, x: &Self, y: &Self) -> Self { + if let Some(c) = x.0.as_constant() { + return Self(y.0.clone() + SparseRow::from(c)); + } + if let Some(c) = y.0.as_constant() { + return Self(x.0.clone() + SparseRow::from(c)); + } + + let witness = x.0.evaluate(&cs.x, &cs.w) + y.0.evaluate(&cs.x, &cs.w); + let z = Self::witness(cs, witness); + cs.add_gate(&x.0, &y.0, &z.0); + + z + } + + pub fn range_check(cs: &mut R1cs, a_bits: &[BinaryAssignment], c: C::Scalar) { + let c_bits = c + .to_bits() + .into_iter() + .skip_while(|&b| b == 0) + .collect::>(); + + // Check that there are no zeroes before the first one in the C + assert!(a_bits + .iter() + .take(a_bits.len() - c_bits.len()) + .all(|b| cs[*b.inner()] == C::Scalar::zero())); + + let a_bits = a_bits + .iter() + .skip(a_bits.len() - c_bits.len()) + .collect::>(); + + let mut p = vec![FieldAssignment::from(a_bits[0])]; + let t = c_bits + .iter() + .rposition(|&b| b != 1) + .unwrap_or(c_bits.len() - 1); + + for (&a, &c) in a_bits.iter().skip(1).zip(c_bits.iter().skip(1).take(t + 1)) { + if c == 1 { + p.push(FieldAssignment::mul( + cs, + p.last().unwrap(), + &FieldAssignment::from(a), + )); + } else { + p.push(p.last().unwrap().clone()); + } + } + + for (i, (&a, &c)) in a_bits.iter().zip(c_bits.iter()).enumerate() { + let bit_field = FieldAssignment::from(a); + if c == 1 { + let bool_constr = FieldAssignment::mul( + cs, + &(&bit_field - &FieldAssignment::constant(&C::Scalar::one())), + &bit_field, + ); + FieldAssignment::eq( + cs, + &bool_constr, + &FieldAssignment::constant(&C::Scalar::zero()), + ); + } else if c == 0 { + let bool_constr = FieldAssignment::mul( + cs, + &(&(&FieldAssignment::constant(&C::Scalar::one()) - &bit_field) - &p[i - 1]), + &bit_field, + ); + FieldAssignment::eq( + cs, + &bool_constr, + &FieldAssignment::constant(&C::Scalar::zero()), + ); + } + } + } + + /// To bit representation in Big-endian + pub fn to_bits(cs: &mut R1cs, x: &Self) -> Vec> { + let bound = C::Scalar::MODULUS - C::Scalar::one(); + + let bit_repr: Vec> = x + .inner() + .evaluate(&cs.x, &cs.w) + .to_bits() + .iter() + .map(|b| BinaryAssignment::witness(cs, *b)) + .collect(); + FieldAssignment::range_check(cs, &bit_repr, bound); + bit_repr + } + + pub fn eq(cs: &mut R1cs, x: &Self, y: &Self) { + cs.mul_gate(&x.0, &SparseRow::one(), &y.0) + } + + pub fn eq_constant(cs: &mut R1cs, x: &Self, c: &C::Scalar) { + cs.mul_gate( + &x.0, + &SparseRow::one(), + &FieldAssignment::::constant(c).0, + ) + } +} + +impl From<&BinaryAssignment> for FieldAssignment { + fn from(value: &BinaryAssignment) -> Self { + Self(SparseRow::from(value.inner())) + } +} + +impl Add<&FieldAssignment> for &FieldAssignment { + type Output = FieldAssignment; + + fn add(self, rhs: &FieldAssignment) -> Self::Output { + FieldAssignment(&self.0 + &rhs.0) + } +} + +impl Sub<&FieldAssignment> for &FieldAssignment { + type Output = FieldAssignment; + + fn sub(self, rhs: &FieldAssignment) -> Self::Output { + FieldAssignment(&self.0 - &rhs.0) + } +} + +impl Neg for &FieldAssignment { + type Output = FieldAssignment; + + fn neg(self) -> Self::Output { + FieldAssignment(-&self.0) + } +} diff --git a/zkstd/src/circuit/prelude.rs b/zkstd/src/circuit/prelude.rs new file mode 100644 index 00000000..6f2d112f --- /dev/null +++ b/zkstd/src/circuit/prelude.rs @@ -0,0 +1,2 @@ +pub use super::CircuitDriver; +pub use crate::circuit::gadget::{curve::PointAssignment, field::FieldAssignment}; diff --git a/zkstd/src/lib.rs b/zkstd/src/lib.rs index 79b26940..44cf5099 100644 --- a/zkstd/src/lib.rs +++ b/zkstd/src/lib.rs @@ -17,6 +17,9 @@ #![doc = include_str!("../README.md")] pub mod arithmetic; +pub mod circuit; pub mod common; pub mod macros; +pub mod matrix; +pub mod r1cs; mod traits; diff --git a/zkstd/src/matrix.rs b/zkstd/src/matrix.rs new file mode 100644 index 00000000..17cd322b --- /dev/null +++ b/zkstd/src/matrix.rs @@ -0,0 +1,49 @@ +mod row; +mod vector; + +use crate::r1cs::Wire; +pub use row::SparseRow; +pub use vector::DenseVectors; + +use crate::common::{vec, Debug, PrimeField, Vec}; + +#[derive(Clone, Debug, Default)] +pub struct SparseMatrix(pub(crate) Vec>); + +impl SparseMatrix { + #[allow(clippy::type_complexity)] + pub(crate) fn x_and_w( + &self, + l: usize, + m_l_1: usize, + ) -> (Vec>, Vec>) { + let mut x = vec![vec![]; l]; + let mut w = vec![vec![]; m_l_1]; + for (i, a) in self.0.iter().enumerate() { + a.iter().for_each(|(wire, coeff)| match wire { + Wire::Instance(k) => x[*k].push((*coeff, i)), + Wire::Witness(k) => w[*k].push((*coeff, i)), + }); + } + (x, w) + } + + pub(crate) fn evaluate_with_z(&self, x: &DenseVectors, w: &DenseVectors) -> Vec { + self.0.iter().map(|row| row.evaluate(x, w)).collect() + } + + // matrix-vector multiplication + pub fn prod(&self, m: &usize, x: &DenseVectors, w: &DenseVectors) -> DenseVectors { + let mut vectors = DenseVectors::zero(*m); + for (index, elements) in self.0.iter().enumerate() { + vectors[index] = elements.iter().fold(F::zero(), |sum, (wire, coeff)| { + let value = match wire { + Wire::Instance(i) => x[*i], + Wire::Witness(i) => w[*i], + }; + sum + *coeff * value + }) + } + vectors + } +} diff --git a/zkstd/src/matrix/row.rs b/zkstd/src/matrix/row.rs new file mode 100644 index 00000000..4d17d56e --- /dev/null +++ b/zkstd/src/matrix/row.rs @@ -0,0 +1,203 @@ +#![allow(clippy::op_ref)] +use super::vector::DenseVectors; +use crate::common::{Add, Debug, Mul, Neg, PrimeField, Sub, Vec}; +use crate::r1cs::Wire; + +use core::slice::Iter; + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct SparseRow(pub(crate) Vec<(Wire, F)>); + +impl SparseRow { + /// Creates a new expression with the given wire coefficients. + pub fn new(coefficients: Vec<(Wire, F)>) -> Self { + Self( + coefficients + .into_iter() + .filter(|element| element.1 != F::zero()) + .collect(), + ) + } + + pub(crate) fn iter(&self) -> Iter<(Wire, F)> { + self.0.iter() + } + + pub fn one() -> Self { + Self::from(F::one()) + } + + pub fn num_terms(&self) -> usize { + self.0.len() + } + + /// Return Some(c) if this is a constant c, otherwise None. + pub fn as_constant(&self) -> Option { + if self.num_terms() == 1 { + get_value_from_wire(Wire::ONE, &self.0) + } else { + None + } + } + + pub fn evaluate(&self, instance: &DenseVectors, witness: &DenseVectors) -> F { + self.0.iter().fold(F::zero(), |sum, (wire, coefficient)| { + let wire_value = match wire { + Wire::Instance(i) => instance[*i], + Wire::Witness(i) => witness[*i], + }; + sum + (wire_value * *coefficient) + }) + } +} + +impl From for SparseRow { + fn from(wire: Wire) -> Self { + Self::new([(wire, F::one())].to_vec()) + } +} + +impl From<&Wire> for SparseRow { + fn from(wire: &Wire) -> Self { + Self::from(*wire) + } +} + +impl From for SparseRow { + fn from(value: F) -> Self { + Self::new([(Wire::ONE, value)].to_vec()) + } +} + +impl Add> for SparseRow { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + &self + &rhs + } +} + +impl Add<&SparseRow> for SparseRow { + type Output = Self; + + fn add(self, rhs: &Self) -> Self { + &self + rhs + } +} + +impl Add> for &SparseRow { + type Output = SparseRow; + + fn add(self, rhs: SparseRow) -> Self::Output { + self + &rhs + } +} + +impl Add<&SparseRow> for &SparseRow { + type Output = SparseRow; + + fn add(self, rhs: &SparseRow) -> Self::Output { + let mut res = self + .0 + .clone() + .into_iter() + .filter(|(w, _)| get_value_from_wire(*w, &rhs.0).is_none()) + .collect::>(); + for (wire, coeff_b) in rhs.0.clone() { + match get_value_from_wire(wire, &self.0) { + Some(coeff_a) => res.push((wire, coeff_a + coeff_b)), + None => res.push((wire, coeff_b)), + } + } + SparseRow::new(res) + } +} + +impl Sub> for SparseRow { + type Output = SparseRow; + + fn sub(self, rhs: SparseRow) -> Self::Output { + &self - &rhs + } +} + +impl Sub<&SparseRow> for SparseRow { + type Output = SparseRow; + + fn sub(self, rhs: &SparseRow) -> Self::Output { + &self - rhs + } +} + +impl Sub> for &SparseRow { + type Output = SparseRow; + + fn sub(self, rhs: SparseRow) -> Self::Output { + self - &rhs + } +} + +impl Sub<&SparseRow> for &SparseRow { + type Output = SparseRow; + + fn sub(self, rhs: &SparseRow) -> Self::Output { + self + -rhs + } +} + +impl Neg for &SparseRow { + type Output = SparseRow; + + fn neg(self) -> Self::Output { + self * -F::one() + } +} + +impl Neg for SparseRow { + type Output = SparseRow; + + fn neg(self) -> Self::Output { + -&self + } +} + +impl Mul for SparseRow { + type Output = SparseRow; + + fn mul(self, rhs: F) -> Self::Output { + &self * &rhs + } +} + +impl Mul<&F> for SparseRow { + type Output = SparseRow; + + fn mul(self, rhs: &F) -> Self::Output { + &self * rhs + } +} + +impl Mul for &SparseRow { + type Output = SparseRow; + + fn mul(self, rhs: F) -> Self::Output { + self * &rhs + } +} + +impl Mul<&F> for &SparseRow { + type Output = SparseRow; + + fn mul(self, rhs: &F) -> Self::Output { + SparseRow::new(self.0.iter().map(|(k, v)| (*k, *v * *rhs)).collect()) + } +} + +fn get_value_from_wire(index: Wire, vectors: &[(Wire, F)]) -> Option { + for vector in vectors { + if index == vector.0 { + return Some(vector.1); + } + } + None +} diff --git a/zkstd/src/matrix/vector.rs b/zkstd/src/matrix/vector.rs new file mode 100644 index 00000000..9d254421 --- /dev/null +++ b/zkstd/src/matrix/vector.rs @@ -0,0 +1,114 @@ +use crate::common::{vec, Add, Mul, PrimeField, Sub, Vec}; +use core::ops::{Index, IndexMut}; + +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct DenseVectors(Vec); + +impl DenseVectors { + pub fn new(vectors: Vec) -> Self { + Self(vectors) + } + + pub fn get(&self) -> Vec { + self.0.clone() + } + + pub fn push(&mut self, vector: F) { + self.0.push(vector) + } + + pub fn len(&self) -> usize { + self.0.len() + } + + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + pub fn iter(&self) -> DenseVectorsIterator { + DenseVectorsIterator { + dense_vectors: self.clone(), + index: 0, + } + } + + pub fn one(m: usize) -> Self { + Self(vec![F::one(); m]) + } + + pub fn zero(m: usize) -> Self { + Self(vec![F::zero(); m]) + } +} + +pub struct DenseVectorsIterator { + dense_vectors: DenseVectors, + index: usize, +} + +impl Iterator for DenseVectorsIterator { + type Item = F; + + fn next(&mut self) -> Option { + if self.index < self.dense_vectors.0.len() { + let item = Some(self.dense_vectors[self.index]); + self.index += 1; + item + } else { + None + } + } +} + +impl Index for DenseVectors { + type Output = F; + + fn index(&self, index: usize) -> &Self::Output { + &self.0[index] + } +} + +impl IndexMut for DenseVectors { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + &mut self.0[index] + } +} + +impl Mul for DenseVectors { + type Output = Self; + + fn mul(self, rhs: F) -> Self { + Self(self.iter().map(|element| element * rhs).collect()) + } +} + +/// Hadamard product +impl Mul for DenseVectors { + type Output = Self; + + fn mul(self, rhs: Self) -> Self::Output { + assert_eq!(self.0.len(), rhs.0.len()); + + Self(self.iter().zip(rhs.iter()).map(|(a, b)| a * b).collect()) + } +} + +impl Add for DenseVectors { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + assert_eq!(self.0.len(), rhs.0.len()); + + Self(self.iter().zip(rhs.iter()).map(|(a, b)| a + b).collect()) + } +} + +impl Sub for DenseVectors { + type Output = Self; + + fn sub(self, rhs: Self) -> Self::Output { + assert_eq!(self.0.len(), rhs.0.len()); + + Self(self.iter().zip(rhs.iter()).map(|(a, b)| a - b).collect()) + } +} diff --git a/zkstd/src/r1cs.rs b/zkstd/src/r1cs.rs new file mode 100644 index 00000000..712dfcf6 --- /dev/null +++ b/zkstd/src/r1cs.rs @@ -0,0 +1,189 @@ +mod wire; + +use crate::circuit::CircuitDriver; +use crate::common::{vec, Ring, Vec}; +use crate::matrix::{DenseVectors, SparseMatrix, SparseRow}; + +use sp_std::ops::Index; +pub(crate) use wire::Wire; + +#[derive(Clone, Debug)] +pub struct R1cs { + // 1. Structure S + // a, b and c matrices and matrix size + m: usize, + a: SparseMatrix, + b: SparseMatrix, + c: SparseMatrix, + + // 2. Instance + // r1cs instance includes one constant and public inputs and outputs + pub(crate) x: DenseVectors, + + // 3. Witness + // r1cs witness includes private inputs and intermediate value + pub(crate) w: DenseVectors, +} + +impl R1cs { + pub fn m(&self) -> usize { + self.m + } + + pub fn l(&self) -> usize { + self.x.len() + } + + pub fn m_l_1(&self) -> usize { + self.w.len() + } + + pub fn x(&self) -> Vec { + self.x.get() + } + + pub fn w(&self) -> Vec { + self.w.get() + } + + #[allow(clippy::type_complexity)] + pub fn matrices( + &self, + ) -> ( + SparseMatrix, + SparseMatrix, + SparseMatrix, + ) { + (self.a.clone(), self.b.clone(), self.c.clone()) + } + + /// check (A · Z) ◦ (B · Z) = C · Z + pub fn is_sat(&self) -> bool { + let R1cs { m, a, b, c, x, w } = self; + // A · Z + let az = a.prod(m, x, w); + // B · Z + let bz = b.prod(m, x, w); + // C · Z + let cz = c.prod(m, x, w); + // (A · Z) ◦ (B · Z) + let azbz = az * bz; + + azbz.iter() + .zip(cz.iter()) + .all(|(left, right)| left == right) + } + + fn append( + &mut self, + a: SparseRow, + b: SparseRow, + c: SparseRow, + ) { + self.a.0.push(a); + self.b.0.push(b); + self.c.0.push(c); + self.m += 1; + } + + pub(crate) fn public_wire(&mut self) -> Wire { + let index = self.x.len(); + Wire::Instance(index) + } + + pub(crate) fn private_wire(&mut self) -> Wire { + let index = self.w.len(); + Wire::Witness(index) + } + + /// constrain x * y = z + pub fn mul_gate( + &mut self, + x: &SparseRow, + y: &SparseRow, + z: &SparseRow, + ) { + self.append(x.clone(), y.clone(), z.clone()); + } + + /// constrain x + y = z + pub fn add_gate( + &mut self, + x: &SparseRow, + y: &SparseRow, + z: &SparseRow, + ) { + self.append(x + y, SparseRow::from(Wire::ONE), z.clone()); + } + + /// constrain x - y = z + pub fn sub_gate( + &mut self, + x: &SparseRow, + y: &SparseRow, + z: &SparseRow, + ) { + self.append(x - y, SparseRow::from(Wire::ONE), z.clone()); + } + + /// constrain x == y + pub fn equal_gate(&mut self, x: &SparseRow, y: &SparseRow) { + self.mul_gate(x, &SparseRow::one(), y); + } + + #[allow(clippy::type_complexity)] + pub fn evaluate(&self) -> (Vec, Vec, Vec) { + let a_evals = self.a.evaluate_with_z(&self.x, &self.w); + let b_evals = self.b.evaluate_with_z(&self.x, &self.w); + let c_evals = self.c.evaluate_with_z(&self.x, &self.w); + (a_evals, b_evals, c_evals) + } + + #[allow(clippy::type_complexity)] + pub fn z_vectors( + &self, + l: usize, + m_l_1: usize, + ) -> ( + ( + Vec>, + Vec>, + Vec>, + ), + ( + Vec>, + Vec>, + Vec>, + ), + ) { + let (a_x, a_w) = self.a.x_and_w(l, m_l_1); + let (b_x, b_w) = self.b.x_and_w(l, m_l_1); + let (c_x, c_w) = self.c.x_and_w(l, m_l_1); + + ((a_x, b_x, c_x), (a_w, b_w, c_w)) + } +} + +impl Default for R1cs { + fn default() -> Self { + Self { + m: 0, + a: SparseMatrix::default(), + b: SparseMatrix::default(), + c: SparseMatrix::default(), + x: DenseVectors::new(vec![C::Scalar::one()]), + w: DenseVectors::default(), + } + } +} + +impl Index for R1cs { + type Output = C::Scalar; + + fn index(&self, w: Wire) -> &Self::Output { + match w { + Wire::Instance(i) => &self.x[i], + Wire::Witness(i) => &self.w[i], + } + } +} diff --git a/zkstd/src/r1cs/wire.rs b/zkstd/src/r1cs/wire.rs new file mode 100644 index 00000000..3b06ffae --- /dev/null +++ b/zkstd/src/r1cs/wire.rs @@ -0,0 +1,43 @@ +use core::{ + cmp::Ordering, + fmt::{self, Formatter}, +}; + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum Wire { + Instance(usize), + Witness(usize), +} + +impl Wire { + pub const ONE: Wire = Wire::Instance(0); +} + +impl Ord for Wire { + fn cmp(&self, other: &Self) -> Ordering { + let rhs = match self { + Wire::Instance(i) => i, + Wire::Witness(i) => i, + }; + let lhs = match other { + Wire::Instance(i) => i, + Wire::Witness(i) => i, + }; + rhs.cmp(lhs) + } +} + +impl PartialOrd for Wire { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl fmt::Display for Wire { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match self { + Self::Instance(i) => write!(f, "instance {:?}", i), + Self::Witness(i) => write!(f, "witness {:?}", i), + } + } +} From a588f12be6522dabf06c379788dd77134913f008 Mon Sep 17 00:00:00 2001 From: ashWhiteHat Date: Fri, 24 Nov 2023 14:40:51 +0900 Subject: [PATCH 4/9] feat: grumpkin driver --- grumpkin/src/driver.rs | 19 +++++++++++++++++++ grumpkin/src/lib.rs | 3 ++- 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 grumpkin/src/driver.rs diff --git a/grumpkin/src/driver.rs b/grumpkin/src/driver.rs new file mode 100644 index 00000000..5296eb13 --- /dev/null +++ b/grumpkin/src/driver.rs @@ -0,0 +1,19 @@ +use crate::params::PARAM_B3; +use bn_254::{Fq, Fr, G1Affine}; +use zkstd::circuit::CircuitDriver; + +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct GrumpkinDriver; + +impl CircuitDriver for GrumpkinDriver { + const NUM_BITS: u16 = 254; + type Affine = G1Affine; + + type Base = Fq; + + type Scalar = Fr; + + fn b3() -> Self::Scalar { + PARAM_B3 + } +} diff --git a/grumpkin/src/lib.rs b/grumpkin/src/lib.rs index 1afa68e7..594fc6db 100644 --- a/grumpkin/src/lib.rs +++ b/grumpkin/src/lib.rs @@ -18,6 +18,7 @@ #![allow(clippy::suspicious_arithmetic_impl)] mod curve; +pub mod driver; +pub mod params; pub use curve::{Affine, Projective}; -pub mod params; From feaa29bdd2f61426629ead50c0904d1c57cf4320 Mon Sep 17 00:00:00 2001 From: ashWhiteHat Date: Fri, 24 Nov 2023 14:47:40 +0900 Subject: [PATCH 5/9] feat: import zkstd r1cs --- Cargo.lock | 15 +- Cargo.toml | 1 - groth16/Cargo.toml | 2 +- groth16/src/circuit.rs | 3 +- groth16/src/lib.rs | 3 +- groth16/src/prover.rs | 2 +- groth16/src/zksnark.rs | 2 +- nova/Cargo.toml | 1 - nova/src/circuit/nifs.rs | 2 +- nova/src/circuit/transcript.rs | 6 +- nova/src/function.rs | 3 +- nova/src/gadget/mimc.rs | 3 +- nova/src/gadget/relaxed_r1cs.rs | 4 +- nova/src/ivc.rs | 12 +- nova/src/pedersen.rs | 2 +- nova/src/proof.rs | 3 +- nova/src/prover.rs | 6 +- nova/src/relaxed_r1cs.rs | 10 +- nova/src/relaxed_r1cs/instance.rs | 3 +- nova/src/relaxed_r1cs/witness.rs | 3 +- nova/src/test.rs | 6 +- nova/src/verifier.rs | 4 +- r1cs/Cargo.toml | 16 -- r1cs/README.md | 3 - r1cs/src/driver.rs | 43 ---- r1cs/src/gadget.rs | 6 - r1cs/src/gadget/binary.rs | 26 --- r1cs/src/gadget/curve.rs | 295 ------------------------- r1cs/src/gadget/field.rs | 316 --------------------------- r1cs/src/lib.rs | 210 ------------------ r1cs/src/matrix.rs | 49 ----- r1cs/src/matrix/row.rs | 203 ----------------- r1cs/src/matrix/vector.rs | 114 ---------- r1cs/src/prelude.rs | 3 - r1cs/src/wire.rs | 43 ---- zkstd/Cargo.toml | 4 - zkstd/src/circuit/prelude.rs | 1 + zkstd/src/r1cs.rs | 1 + {r1cs/src => zkstd/src/r1cs}/test.rs | 33 +-- 39 files changed, 50 insertions(+), 1412 deletions(-) delete mode 100644 r1cs/Cargo.toml delete mode 100644 r1cs/README.md delete mode 100644 r1cs/src/driver.rs delete mode 100644 r1cs/src/gadget.rs delete mode 100644 r1cs/src/gadget/binary.rs delete mode 100644 r1cs/src/gadget/curve.rs delete mode 100644 r1cs/src/gadget/field.rs delete mode 100644 r1cs/src/lib.rs delete mode 100644 r1cs/src/matrix.rs delete mode 100644 r1cs/src/matrix/row.rs delete mode 100644 r1cs/src/matrix/vector.rs delete mode 100644 r1cs/src/prelude.rs delete mode 100644 r1cs/src/wire.rs rename {r1cs/src => zkstd/src/r1cs}/test.rs (77%) diff --git a/Cargo.lock b/Cargo.lock index 8563fc22..5a5ce1fb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -660,16 +660,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "r1cs" -version = "0.1.0" -dependencies = [ - "bn-254", - "ff", - "grumpkin", - "zkstd", -] - [[package]] name = "radium" version = "0.7.0" @@ -1163,7 +1153,7 @@ name = "zkgroth16" version = "0.0.1" dependencies = [ "bn-254", - "r1cs", + "grumpkin", "rayon", "zkstd", ] @@ -1175,7 +1165,6 @@ dependencies = [ "blake2b_simd", "bn-254", "grumpkin", - "r1cs", "rand_core", "serde", "zkstd", @@ -1185,8 +1174,6 @@ dependencies = [ name = "zkstd" version = "0.0.22" dependencies = [ - "bn-254", - "grumpkin", "parity-scale-codec", "paste", "rand_core", diff --git a/Cargo.toml b/Cargo.toml index 13ed8507..5d86d103 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,6 @@ members = [ "groth16", "grumpkin", "nova", - "r1cs", "zkstd", ] diff --git a/groth16/Cargo.toml b/groth16/Cargo.toml index 506bcd9f..15b68982 100644 --- a/groth16/Cargo.toml +++ b/groth16/Cargo.toml @@ -16,8 +16,8 @@ rustdoc-args = ["--cfg", "docsrs", "--html-in-header", "katex-header.html"] [dependencies] zkstd = { path = "../zkstd", default-features = false } -r1cs = { path = "../r1cs", default-features = false } bn-254 = { path = "../bn254", default-features = false } +grumpkin = { path = "../grumpkin", default-features = false } rayon = { version = "1.5.1", optional = true } [features] diff --git a/groth16/src/circuit.rs b/groth16/src/circuit.rs index c4631865..8ff6fcf3 100644 --- a/groth16/src/circuit.rs +++ b/groth16/src/circuit.rs @@ -1,6 +1,7 @@ use crate::error::Error; -use r1cs::prelude::{GrumpkinDriver, R1cs}; +use grumpkin::driver::GrumpkinDriver; +use zkstd::circuit::prelude::R1cs; use zkstd::common::Debug; /// circuit trait diff --git a/groth16/src/lib.rs b/groth16/src/lib.rs index e85241dc..78a92e65 100644 --- a/groth16/src/lib.rs +++ b/groth16/src/lib.rs @@ -23,7 +23,8 @@ mod tests { use crate::zksnark::ZkSnark; use bn_254::Fr as BnScalar; - use r1cs::prelude::{FieldAssignment, GrumpkinDriver, R1cs}; + use grumpkin::driver::GrumpkinDriver; + use zkstd::circuit::prelude::{FieldAssignment, R1cs}; use zkstd::common::OsRng; #[test] diff --git a/groth16/src/prover.rs b/groth16/src/prover.rs index b5212d76..678ff264 100644 --- a/groth16/src/prover.rs +++ b/groth16/src/prover.rs @@ -7,8 +7,8 @@ use crate::poly::PointsValue; use crate::proof::Proof; use bn_254::Fr; -use r1cs::R1cs; use zkstd::common::{CurveGroup, Group, RngCore}; +use zkstd::r1cs::R1cs; #[derive(Debug)] pub struct Prover { diff --git a/groth16/src/zksnark.rs b/groth16/src/zksnark.rs index 4504e43a..a75f115d 100644 --- a/groth16/src/zksnark.rs +++ b/groth16/src/zksnark.rs @@ -7,8 +7,8 @@ use crate::prover::Prover; use crate::verifier::{Verifier, VerifyingKey}; use bn_254::{Fr, G1Affine, G2Affine}; -use r1cs::R1cs; use zkstd::common::{vec, Group, MulAssign, PrimeField, RngCore, Vec}; +use zkstd::r1cs::R1cs; /// Generate the arguments to prove and verify a circuit pub struct ZkSnark {} diff --git a/nova/Cargo.toml b/nova/Cargo.toml index 115c3751..2dd66e92 100644 --- a/nova/Cargo.toml +++ b/nova/Cargo.toml @@ -11,7 +11,6 @@ categories = ["cryptography"] keywords = ["zkp", "blockchain", "elliptic-curve"] [dependencies] -r1cs = { path = "../r1cs", default-features = false } zkstd = { path = "../zkstd", default-features = false } bn-254 = { path = "../bn254", default-features = false } grumpkin = { path = "../grumpkin", default-features = false } diff --git a/nova/src/circuit/nifs.rs b/nova/src/circuit/nifs.rs index ac8dc8e1..518da0f9 100644 --- a/nova/src/circuit/nifs.rs +++ b/nova/src/circuit/nifs.rs @@ -1,6 +1,6 @@ use core::marker::PhantomData; -use r1cs::{prelude::CircuitDriver, R1cs}; +use zkstd::circuit::prelude::{CircuitDriver, R1cs}; pub(crate) struct NifsCircuit { p: PhantomData, diff --git a/nova/src/circuit/transcript.rs b/nova/src/circuit/transcript.rs index 88ce6a6b..5c55cc70 100644 --- a/nova/src/circuit/transcript.rs +++ b/nova/src/circuit/transcript.rs @@ -1,6 +1,6 @@ use crate::gadget::MimcAssignment; -use r1cs::prelude::{CircuitDriver, FieldAssignment, PointAssignment, R1cs}; +use zkstd::circuit::prelude::{CircuitDriver, FieldAssignment, PointAssignment, R1cs}; use zkstd::common::IntGroup; pub(crate) struct MimcROCircuit { @@ -44,9 +44,9 @@ mod tests { use crate::hash::{MimcRO, MIMC_ROUNDS}; use bn_254::Fr; - use grumpkin::Affine; - use r1cs::prelude::{FieldAssignment, GrumpkinDriver, PointAssignment, R1cs}; + use grumpkin::{driver::GrumpkinDriver, Affine}; use rand_core::OsRng; + use zkstd::circuit::prelude::{FieldAssignment, PointAssignment, R1cs}; use zkstd::common::{CurveGroup, Group}; #[test] diff --git a/nova/src/function.rs b/nova/src/function.rs index c076542f..168c1bcb 100644 --- a/nova/src/function.rs +++ b/nova/src/function.rs @@ -1,4 +1,5 @@ -use r1cs::{prelude::CircuitDriver, DenseVectors}; +use zkstd::circuit::prelude::CircuitDriver; +use zkstd::matrix::DenseVectors; pub trait Function { fn invoke(z: &DenseVectors) -> DenseVectors; diff --git a/nova/src/gadget/mimc.rs b/nova/src/gadget/mimc.rs index e66867aa..9f9aef0e 100644 --- a/nova/src/gadget/mimc.rs +++ b/nova/src/gadget/mimc.rs @@ -1,5 +1,6 @@ use crate::hash::Mimc; -use r1cs::prelude::{CircuitDriver, FieldAssignment, R1cs}; + +use zkstd::circuit::prelude::{CircuitDriver, FieldAssignment, R1cs}; pub(crate) struct MimcAssignment { constants: [C::Scalar; ROUND], diff --git a/nova/src/gadget/relaxed_r1cs.rs b/nova/src/gadget/relaxed_r1cs.rs index 813efb0a..d08c36e2 100644 --- a/nova/src/gadget/relaxed_r1cs.rs +++ b/nova/src/gadget/relaxed_r1cs.rs @@ -1,7 +1,7 @@ -use r1cs::prelude::{CircuitDriver, FieldAssignment, PointAssignment, R1cs}; - use crate::relaxed_r1cs::RelaxedR1csInstance; +use zkstd::circuit::prelude::{CircuitDriver, FieldAssignment, PointAssignment, R1cs}; + pub(crate) struct RelaxedR1csAssignment { pub(crate) commit_w: PointAssignment, pub(crate) commit_e: PointAssignment, diff --git a/nova/src/ivc.rs b/nova/src/ivc.rs index 21feded1..4ffb863b 100644 --- a/nova/src/ivc.rs +++ b/nova/src/ivc.rs @@ -2,8 +2,9 @@ use crate::function::Function; use crate::proof::RecursiveProof; use crate::{Prover, RelaxedR1cs}; -use r1cs::{prelude::CircuitDriver, DenseVectors, R1cs}; +use zkstd::circuit::prelude::{CircuitDriver, R1cs}; use zkstd::common::RngCore; +use zkstd::matrix::DenseVectors; pub struct Ivc { i: usize, @@ -72,12 +73,11 @@ mod tests { use super::Ivc; use crate::test::ExampleFunction; - use r1cs::{ - prelude::{GrumpkinDriver, R1cs}, - test::example_r1cs, - DenseVectors, - }; + use grumpkin::driver::GrumpkinDriver; use rand_core::OsRng; + use zkstd::circuit::prelude::R1cs; + use zkstd::matrix::DenseVectors; + use zkstd::r1cs::test::example_r1cs; #[test] fn ivc_test() { diff --git a/nova/src/pedersen.rs b/nova/src/pedersen.rs index e24f93f1..404b3064 100644 --- a/nova/src/pedersen.rs +++ b/nova/src/pedersen.rs @@ -1,5 +1,5 @@ -use r1cs::DenseVectors; use zkstd::common::{BNAffine, Group, RngCore}; +use zkstd::matrix::DenseVectors; pub struct PedersenCommitment { g: Vec, diff --git a/nova/src/proof.rs b/nova/src/proof.rs index 3e4c9b11..99b7b79f 100644 --- a/nova/src/proof.rs +++ b/nova/src/proof.rs @@ -3,8 +3,9 @@ use crate::{ RelaxedR1cs, }; -use r1cs::{prelude::CircuitDriver, DenseVectors, R1cs}; +use zkstd::circuit::prelude::{CircuitDriver, R1cs}; use zkstd::common::{Group, Ring}; +use zkstd::matrix::DenseVectors; #[allow(clippy::type_complexity)] pub struct RecursiveProof { diff --git a/nova/src/prover.rs b/nova/src/prover.rs index 5f527e27..bc225d3b 100644 --- a/nova/src/prover.rs +++ b/nova/src/prover.rs @@ -4,8 +4,9 @@ use crate::{ }; use crate::hash::{MimcRO, MIMC_ROUNDS}; -use r1cs::{prelude::CircuitDriver, DenseVectors, R1cs}; +use zkstd::circuit::prelude::{CircuitDriver, R1cs}; use zkstd::common::{Ring, RngCore}; +use zkstd::matrix::DenseVectors; pub struct Prover { // public parameters @@ -88,8 +89,9 @@ impl Prover { pub(crate) mod tests { use super::{Prover, RelaxedR1cs}; - use r1cs::{prelude::GrumpkinDriver, test::example_r1cs}; + use grumpkin::driver::GrumpkinDriver; use zkstd::common::OsRng; + use zkstd::r1cs::test::example_r1cs; pub(crate) fn example_prover() -> Prover { let r1cs = example_r1cs(0); diff --git a/nova/src/relaxed_r1cs.rs b/nova/src/relaxed_r1cs.rs index 308f6755..51a1f0d5 100644 --- a/nova/src/relaxed_r1cs.rs +++ b/nova/src/relaxed_r1cs.rs @@ -3,8 +3,9 @@ mod witness; use crate::hash::MimcRO; pub(crate) use instance::RelaxedR1csInstance; -use r1cs::{prelude::CircuitDriver, DenseVectors, R1cs, SparseMatrix}; pub(crate) use witness::RelaxedR1csWitness; +use zkstd::circuit::prelude::{CircuitDriver, R1cs}; +use zkstd::matrix::{DenseVectors, SparseMatrix}; #[derive(Clone, Debug)] pub struct RelaxedR1cs { @@ -145,10 +146,9 @@ impl RelaxedR1cs { mod tests { use super::RelaxedR1cs; - use r1cs::{ - prelude::{GrumpkinDriver, R1cs}, - test::example_r1cs, - }; + use grumpkin::driver::GrumpkinDriver; + use zkstd::circuit::prelude::R1cs; + use zkstd::r1cs::test::example_r1cs; #[test] fn relaxed_r1cs_test() { diff --git a/nova/src/relaxed_r1cs/instance.rs b/nova/src/relaxed_r1cs/instance.rs index b008d99c..aa36dca9 100644 --- a/nova/src/relaxed_r1cs/instance.rs +++ b/nova/src/relaxed_r1cs/instance.rs @@ -1,6 +1,7 @@ use crate::hash::MimcRO; -use r1cs::{prelude::CircuitDriver, DenseVectors, R1cs}; +use zkstd::circuit::prelude::{CircuitDriver, R1cs}; use zkstd::common::{Group, PrimeField, Ring}; +use zkstd::matrix::DenseVectors; #[derive(Clone, Debug, PartialEq, Eq)] pub struct RelaxedR1csInstance { diff --git a/nova/src/relaxed_r1cs/witness.rs b/nova/src/relaxed_r1cs/witness.rs index 47aaed4c..8b746eb0 100644 --- a/nova/src/relaxed_r1cs/witness.rs +++ b/nova/src/relaxed_r1cs/witness.rs @@ -1,5 +1,6 @@ -use r1cs::{prelude::CircuitDriver, DenseVectors, R1cs}; +use zkstd::circuit::prelude::{CircuitDriver, R1cs}; use zkstd::common::{IntGroup, PrimeField}; +use zkstd::matrix::DenseVectors; #[derive(Clone, Debug)] pub struct RelaxedR1csWitness { diff --git a/nova/src/test.rs b/nova/src/test.rs index a476b180..f09a70fd 100644 --- a/nova/src/test.rs +++ b/nova/src/test.rs @@ -1,8 +1,8 @@ -use core::marker::PhantomData; - use crate::function::Function; -use r1cs::{prelude::CircuitDriver, DenseVectors}; +use core::marker::PhantomData; +use zkstd::circuit::prelude::CircuitDriver; +use zkstd::matrix::DenseVectors; pub(crate) struct ExampleFunction { mark: PhantomData, diff --git a/nova/src/verifier.rs b/nova/src/verifier.rs index c13ad46f..1adc1036 100644 --- a/nova/src/verifier.rs +++ b/nova/src/verifier.rs @@ -2,7 +2,7 @@ use crate::relaxed_r1cs::{RelaxedR1cs, RelaxedR1csInstance}; use crate::hash::{MimcRO, MIMC_ROUNDS}; use core::marker::PhantomData; -use r1cs::prelude::{CircuitDriver, R1cs}; +use zkstd::circuit::prelude::{CircuitDriver, R1cs}; pub struct Verifier { mark: PhantomData, @@ -30,7 +30,7 @@ mod tests { use super::{RelaxedR1cs, Verifier}; use crate::prover::tests::example_prover; - use r1cs::test::example_r1cs; + use zkstd::r1cs::test::example_r1cs; #[test] fn folding_scheme_verifier_test() { diff --git a/r1cs/Cargo.toml b/r1cs/Cargo.toml deleted file mode 100644 index c51ef8b1..00000000 --- a/r1cs/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "r1cs" -version = "0.1.0" -edition = "2021" - -[dependencies] -zkstd = { path = "../zkstd", default-features = false } -bn-254 = { path = "../bn254", default-features = false } -grumpkin = { path = "../grumpkin", default-features = false } -ff = { version = "0.13.0", features = ["derive"] } - -[features] -default = ["std"] -std = [ - "zkstd/std" -] diff --git a/r1cs/README.md b/r1cs/README.md deleted file mode 100644 index c11ace9f..00000000 --- a/r1cs/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# R1cs - -$\sum^{q}{i=1}c_1·\circ{j\in{S_i}}Mj·z=0$ diff --git a/r1cs/src/driver.rs b/r1cs/src/driver.rs deleted file mode 100644 index ccde400f..00000000 --- a/r1cs/src/driver.rs +++ /dev/null @@ -1,43 +0,0 @@ -use bn_254::{Fq, Fr, G1Affine}; -use grumpkin::params::PARAM_B3; -use zkstd::common::{BNAffine, Deserialize, PrimeField, Serialize}; - -pub trait CircuitDriver: Clone { - const NUM_BITS: u16; - // curve affine - type Affine: BNAffine; - - // curve base field - type Base: PrimeField - + From - + ff::PrimeField - + ff::PrimeFieldBits - + Serialize - + for<'de> Deserialize<'de>; - - // curve scalar field - type Scalar: PrimeField - + From - + ff::PrimeField - + ff::PrimeFieldBits - + Serialize - + for<'de> Deserialize<'de>; - // bn curve 3b param - fn b3() -> Self::Scalar; -} - -#[derive(Clone, Debug, Default, PartialEq, Eq)] -pub struct GrumpkinDriver; - -impl CircuitDriver for GrumpkinDriver { - const NUM_BITS: u16 = 254; - type Affine = G1Affine; - - type Base = Fq; - - type Scalar = Fr; - - fn b3() -> Self::Scalar { - PARAM_B3 - } -} diff --git a/r1cs/src/gadget.rs b/r1cs/src/gadget.rs deleted file mode 100644 index 570fd1a5..00000000 --- a/r1cs/src/gadget.rs +++ /dev/null @@ -1,6 +0,0 @@ -mod binary; -mod curve; -mod field; - -pub use curve::*; -pub use field::*; diff --git a/r1cs/src/gadget/binary.rs b/r1cs/src/gadget/binary.rs deleted file mode 100644 index 77330186..00000000 --- a/r1cs/src/gadget/binary.rs +++ /dev/null @@ -1,26 +0,0 @@ -use crate::driver::CircuitDriver; -use crate::{R1cs, Wire}; -use std::marker::PhantomData; - -#[derive(Clone)] -pub struct BinaryAssignment(Wire, PhantomData); - -impl BinaryAssignment { - pub fn instance(cs: &mut R1cs, bit: u8) -> Self { - let wire = cs.public_wire(); - cs.x.push(C::Scalar::from(bit as u64)); - - Self(wire, PhantomData::default()) - } - - pub fn witness(cs: &mut R1cs, bit: u8) -> Self { - let wire = cs.private_wire(); - cs.w.push(C::Scalar::from(bit as u64)); - - Self(wire, PhantomData::default()) - } - - pub fn inner(&self) -> &Wire { - &self.0 - } -} diff --git a/r1cs/src/gadget/curve.rs b/r1cs/src/gadget/curve.rs deleted file mode 100644 index 929c755f..00000000 --- a/r1cs/src/gadget/curve.rs +++ /dev/null @@ -1,295 +0,0 @@ -use super::field::FieldAssignment; -use crate::driver::CircuitDriver; -use crate::R1cs; - -use crate::gadget::binary::BinaryAssignment; -use zkstd::common::{BNProjective, CurveGroup, Group, IntGroup, Ring}; - -#[derive(Clone)] -pub struct PointAssignment { - x: FieldAssignment, - y: FieldAssignment, - z: FieldAssignment, -} - -impl PointAssignment { - pub fn instance(cs: &mut R1cs, x: C::Scalar, y: C::Scalar, is_infinity: bool) -> Self { - let x = FieldAssignment::instance(cs, x); - let y = FieldAssignment::instance(cs, y); - let z = FieldAssignment::instance( - cs, - if is_infinity { - C::Scalar::zero() - } else { - C::Scalar::one() - }, - ); - - Self { x, y, z } - } - - pub fn witness(cs: &mut R1cs, x: C::Scalar, y: C::Scalar, is_infinity: bool) -> Self { - let x = FieldAssignment::witness(cs, x); - let y = FieldAssignment::witness(cs, y); - let z = FieldAssignment::witness( - cs, - if is_infinity { - C::Scalar::zero() - } else { - C::Scalar::one() - }, - ); - - Self { x, y, z } - } - - pub fn assert_equal_public_point( - &self, - cs: &mut R1cs, - point: impl BNProjective, - ) { - let point_x = FieldAssignment::constant(&point.get_x()); - let point_y = FieldAssignment::constant(&point.get_y()); - let point_z = FieldAssignment::constant(&point.get_z()); - - let xz1 = FieldAssignment::mul(cs, &self.x, &point_z); - let xz2 = FieldAssignment::mul(cs, &point_x, &self.z); - - FieldAssignment::eq(cs, &xz1, &xz2); - - let yz1 = FieldAssignment::mul(cs, &self.y, &point_z); - let yz2 = FieldAssignment::mul(cs, &point_y, &self.z); - - FieldAssignment::eq(cs, &yz1, &yz2); - } - - pub fn add(&self, rhs: &Self, cs: &mut R1cs) -> Self { - let b3 = FieldAssignment::::constant(&C::b3()); - let t0 = FieldAssignment::mul(cs, &self.x, &rhs.x); - let t1 = FieldAssignment::mul(cs, &self.y, &rhs.y); - let t2 = FieldAssignment::mul(cs, &self.z, &rhs.z); - let t3 = &self.x + &self.y; - let t4 = &rhs.x + &rhs.y; - let t3 = FieldAssignment::mul(cs, &t3, &t4); - let t4 = &t0 + &t1; - let t3 = &t3 - &t4; - let t4 = &self.y + &self.z; - let x3 = &rhs.y + &rhs.z; - let t4 = FieldAssignment::mul(cs, &t4, &x3); - let x3 = &t1 + &t2; - let t4 = &t4 - &x3; - let x3 = &self.x + &self.z; - let y3 = &rhs.x + &rhs.z; - let x3 = FieldAssignment::mul(cs, &x3, &y3); - let y3 = &t0 + &t2; - let y3 = &x3 - &y3; - let x3 = &t0 + &t0; - let t0 = &x3 + &t0; - let t2 = FieldAssignment::mul(cs, &t2, &b3); - let z3 = &t1 + &t2; - let t1 = &t1 - &t2; - let y3 = FieldAssignment::mul(cs, &y3, &b3); - let x3 = FieldAssignment::mul(cs, &t4, &y3); - let t2 = FieldAssignment::mul(cs, &t3, &t1); - let x3 = &t2 - &x3; - let y3 = FieldAssignment::mul(cs, &y3, &t0); - let t1 = FieldAssignment::mul(cs, &t1, &z3); - let y3 = &t1 + &y3; - let t0 = FieldAssignment::mul(cs, &t0, &t3); - let z3 = FieldAssignment::mul(cs, &z3, &t4); - let z3 = &z3 + &t0; - - Self { - x: x3, - y: y3, - z: z3, - } - } - - pub fn double(&self, cs: &mut R1cs) -> Self { - let b3 = FieldAssignment::::constant(&C::b3()); - let t0 = FieldAssignment::mul(cs, &self.y, &self.y); - let z3 = &t0 + &t0; - let z3 = &z3 + &z3; - let z3 = &z3 + &z3; - let t1 = FieldAssignment::mul(cs, &self.y, &self.z); - let t2 = FieldAssignment::mul(cs, &self.z, &self.z); - let t2 = FieldAssignment::mul(cs, &t2, &b3); - let x3 = FieldAssignment::mul(cs, &t2, &z3); - let y3 = &t0 + &t2; - let z3 = FieldAssignment::mul(cs, &t1, &z3); - let t1 = &t2 + &t2; - let t2 = &t1 + &t2; - let t0 = &t0 - &t2; - let y3 = FieldAssignment::mul(cs, &t0, &y3); - let y3 = &x3 + &y3; - let t1 = FieldAssignment::mul(cs, &self.x, &self.y); - let x3 = FieldAssignment::mul(cs, &t0, &t1); - let x3 = &x3 + &x3; - - Self { - x: x3, - y: y3, - z: z3, - } - } - - /// coordinate scalar - pub fn scalar_point(&self, cs: &mut R1cs, scalar: &FieldAssignment) -> Self { - let i = C::Affine::ADDITIVE_IDENTITY; - let mut res = - PointAssignment::instance(cs, i.get_x().into(), i.get_y().into(), i.is_identity()); - for bit in FieldAssignment::to_bits(cs, scalar).iter() { - res = res.double(cs); - let point_to_add = self.select_identity(cs, bit); - res = res.add(&point_to_add, cs); - } - - res - } - - pub fn select_identity(&self, cs: &mut R1cs, bit: &BinaryAssignment) -> Self { - let PointAssignment { x, y, z } = self.clone(); - let bit = FieldAssignment::from(bit); - Self { - x: FieldAssignment::mul(cs, &x, &bit), - y: &(&FieldAssignment::mul(cs, &y, &bit) - + &FieldAssignment::constant(&C::Scalar::one())) - - &bit, - z: FieldAssignment::mul(cs, &z, &bit), - } - } - - pub fn get_x(&self) -> FieldAssignment { - self.x.clone() - } - - pub fn get_y(&self) -> FieldAssignment { - self.y.clone() - } - - pub fn get_z(&self) -> FieldAssignment { - self.z.clone() - } -} - -#[cfg(test)] -mod tests { - use super::{PointAssignment, R1cs}; - use crate::gadget::field::FieldAssignment; - use crate::test::GrumpkinDriver; - use bn_254::{Fq, Fr}; - use grumpkin::{Affine, Projective}; - use zkstd::common::{BNAffine, BNProjective, CurveGroup, Group, OsRng, PrimeField}; - - #[test] - fn curve_double_test() { - for _ in 0..100 { - let mut cs: R1cs = R1cs::default(); - let point = Affine::random(OsRng); - - let circuit_double = PointAssignment::instance( - &mut cs, - point.get_x(), - point.get_y(), - point.is_identity(), - ) - .double(&mut cs); - - let expected = point.double(); - - circuit_double.assert_equal_public_point(&mut cs, expected); - - assert!(cs.is_sat()); - } - } - - #[test] - fn curve_add_test() { - // Identity addition test - { - let mut cs: R1cs = R1cs::default(); - let a = Affine::random(OsRng); - let b = Affine::ADDITIVE_IDENTITY; - - let a_assignment = - PointAssignment::instance(&mut cs, a.get_x(), a.get_y(), a.is_identity()); - let b_assignment = - PointAssignment::instance(&mut cs, b.get_x(), b.get_y(), b.is_identity()); - - let expected = a.to_extended() + b.to_extended(); - - let sum_circuit = a_assignment.add(&b_assignment, &mut cs); - - assert_eq!( - expected, - Projective::new_unchecked( - sum_circuit.x.inner().evaluate(&cs.x, &cs.w), - sum_circuit.y.inner().evaluate(&cs.x, &cs.w), - sum_circuit.z.inner().evaluate(&cs.x, &cs.w) - ) - ); - - sum_circuit.assert_equal_public_point(&mut cs, expected); - - assert!(cs.is_sat()); - } - - for _ in 0..100 { - let mut cs: R1cs = R1cs::default(); - let a = Affine::random(OsRng); - let b = Affine::random(OsRng); - - let a_assignment = - PointAssignment::instance(&mut cs, a.get_x(), a.get_y(), a.is_identity()); - let b_assignment = - PointAssignment::instance(&mut cs, b.get_x(), b.get_y(), b.is_identity()); - - let expected = a.to_extended() + b.to_extended(); - - let sum_circuit = a_assignment.add(&b_assignment, &mut cs); - - assert_eq!( - expected, - Projective::new_unchecked( - sum_circuit.x.inner().evaluate(&cs.x, &cs.w), - sum_circuit.y.inner().evaluate(&cs.x, &cs.w), - sum_circuit.z.inner().evaluate(&cs.x, &cs.w) - ) - ); - - sum_circuit.assert_equal_public_point(&mut cs, expected); - - assert!(cs.is_sat()); - } - } - - #[test] - fn curve_scalar_mul_test() { - for _ in 0..100 { - let mut cs: R1cs = R1cs::default(); - let x = Fr::random(OsRng); - let p = Affine::random(OsRng); - - let x_assignment = FieldAssignment::instance(&mut cs, x); // Fr - let p_assignment = - PointAssignment::instance(&mut cs, p.get_x(), p.get_y(), p.is_identity()); - let expected = p * Fq::from(x); - - assert_eq!(x.to_bits(), Fq::from(x).to_bits()); - - let mul_circuit = p_assignment.scalar_point(&mut cs, &x_assignment); - assert_eq!( - expected, - Projective::new_unchecked( - mul_circuit.x.inner().evaluate(&cs.x, &cs.w), - mul_circuit.y.inner().evaluate(&cs.x, &cs.w), - mul_circuit.z.inner().evaluate(&cs.x, &cs.w) - ) - ); - mul_circuit.assert_equal_public_point(&mut cs, expected); - - assert!(cs.is_sat()); - } - } -} diff --git a/r1cs/src/gadget/field.rs b/r1cs/src/gadget/field.rs deleted file mode 100644 index 338406aa..00000000 --- a/r1cs/src/gadget/field.rs +++ /dev/null @@ -1,316 +0,0 @@ -use crate::driver::CircuitDriver; -use crate::matrix::SparseRow; -use crate::wire::Wire; -use crate::R1cs; -use std::ops::{Neg, Sub}; - -use crate::gadget::binary::BinaryAssignment; -use zkstd::common::{Add, IntGroup, PrimeField, Ring}; - -#[derive(Clone)] -pub struct FieldAssignment(SparseRow); - -impl FieldAssignment { - pub fn inner(&self) -> &SparseRow { - &self.0 - } - pub fn instance(cs: &mut R1cs, instance: C::Scalar) -> Self { - let wire = cs.public_wire(); - cs.x.push(instance); - - Self(SparseRow::from(wire)) - } - - pub fn witness(cs: &mut R1cs, witness: C::Scalar) -> Self { - let wire = cs.private_wire(); - cs.w.push(witness); - - Self(SparseRow::from(wire)) - } - - pub fn constant(constant: &C::Scalar) -> Self { - Self(SparseRow(vec![(Wire::ONE, *constant)])) - } - - pub fn square(cs: &mut R1cs, x: &Self) -> Self { - Self::mul(cs, x, x) - } - - pub fn mul(cs: &mut R1cs, x: &Self, y: &Self) -> Self { - if let Some(c) = x.0.as_constant() { - return Self(y.0.clone() * c); - } - if let Some(c) = y.0.as_constant() { - return Self(x.0.clone() * c); - } - - let witness = x.0.evaluate(&cs.x, &cs.w) * y.0.evaluate(&cs.x, &cs.w); - let z = Self::witness(cs, witness); - cs.mul_gate(&x.0, &y.0, &z.0); - - z - } - - pub fn add(cs: &mut R1cs, x: &Self, y: &Self) -> Self { - if let Some(c) = x.0.as_constant() { - return Self(y.0.clone() + SparseRow::from(c)); - } - if let Some(c) = y.0.as_constant() { - return Self(x.0.clone() + SparseRow::from(c)); - } - - let witness = x.0.evaluate(&cs.x, &cs.w) + y.0.evaluate(&cs.x, &cs.w); - let z = Self::witness(cs, witness); - cs.add_gate(&x.0, &y.0, &z.0); - - z - } - - pub fn range_check(cs: &mut R1cs, a_bits: &[BinaryAssignment], c: C::Scalar) { - let c_bits = c - .to_bits() - .into_iter() - .skip_while(|&b| b == 0) - .collect::>(); - - // Check that there are no zeroes before the first one in the C - assert!(a_bits - .iter() - .take(a_bits.len() - c_bits.len()) - .all(|b| cs[*b.inner()] == C::Scalar::zero())); - - let a_bits = a_bits - .iter() - .skip(a_bits.len() - c_bits.len()) - .collect::>(); - - let mut p = vec![FieldAssignment::from(a_bits[0])]; - let t = c_bits - .iter() - .rposition(|&b| b != 1) - .unwrap_or(c_bits.len() - 1); - - for (&a, &c) in a_bits.iter().skip(1).zip(c_bits.iter().skip(1).take(t + 1)) { - if c == 1 { - p.push(FieldAssignment::mul( - cs, - p.last().unwrap(), - &FieldAssignment::from(a), - )); - } else { - p.push(p.last().unwrap().clone()); - } - } - - for (i, (&a, &c)) in a_bits.iter().zip(c_bits.iter()).enumerate() { - let bit_field = FieldAssignment::from(a); - if c == 1 { - let bool_constr = FieldAssignment::mul( - cs, - &(&bit_field - &FieldAssignment::constant(&C::Scalar::one())), - &bit_field, - ); - FieldAssignment::eq( - cs, - &bool_constr, - &FieldAssignment::constant(&C::Scalar::zero()), - ); - } else if c == 0 { - let bool_constr = FieldAssignment::mul( - cs, - &(&(&FieldAssignment::constant(&C::Scalar::one()) - &bit_field) - &p[i - 1]), - &bit_field, - ); - FieldAssignment::eq( - cs, - &bool_constr, - &FieldAssignment::constant(&C::Scalar::zero()), - ); - } - } - } - - /// To bit representation in Big-endian - pub fn to_bits(cs: &mut R1cs, x: &Self) -> Vec> { - let bound = C::Scalar::MODULUS - C::Scalar::one(); - - let bit_repr: Vec> = x - .inner() - .evaluate(&cs.x, &cs.w) - .to_bits() - .iter() - .map(|b| BinaryAssignment::witness(cs, *b)) - .collect(); - FieldAssignment::range_check(cs, &bit_repr, bound); - bit_repr - } - - pub fn eq(cs: &mut R1cs, x: &Self, y: &Self) { - cs.mul_gate(&x.0, &SparseRow::one(), &y.0) - } - - pub fn eq_constant(cs: &mut R1cs, x: &Self, c: &C::Scalar) { - cs.mul_gate( - &x.0, - &SparseRow::one(), - &FieldAssignment::::constant(c).0, - ) - } -} - -impl From<&BinaryAssignment> for FieldAssignment { - fn from(value: &BinaryAssignment) -> Self { - Self(SparseRow::from(value.inner())) - } -} - -impl Add<&FieldAssignment> for &FieldAssignment { - type Output = FieldAssignment; - - fn add(self, rhs: &FieldAssignment) -> Self::Output { - FieldAssignment(&self.0 + &rhs.0) - } -} - -impl Sub<&FieldAssignment> for &FieldAssignment { - type Output = FieldAssignment; - - fn sub(self, rhs: &FieldAssignment) -> Self::Output { - FieldAssignment(&self.0 - &rhs.0) - } -} - -impl Neg for &FieldAssignment { - type Output = FieldAssignment; - - fn neg(self) -> Self::Output { - FieldAssignment(-&self.0) - } -} - -#[cfg(test)] -mod tests { - use super::{FieldAssignment, R1cs}; - use crate::test::GrumpkinDriver; - use bn_254::{Fr as Scalar, Fr}; - use zkstd::common::{Group, OsRng}; - - #[test] - fn to_bits() { - let mut cs: R1cs = R1cs::default(); - let input = Fr::random(OsRng); - - let x = FieldAssignment::instance(&mut cs, input); - let _ = FieldAssignment::to_bits(&mut cs, &x); - - assert!(cs.is_sat()); - } - - #[test] - fn field_range() { - for _ in 0..100 { - let mut cs: R1cs = R1cs::default(); - let mut ncs = cs.clone(); - let bound = Fr::from(10); - - let x_ass = FieldAssignment::instance(&mut cs, bound); - let x_bits = FieldAssignment::to_bits(&mut cs, &x_ass); - FieldAssignment::range_check(&mut cs, &x_bits, bound); - assert!(cs.is_sat()); - - let x_ass = FieldAssignment::instance(&mut ncs, bound + Fr::one()); - let x_bits = FieldAssignment::to_bits(&mut ncs, &x_ass); - FieldAssignment::range_check(&mut ncs, &x_bits, bound); - assert!(!ncs.is_sat()); - } - } - - #[test] - fn field_add_test() { - let mut cs: R1cs = R1cs::default(); - let mut ncs = cs.clone(); - let a = Scalar::random(OsRng); - let b = Scalar::random(OsRng); - let mut c = a + b; - - // a + b == c - let x = FieldAssignment::instance(&mut cs, a); - let y = FieldAssignment::witness(&mut cs, b); - let z = FieldAssignment::instance(&mut cs, c); - let sum = &x + &y; - FieldAssignment::eq(&mut cs, &z, &sum); - - assert!(cs.is_sat()); - - // a + b != c - c += Scalar::one(); - let x = FieldAssignment::instance(&mut ncs, a); - let y = FieldAssignment::witness(&mut ncs, b); - let z = FieldAssignment::instance(&mut ncs, c); - let sum = &x + &y; - FieldAssignment::eq(&mut ncs, &z, &sum); - - assert!(!ncs.is_sat()) - } - - #[test] - fn field_mul_test() { - let mut cs: R1cs = R1cs::default(); - let mut ncs = cs.clone(); - let a = Scalar::random(OsRng); - let b = Scalar::random(OsRng); - let mut c = a * b; - - // a * b == c - let x = FieldAssignment::instance(&mut cs, a); - let y = FieldAssignment::witness(&mut cs, b); - let z = FieldAssignment::instance(&mut cs, c); - let product = FieldAssignment::mul(&mut cs, &x, &y); - FieldAssignment::eq(&mut cs, &z, &product); - - assert!(cs.is_sat()); - - // a * b != c - c += Scalar::one(); - let x = FieldAssignment::instance(&mut ncs, a); - let y = FieldAssignment::witness(&mut ncs, b); - let z = FieldAssignment::instance(&mut ncs, c); - let product = FieldAssignment::mul(&mut ncs, &x, &y); - FieldAssignment::eq(&mut ncs, &z, &product); - - assert!(!ncs.is_sat()) - } - - #[test] - fn field_ops_test() { - let mut cs: R1cs = R1cs::default(); - let mut ncs = cs.clone(); - let input = Scalar::from(3); - let c = Scalar::from(5); - let out = Scalar::from(35); - - // x^3 + x + 5 == 35 - let x = FieldAssignment::witness(&mut cs, input); - let c = FieldAssignment::constant(&c); - let z = FieldAssignment::instance(&mut cs, out); - let sym_1 = FieldAssignment::mul(&mut cs, &x, &x); - let y = FieldAssignment::mul(&mut cs, &sym_1, &x); - let sym_2 = &y + &x; - FieldAssignment::eq(&mut cs, &z, &(&sym_2 + &c)); - - assert!(cs.is_sat()); - - // x^3 + x + 5 != 36 - let c = Scalar::from(5); - let out = Scalar::from(36); - let x = FieldAssignment::witness(&mut ncs, input); - let c = FieldAssignment::constant(&c); - let z = FieldAssignment::instance(&mut ncs, out); - let sym_1 = FieldAssignment::mul(&mut ncs, &x, &x); - let y = FieldAssignment::mul(&mut ncs, &sym_1, &x); - let sym_2 = &y + &x; - FieldAssignment::eq(&mut ncs, &z, &(&sym_2 + &c)); - - assert!(!ncs.is_sat()); - } -} diff --git a/r1cs/src/lib.rs b/r1cs/src/lib.rs deleted file mode 100644 index 65340a96..00000000 --- a/r1cs/src/lib.rs +++ /dev/null @@ -1,210 +0,0 @@ -#![doc = include_str!("../README.md")] - -mod driver; -mod gadget; -mod matrix; -pub mod prelude; -pub mod test; -mod wire; - -use driver::CircuitDriver; -pub use matrix::{DenseVectors, SparseMatrix, SparseRow}; -pub use wire::Wire; - -use core::ops::Index; -use zkstd::common::{vec, Ring, Vec}; - -#[derive(Clone, Debug)] -pub struct R1cs { - // 1. Structure S - // a, b and c matrices and matrix size - m: usize, - a: SparseMatrix, - b: SparseMatrix, - c: SparseMatrix, - - // 2. Instance - // r1cs instance includes one constant and public inputs and outputs - x: DenseVectors, - - // 3. Witness - // r1cs witness includes private inputs and intermediate value - w: DenseVectors, -} - -impl R1cs { - pub fn m(&self) -> usize { - self.m - } - - pub fn l(&self) -> usize { - self.x.len() - } - - pub fn m_l_1(&self) -> usize { - self.w.len() - } - - pub fn x(&self) -> Vec { - self.x.get() - } - - pub fn w(&self) -> Vec { - self.w.get() - } - - #[allow(clippy::type_complexity)] - pub fn matrices( - &self, - ) -> ( - SparseMatrix, - SparseMatrix, - SparseMatrix, - ) { - (self.a.clone(), self.b.clone(), self.c.clone()) - } - - /// check (A · Z) ◦ (B · Z) = C · Z - pub fn is_sat(&self) -> bool { - let R1cs { m, a, b, c, x, w } = self; - // A · Z - let az = a.prod(m, x, w); - // B · Z - let bz = b.prod(m, x, w); - // C · Z - let cz = c.prod(m, x, w); - // (A · Z) ◦ (B · Z) - let azbz = az * bz; - - azbz.iter() - .zip(cz.iter()) - .all(|(left, right)| left == right) - } - - fn append( - &mut self, - a: SparseRow, - b: SparseRow, - c: SparseRow, - ) { - self.a.0.push(a); - self.b.0.push(b); - self.c.0.push(c); - self.m += 1; - } - - fn public_wire(&mut self) -> Wire { - let index = self.x.len(); - Wire::Instance(index) - } - - fn private_wire(&mut self) -> Wire { - let index = self.w.len(); - Wire::Witness(index) - } - - /// constrain x * y = z - pub fn mul_gate( - &mut self, - x: &SparseRow, - y: &SparseRow, - z: &SparseRow, - ) { - self.append(x.clone(), y.clone(), z.clone()); - } - - /// constrain x + y = z - pub fn add_gate( - &mut self, - x: &SparseRow, - y: &SparseRow, - z: &SparseRow, - ) { - self.append(x + y, SparseRow::from(Wire::ONE), z.clone()); - } - - /// constrain x - y = z - pub fn sub_gate( - &mut self, - x: &SparseRow, - y: &SparseRow, - z: &SparseRow, - ) { - self.append(x - y, SparseRow::from(Wire::ONE), z.clone()); - } - - /// constrain x == y - pub fn equal_gate(&mut self, x: &SparseRow, y: &SparseRow) { - self.mul_gate(x, &SparseRow::one(), y); - } - - #[allow(clippy::type_complexity)] - pub fn evaluate(&self) -> (Vec, Vec, Vec) { - let a_evals = self.a.evaluate_with_z(&self.x, &self.w); - let b_evals = self.b.evaluate_with_z(&self.x, &self.w); - let c_evals = self.c.evaluate_with_z(&self.x, &self.w); - (a_evals, b_evals, c_evals) - } - - #[allow(clippy::type_complexity)] - pub fn z_vectors( - &self, - l: usize, - m_l_1: usize, - ) -> ( - ( - Vec>, - Vec>, - Vec>, - ), - ( - Vec>, - Vec>, - Vec>, - ), - ) { - let (a_x, a_w) = self.a.x_and_w(l, m_l_1); - let (b_x, b_w) = self.b.x_and_w(l, m_l_1); - let (c_x, c_w) = self.c.x_and_w(l, m_l_1); - - ((a_x, b_x, c_x), (a_w, b_w, c_w)) - } -} - -impl Default for R1cs { - fn default() -> Self { - Self { - m: 0, - a: SparseMatrix::default(), - b: SparseMatrix::default(), - c: SparseMatrix::default(), - x: DenseVectors::new(vec![C::Scalar::one()]), - w: DenseVectors::default(), - } - } -} - -impl Index for R1cs { - type Output = C::Scalar; - - fn index(&self, w: Wire) -> &Self::Output { - match w { - Wire::Instance(i) => &self.x[i], - Wire::Witness(i) => &self.w[i], - } - } -} - -#[cfg(test)] -mod tests { - use super::R1cs; - use crate::test::{example_r1cs, GrumpkinDriver}; - - #[test] - fn r1cs_test() { - for i in 1..10 { - let r1cs: R1cs = example_r1cs(i); - assert!(r1cs.is_sat()) - } - } -} diff --git a/r1cs/src/matrix.rs b/r1cs/src/matrix.rs deleted file mode 100644 index 96862781..00000000 --- a/r1cs/src/matrix.rs +++ /dev/null @@ -1,49 +0,0 @@ -mod row; -mod vector; - -use crate::wire::Wire; -pub use row::SparseRow; -pub use vector::DenseVectors; - -use zkstd::common::{vec, Debug, PrimeField, Vec}; - -#[derive(Clone, Debug, Default)] -pub struct SparseMatrix(pub(crate) Vec>); - -impl SparseMatrix { - #[allow(clippy::type_complexity)] - pub(crate) fn x_and_w( - &self, - l: usize, - m_l_1: usize, - ) -> (Vec>, Vec>) { - let mut x = vec![vec![]; l]; - let mut w = vec![vec![]; m_l_1]; - for (i, a) in self.0.iter().enumerate() { - a.iter().for_each(|(wire, coeff)| match wire { - Wire::Instance(k) => x[*k].push((*coeff, i)), - Wire::Witness(k) => w[*k].push((*coeff, i)), - }); - } - (x, w) - } - - pub(crate) fn evaluate_with_z(&self, x: &DenseVectors, w: &DenseVectors) -> Vec { - self.0.iter().map(|row| row.evaluate(x, w)).collect() - } - - // matrix-vector multiplication - pub fn prod(&self, m: &usize, x: &DenseVectors, w: &DenseVectors) -> DenseVectors { - let mut vectors = DenseVectors::zero(*m); - for (index, elements) in self.0.iter().enumerate() { - vectors[index] = elements.iter().fold(F::zero(), |sum, (wire, coeff)| { - let value = match wire { - Wire::Instance(i) => x[*i], - Wire::Witness(i) => w[*i], - }; - sum + *coeff * value - }) - } - vectors - } -} diff --git a/r1cs/src/matrix/row.rs b/r1cs/src/matrix/row.rs deleted file mode 100644 index aee62918..00000000 --- a/r1cs/src/matrix/row.rs +++ /dev/null @@ -1,203 +0,0 @@ -#![allow(clippy::op_ref)] -use super::vector::DenseVectors; -use crate::wire::Wire; - -use core::slice::Iter; -use zkstd::common::{Add, Debug, Mul, Neg, PrimeField, Sub, Vec}; - -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct SparseRow(pub(crate) Vec<(Wire, F)>); - -impl SparseRow { - /// Creates a new expression with the given wire coefficients. - pub fn new(coefficients: Vec<(Wire, F)>) -> Self { - Self( - coefficients - .into_iter() - .filter(|element| element.1 != F::zero()) - .collect(), - ) - } - - pub(crate) fn iter(&self) -> Iter<(Wire, F)> { - self.0.iter() - } - - pub fn one() -> Self { - Self::from(F::one()) - } - - pub fn num_terms(&self) -> usize { - self.0.len() - } - - /// Return Some(c) if this is a constant c, otherwise None. - pub fn as_constant(&self) -> Option { - if self.num_terms() == 1 { - get_value_from_wire(Wire::ONE, &self.0) - } else { - None - } - } - - pub fn evaluate(&self, instance: &DenseVectors, witness: &DenseVectors) -> F { - self.0.iter().fold(F::zero(), |sum, (wire, coefficient)| { - let wire_value = match wire { - Wire::Instance(i) => instance[*i], - Wire::Witness(i) => witness[*i], - }; - sum + (wire_value * *coefficient) - }) - } -} - -impl From for SparseRow { - fn from(wire: Wire) -> Self { - Self::new([(wire, F::one())].to_vec()) - } -} - -impl From<&Wire> for SparseRow { - fn from(wire: &Wire) -> Self { - Self::from(*wire) - } -} - -impl From for SparseRow { - fn from(value: F) -> Self { - Self::new([(Wire::ONE, value)].to_vec()) - } -} - -impl Add> for SparseRow { - type Output = Self; - - fn add(self, rhs: Self) -> Self { - &self + &rhs - } -} - -impl Add<&SparseRow> for SparseRow { - type Output = Self; - - fn add(self, rhs: &Self) -> Self { - &self + rhs - } -} - -impl Add> for &SparseRow { - type Output = SparseRow; - - fn add(self, rhs: SparseRow) -> Self::Output { - self + &rhs - } -} - -impl Add<&SparseRow> for &SparseRow { - type Output = SparseRow; - - fn add(self, rhs: &SparseRow) -> Self::Output { - let mut res = self - .0 - .clone() - .into_iter() - .filter(|(w, _)| get_value_from_wire(*w, &rhs.0).is_none()) - .collect::>(); - for (wire, coeff_b) in rhs.0.clone() { - match get_value_from_wire(wire, &self.0) { - Some(coeff_a) => res.push((wire, coeff_a + coeff_b)), - None => res.push((wire, coeff_b)), - } - } - SparseRow::new(res) - } -} - -impl Sub> for SparseRow { - type Output = SparseRow; - - fn sub(self, rhs: SparseRow) -> Self::Output { - &self - &rhs - } -} - -impl Sub<&SparseRow> for SparseRow { - type Output = SparseRow; - - fn sub(self, rhs: &SparseRow) -> Self::Output { - &self - rhs - } -} - -impl Sub> for &SparseRow { - type Output = SparseRow; - - fn sub(self, rhs: SparseRow) -> Self::Output { - self - &rhs - } -} - -impl Sub<&SparseRow> for &SparseRow { - type Output = SparseRow; - - fn sub(self, rhs: &SparseRow) -> Self::Output { - self + -rhs - } -} - -impl Neg for &SparseRow { - type Output = SparseRow; - - fn neg(self) -> Self::Output { - self * -F::one() - } -} - -impl Neg for SparseRow { - type Output = SparseRow; - - fn neg(self) -> Self::Output { - -&self - } -} - -impl Mul for SparseRow { - type Output = SparseRow; - - fn mul(self, rhs: F) -> Self::Output { - &self * &rhs - } -} - -impl Mul<&F> for SparseRow { - type Output = SparseRow; - - fn mul(self, rhs: &F) -> Self::Output { - &self * rhs - } -} - -impl Mul for &SparseRow { - type Output = SparseRow; - - fn mul(self, rhs: F) -> Self::Output { - self * &rhs - } -} - -impl Mul<&F> for &SparseRow { - type Output = SparseRow; - - fn mul(self, rhs: &F) -> Self::Output { - SparseRow::new(self.0.iter().map(|(k, v)| (*k, *v * *rhs)).collect()) - } -} - -fn get_value_from_wire(index: Wire, vectors: &[(Wire, F)]) -> Option { - for vector in vectors { - if index == vector.0 { - return Some(vector.1); - } - } - None -} diff --git a/r1cs/src/matrix/vector.rs b/r1cs/src/matrix/vector.rs deleted file mode 100644 index 02036564..00000000 --- a/r1cs/src/matrix/vector.rs +++ /dev/null @@ -1,114 +0,0 @@ -use core::ops::{Index, IndexMut}; -use zkstd::common::{vec, Add, Mul, PrimeField, Sub, Vec}; - -#[derive(Clone, Debug, Default, PartialEq, Eq)] -pub struct DenseVectors(Vec); - -impl DenseVectors { - pub fn new(vectors: Vec) -> Self { - Self(vectors) - } - - pub fn get(&self) -> Vec { - self.0.clone() - } - - pub fn push(&mut self, vector: F) { - self.0.push(vector) - } - - pub fn len(&self) -> usize { - self.0.len() - } - - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } - - pub fn iter(&self) -> DenseVectorsIterator { - DenseVectorsIterator { - dense_vectors: self.clone(), - index: 0, - } - } - - pub fn one(m: usize) -> Self { - Self(vec![F::one(); m]) - } - - pub fn zero(m: usize) -> Self { - Self(vec![F::zero(); m]) - } -} - -pub struct DenseVectorsIterator { - dense_vectors: DenseVectors, - index: usize, -} - -impl Iterator for DenseVectorsIterator { - type Item = F; - - fn next(&mut self) -> Option { - if self.index < self.dense_vectors.0.len() { - let item = Some(self.dense_vectors[self.index]); - self.index += 1; - item - } else { - None - } - } -} - -impl Index for DenseVectors { - type Output = F; - - fn index(&self, index: usize) -> &Self::Output { - &self.0[index] - } -} - -impl IndexMut for DenseVectors { - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - &mut self.0[index] - } -} - -impl Mul for DenseVectors { - type Output = Self; - - fn mul(self, rhs: F) -> Self { - Self(self.iter().map(|element| element * rhs).collect()) - } -} - -/// Hadamard product -impl Mul for DenseVectors { - type Output = Self; - - fn mul(self, rhs: Self) -> Self::Output { - assert_eq!(self.0.len(), rhs.0.len()); - - Self(self.iter().zip(rhs.iter()).map(|(a, b)| a * b).collect()) - } -} - -impl Add for DenseVectors { - type Output = Self; - - fn add(self, rhs: Self) -> Self::Output { - assert_eq!(self.0.len(), rhs.0.len()); - - Self(self.iter().zip(rhs.iter()).map(|(a, b)| a + b).collect()) - } -} - -impl Sub for DenseVectors { - type Output = Self; - - fn sub(self, rhs: Self) -> Self::Output { - assert_eq!(self.0.len(), rhs.0.len()); - - Self(self.iter().zip(rhs.iter()).map(|(a, b)| a - b).collect()) - } -} diff --git a/r1cs/src/prelude.rs b/r1cs/src/prelude.rs deleted file mode 100644 index 082ce78e..00000000 --- a/r1cs/src/prelude.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub use super::R1cs; -pub use crate::driver::{CircuitDriver, GrumpkinDriver}; -pub use crate::gadget::{FieldAssignment, PointAssignment}; diff --git a/r1cs/src/wire.rs b/r1cs/src/wire.rs deleted file mode 100644 index 3b06ffae..00000000 --- a/r1cs/src/wire.rs +++ /dev/null @@ -1,43 +0,0 @@ -use core::{ - cmp::Ordering, - fmt::{self, Formatter}, -}; - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub enum Wire { - Instance(usize), - Witness(usize), -} - -impl Wire { - pub const ONE: Wire = Wire::Instance(0); -} - -impl Ord for Wire { - fn cmp(&self, other: &Self) -> Ordering { - let rhs = match self { - Wire::Instance(i) => i, - Wire::Witness(i) => i, - }; - let lhs = match other { - Wire::Instance(i) => i, - Wire::Witness(i) => i, - }; - rhs.cmp(lhs) - } -} - -impl PartialOrd for Wire { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl fmt::Display for Wire { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - Self::Instance(i) => write!(f, "instance {:?}", i), - Self::Witness(i) => write!(f, "witness {:?}", i), - } - } -} diff --git a/zkstd/Cargo.toml b/zkstd/Cargo.toml index 17d82517..cf320287 100644 --- a/zkstd/Cargo.toml +++ b/zkstd/Cargo.toml @@ -25,10 +25,6 @@ sp-std = { version = '3.0.0', default-features = false } parity-scale-codec = { version = "2.0.0", default-features = false, features = ["derive"] } serde = { version = "1.0.102", default-features = false, features = ["derive"] } -[dev-dependencies] -grumpkin = { path = '../grumpkin', default-features = false } -bn-254 = { path = '../bn254', default-features = false } - [[test]] name = "arithmetics" path = "tests/limbs.rs" diff --git a/zkstd/src/circuit/prelude.rs b/zkstd/src/circuit/prelude.rs index 6f2d112f..57efbf45 100644 --- a/zkstd/src/circuit/prelude.rs +++ b/zkstd/src/circuit/prelude.rs @@ -1,2 +1,3 @@ pub use super::CircuitDriver; pub use crate::circuit::gadget::{curve::PointAssignment, field::FieldAssignment}; +pub use crate::r1cs::R1cs; diff --git a/zkstd/src/r1cs.rs b/zkstd/src/r1cs.rs index 712dfcf6..ebbcc885 100644 --- a/zkstd/src/r1cs.rs +++ b/zkstd/src/r1cs.rs @@ -1,3 +1,4 @@ +pub mod test; mod wire; use crate::circuit::CircuitDriver; diff --git a/r1cs/src/test.rs b/zkstd/src/r1cs/test.rs similarity index 77% rename from r1cs/src/test.rs rename to zkstd/src/r1cs/test.rs index 3211d4d9..e3a4eca1 100644 --- a/r1cs/src/test.rs +++ b/zkstd/src/r1cs/test.rs @@ -1,35 +1,8 @@ -use crate::driver::CircuitDriver; +use super::{R1cs, Wire}; +use crate::circuit::CircuitDriver; use crate::matrix::{DenseVectors, SparseMatrix, SparseRow}; -use crate::wire::Wire; -use crate::R1cs; -use bn_254::{Fq, Fr, G1Affine}; -use zkstd::common::{vec, PrimeField, Vec}; - -// bn curve b param -pub(crate) const PARAM_B: Fr = Fr::new_unchecked([ - 0xdd7056026000005a, - 0x223fa97acb319311, - 0xcc388229877910c0, - 0x034394632b724eaa, -]); -pub const PARAM_B3: Fr = PARAM_B.add_const(PARAM_B).add_const(PARAM_B); - -#[derive(Clone, Debug, Default, PartialEq, Eq)] -pub(crate) struct GrumpkinDriver; - -impl CircuitDriver for GrumpkinDriver { - const NUM_BITS: u16 = 254; - type Affine = G1Affine; - - type Base = Fq; - - type Scalar = Fr; - - fn b3() -> Self::Scalar { - PARAM_B3 - } -} +use crate::common::{vec, PrimeField, Vec}; fn array_to_witnessess(witnesses: Vec) -> Vec { witnesses From fa5a57b0d7006c1caafd2ec31f29773e881ac79a Mon Sep 17 00:00:00 2001 From: ashWhiteHat Date: Fri, 24 Nov 2023 15:19:50 +0900 Subject: [PATCH 6/9] test: bn254 fr field --- grumpkin/src/params.rs | 1 + zkstd/tests/grumpkin.rs | 138 +++++++++++++++++++++ zkstd/tests/{construction.rs => jubjub.rs} | 0 zkstd/tests/limbs.rs | 6 +- zkstd/tests/points.rs | 4 +- 5 files changed, 144 insertions(+), 5 deletions(-) create mode 100644 zkstd/tests/grumpkin.rs rename zkstd/tests/{construction.rs => jubjub.rs} (100%) diff --git a/grumpkin/src/params.rs b/grumpkin/src/params.rs index 9cfe00da..93d8d708 100644 --- a/grumpkin/src/params.rs +++ b/grumpkin/src/params.rs @@ -8,6 +8,7 @@ pub const GENERATOR_Y: Fr = Fr::new_unchecked([ 0xaa7b8cf435dfafbb, 0x14b34cf69dc25d68, ]); + // bn curve b param pub(crate) const PARAM_B: Fr = Fr::new_unchecked([ 0xdd7056026000005a, diff --git a/zkstd/tests/grumpkin.rs b/zkstd/tests/grumpkin.rs new file mode 100644 index 00000000..ffe5f9a6 --- /dev/null +++ b/zkstd/tests/grumpkin.rs @@ -0,0 +1,138 @@ +use zkstd::arithmetic::bits_256::*; +use zkstd::circuit::CircuitDriver; +use zkstd::common::*; +use zkstd::macros::field::*; + +pub(crate) const FR_MODULUS: [u64; 4] = [ + 0x43e1f593f0000001, + 0x2833e84879b97091, + 0xb85045b68181585d, + 0x30644e72e131a029, +]; + +const FR_GENERATOR: [u64; 4] = [7, 0, 0, 0]; + +pub(crate) const FR_R: [u64; 4] = [ + 0xac96341c4ffffffb, + 0x36fc76959f60cd29, + 0x666ea36f7879462e, + 0x0e0a77c19a07df2f, +]; + +pub(crate) const FR_R2: [u64; 4] = [ + 0x1bb8e645ae216da7, + 0x53fe3ab1e35c59e3, + 0x8c49833d53bb8085, + 0x0216d0b17f4e44a5, +]; + +pub(crate) const FR_R3: [u64; 4] = [ + 0x5e94d8e1b4bf0040, + 0x2a489cbe1cfbb6b8, + 0x893cc664a19fcfed, + 0x0cf8594b7fcc657c, +]; + +pub const FR_INV: u64 = 0xc2e1f593efffffff; + +pub const FR_ROOT_OF_UNITY: [u64; 4] = [ + 0xd34f1ed960c37c9c, + 0x3215cf6dd39329c8, + 0x98865ea93dd31f74, + 0x03ddb9f5166d18b7, +]; + +curve_macro!(Fr, FR_GENERATOR, FR_MODULUS, FR_R, FR_R2, FR_R3, FR_INV); + +pub(crate) const FR_PARAM_B: Fr = Fr::new_unchecked([ + 0xdd7056026000005a, + 0x223fa97acb319311, + 0xcc388229877910c0, + 0x034394632b724eaa, +]); + +pub const FR_PARAM_B3: Fr = FR_PARAM_B.add_const(FR_PARAM_B).add_const(FR_PARAM_B); + +#[macro_export] +macro_rules! curve_macro { + ($field:ident, $generator:ident, $modulus:ident, $r:ident, $r2:ident, $r3:ident, $inv:ident) => { + #[derive(Clone, Copy, Decode, Encode, Serialize, Deserialize)] + pub struct $field(pub [u64; 4]); + + impl $field { + pub const fn new_unchecked(val: [u64; 4]) -> Self { + Self(val) + } + pub const fn add_const(self, rhs: Self) -> Self { + Self(add(self.0, rhs.0, $modulus)) + } + + pub const fn to_mont_form(val: [u64; 4]) -> Self { + Self(to_mont_form(val, $r2, $modulus, $inv)) + } + + pub const fn inner(&self) -> &[u64; 4] { + &self.0 + } + + pub(crate) const fn montgomery_reduce(self) -> [u64; 4] { + mont( + [self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0], + $modulus, + $inv, + ) + } + } + + impl SigUtils<32> for $field { + fn to_bytes(self) -> [u8; Self::LENGTH] { + let tmp = self.montgomery_reduce(); + + let mut res = [0; Self::LENGTH]; + res[0..8].copy_from_slice(&tmp[0].to_le_bytes()); + res[8..16].copy_from_slice(&tmp[1].to_le_bytes()); + res[16..24].copy_from_slice(&tmp[2].to_le_bytes()); + res[24..32].copy_from_slice(&tmp[3].to_le_bytes()); + + res + } + + fn from_bytes(bytes: [u8; Self::LENGTH]) -> Option { + // SBP-M1 review: apply proper error handling instead of `unwrap` + let l0 = u64::from_le_bytes(bytes[0..8].try_into().unwrap()); + let l1 = u64::from_le_bytes(bytes[8..16].try_into().unwrap()); + let l2 = u64::from_le_bytes(bytes[16..24].try_into().unwrap()); + let l3 = u64::from_le_bytes(bytes[24..32].try_into().unwrap()); + + let (_, borrow) = sbb(l0, $modulus[0], 0); + let (_, borrow) = sbb(l1, $modulus[1], borrow); + let (_, borrow) = sbb(l2, $modulus[2], borrow); + let (_, borrow) = sbb(l3, $modulus[3], borrow); + + if borrow & 1 == 1 { + Some(Self([l0, l1, l2, l3]) * Self($r2)) + } else { + None + } + } + } + + prime_field_operation!($field, $modulus, $generator, $inv, $r, $r2, $r3); + }; +} + +// #[derive(Clone, Debug, Default, PartialEq, Eq)] +// pub struct GrumpkinDriver; + +// impl CircuitDriver for GrumpkinDriver { +// const NUM_BITS: u16 = 254; +// type Affine = G1Affine; + +// type Base = Fq; + +// type Scalar = Fr; + +// fn b3() -> Self::Scalar { +// PARAM_B3 +// } +// } diff --git a/zkstd/tests/construction.rs b/zkstd/tests/jubjub.rs similarity index 100% rename from zkstd/tests/construction.rs rename to zkstd/tests/jubjub.rs diff --git a/zkstd/tests/limbs.rs b/zkstd/tests/limbs.rs index f0ada71f..57232823 100644 --- a/zkstd/tests/limbs.rs +++ b/zkstd/tests/limbs.rs @@ -1,11 +1,11 @@ -mod construction; +mod jubjub; macro_rules! limbs_test { ($test_name:ident, $test_bits:ident, $test_mod:ident, $limbs_type:ident, $one:expr, $two:expr) => { #[cfg(test)] mod $test_name { use super::*; - use construction::$test_mod::*; + use jubjub::$test_mod::*; use paste::paste; use rand_core::OsRng; use zkstd::arithmetic::$test_bits::*; @@ -117,7 +117,7 @@ macro_rules! limbs_test { }; } -use construction::{Bits256Limbs, Bits384Limbs}; +use jubjub::{Bits256Limbs, Bits384Limbs}; limbs_test!( jubjub_limbs_tests, diff --git a/zkstd/tests/points.rs b/zkstd/tests/points.rs index 3ed31b8a..8d07c7b3 100644 --- a/zkstd/tests/points.rs +++ b/zkstd/tests/points.rs @@ -1,9 +1,9 @@ -mod construction; +mod jubjub; #[cfg(test)] mod twisted_edwards_points_tests { use super::*; - use construction::jubjub_curve::{BlsScalar, JubjubAffine, JubjubExtended}; + use jubjub::jubjub_curve::{BlsScalar, JubjubAffine, JubjubExtended}; use rand_core::OsRng; use zkstd::{ arithmetic::edwards::*, From 202afa0e16643f8a2d77e2e0f983c8740be231a2 Mon Sep 17 00:00:00 2001 From: ashWhiteHat Date: Fri, 24 Nov 2023 15:27:23 +0900 Subject: [PATCH 7/9] test: grumpkin driver --- zkstd/tests/grumpkin.rs | 207 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 190 insertions(+), 17 deletions(-) diff --git a/zkstd/tests/grumpkin.rs b/zkstd/tests/grumpkin.rs index ffe5f9a6..afd2e019 100644 --- a/zkstd/tests/grumpkin.rs +++ b/zkstd/tests/grumpkin.rs @@ -1,6 +1,8 @@ use zkstd::arithmetic::bits_256::*; +use zkstd::arithmetic::weierstrass::*; use zkstd::circuit::CircuitDriver; use zkstd::common::*; +use zkstd::macros::curve::weierstrass::*; use zkstd::macros::field::*; pub(crate) const FR_MODULUS: [u64; 4] = [ @@ -35,14 +37,44 @@ pub(crate) const FR_R3: [u64; 4] = [ pub const FR_INV: u64 = 0xc2e1f593efffffff; -pub const FR_ROOT_OF_UNITY: [u64; 4] = [ - 0xd34f1ed960c37c9c, - 0x3215cf6dd39329c8, - 0x98865ea93dd31f74, - 0x03ddb9f5166d18b7, +pub(crate) const FQ_MODULUS: [u64; 4] = [ + 0x3c208c16d87cfd47, + 0x97816a916871ca8d, + 0xb85045b68181585d, + 0x30644e72e131a029, +]; + +pub(crate) const FQ_GENERATOR: [u64; 4] = [3, 0, 0, 0]; + +/// R = 2^256 mod q +pub(crate) const FQ_R: [u64; 4] = [ + 0xd35d438dc58f0d9d, + 0x0a78eb28f5c70b3d, + 0x666ea36f7879462c, + 0x0e0a77c19a07df2f, +]; + +/// R^2 = 2^512 mod q +pub(crate) const FQ_R2: [u64; 4] = [ + 0xf32cfc5b538afa89, + 0xb5e71911d44501fb, + 0x47ab1eff0a417ff6, + 0x06d89f71cab8351f, +]; + +/// R^3 = 2^768 mod q +pub(crate) const FQ_R3: [u64; 4] = [ + 0xb1cd6dafda1530df, + 0x62f210e6a7283db6, + 0xef7f0b0c0ada0afb, + 0x20fd6e902d592544, ]; +/// INV = -(q^{-1} mod 2^64) mod 2^64 +pub(crate) const FQ_INV: u64 = 0x87d20782e4866389; + curve_macro!(Fr, FR_GENERATOR, FR_MODULUS, FR_R, FR_R2, FR_R3, FR_INV); +curve_macro!(Fq, FQ_GENERATOR, FQ_MODULUS, FQ_R, FQ_R2, FQ_R3, FQ_INV); pub(crate) const FR_PARAM_B: Fr = Fr::new_unchecked([ 0xdd7056026000005a, @@ -50,9 +82,13 @@ pub(crate) const FR_PARAM_B: Fr = Fr::new_unchecked([ 0xcc388229877910c0, 0x034394632b724eaa, ]); - pub const FR_PARAM_B3: Fr = FR_PARAM_B.add_const(FR_PARAM_B).add_const(FR_PARAM_B); +pub(crate) const G1_GENERATOR_X: Fq = Fq::one(); +pub(crate) const G1_GENERATOR_Y: Fq = Fq::to_mont_form([2, 0, 0, 0]); +pub(crate) const G1_PARAM_B: Fq = Fq::to_mont_form([3, 0, 0, 0]); +pub const FQ_PARAM_B3: Fq = G1_PARAM_B.add_const(G1_PARAM_B).add_const(G1_PARAM_B); + #[macro_export] macro_rules! curve_macro { ($field:ident, $generator:ident, $modulus:ident, $r:ident, $r2:ident, $r3:ident, $inv:ident) => { @@ -121,18 +157,155 @@ macro_rules! curve_macro { }; } -// #[derive(Clone, Debug, Default, PartialEq, Eq)] -// pub struct GrumpkinDriver; +impl From for Fr { + fn from(val: Fq) -> Fr { + Self(to_mont_form( + val.montgomery_reduce(), + FR_R2, + FR_MODULUS, + FR_INV, + )) + } +} + +impl From for Fq { + fn from(val: Fr) -> Fq { + Self(to_mont_form( + val.montgomery_reduce(), + FQ_R2, + FQ_MODULUS, + FQ_INV, + )) + } +} + +/// The projective form of coordinate +#[derive(Debug, Clone, Copy, Decode, Encode)] +pub struct G1Affine { + pub(crate) x: Fq, + pub(crate) y: Fq, + is_infinity: bool, +} + +impl Add for G1Affine { + type Output = G1Projective; + + fn add(self, rhs: G1Affine) -> Self::Output { + add_affine_point(self, rhs) + } +} + +impl Neg for G1Affine { + type Output = Self; -// impl CircuitDriver for GrumpkinDriver { -// const NUM_BITS: u16 = 254; -// type Affine = G1Affine; + fn neg(self) -> Self { + Self { + x: self.x, + y: -self.y, + is_infinity: self.is_infinity, + } + } +} -// type Base = Fq; +impl Sub for G1Affine { + type Output = G1Projective; -// type Scalar = Fr; + fn sub(self, rhs: G1Affine) -> Self::Output { + add_affine_point(self, rhs.neg()) + } +} + +impl Mul for G1Affine { + type Output = G1Projective; + + fn mul(self, rhs: Fr) -> Self::Output { + scalar_point(self.to_extended(), &rhs) + } +} -// fn b3() -> Self::Scalar { -// PARAM_B3 -// } -// } +impl Mul for Fr { + type Output = G1Projective; + + fn mul(self, rhs: G1Affine) -> Self::Output { + scalar_point(rhs.to_extended(), &self) + } +} + +/// The projective form of coordinate +#[derive(Debug, Clone, Copy, Decode, Encode)] +pub struct G1Projective { + pub(crate) x: Fq, + pub(crate) y: Fq, + pub(crate) z: Fq, +} + +impl Add for G1Projective { + type Output = Self; + + fn add(self, rhs: G1Projective) -> Self { + add_projective_point(self, rhs) + } +} + +impl Neg for G1Projective { + type Output = Self; + + fn neg(self) -> Self { + Self { + x: self.x, + y: -self.y, + z: self.z, + } + } +} + +impl Sub for G1Projective { + type Output = Self; + + fn sub(self, rhs: G1Projective) -> Self { + add_projective_point(self, -rhs) + } +} + +impl Mul for G1Projective { + type Output = G1Projective; + + fn mul(self, rhs: Fr) -> Self::Output { + scalar_point(self, &rhs) + } +} + +impl Mul for Fr { + type Output = G1Projective; + + fn mul(self, rhs: G1Projective) -> Self::Output { + scalar_point(rhs, &self) + } +} + +weierstrass_curve_operation!( + Fr, + Fq, + G1_PARAM_B, + FQ_PARAM_B3, + G1Affine, + G1Projective, + G1_GENERATOR_X, + G1_GENERATOR_Y +); + +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct GrumpkinDriver; + +impl CircuitDriver for GrumpkinDriver { + const NUM_BITS: u16 = 254; + type Affine = G1Affine; + + type Base = Fq; + + type Scalar = Fr; + + fn b3() -> Self::Scalar { + FR_PARAM_B3 + } +} From a74f25b235b04740cef771ff8d08e21913511b82 Mon Sep 17 00:00:00 2001 From: ashWhiteHat Date: Fri, 24 Nov 2023 15:48:09 +0900 Subject: [PATCH 8/9] test: field, curve and binary gadget --- zkstd/tests/gadget.rs | 204 ++++++++++++++++++++++++++++++++++++++++ zkstd/tests/grumpkin.rs | 161 +++++++++++++++++++++++++++---- 2 files changed, 348 insertions(+), 17 deletions(-) create mode 100644 zkstd/tests/gadget.rs diff --git a/zkstd/tests/gadget.rs b/zkstd/tests/gadget.rs new file mode 100644 index 00000000..6db758f9 --- /dev/null +++ b/zkstd/tests/gadget.rs @@ -0,0 +1,204 @@ +mod grumpkin; + +#[cfg(test)] +mod grumpkin_gadget_tests { + use crate::grumpkin::{Affine, Fq as Base, Fr as Scalar, GrumpkinDriver}; + + use rand_core::OsRng; + use zkstd::circuit::prelude::{FieldAssignment, PointAssignment, R1cs}; + use zkstd::common::{BNAffine, BNProjective, CurveGroup, Group, PrimeField}; + + #[test] + fn range_proof_test() { + for _ in 0..100 { + let mut cs: R1cs = R1cs::default(); + let mut ncs = cs.clone(); + let bound = Scalar::from(10); + + let x_ass = FieldAssignment::instance(&mut cs, bound); + let x_bits = FieldAssignment::to_bits(&mut cs, &x_ass); + FieldAssignment::range_check(&mut cs, &x_bits, bound); + assert!(cs.is_sat()); + + let x_ass = FieldAssignment::instance(&mut ncs, bound + Scalar::one()); + let x_bits = FieldAssignment::to_bits(&mut ncs, &x_ass); + FieldAssignment::range_check(&mut ncs, &x_bits, bound); + assert!(!ncs.is_sat()); + } + } + + #[test] + fn field_add_test() { + let mut cs: R1cs = R1cs::default(); + let mut ncs = cs.clone(); + let a = Scalar::random(OsRng); + let b = Scalar::random(OsRng); + let mut c = a + b; + + // a + b == c + let x = FieldAssignment::instance(&mut cs, a); + let y = FieldAssignment::witness(&mut cs, b); + let z = FieldAssignment::instance(&mut cs, c); + let sum = &x + &y; + FieldAssignment::eq(&mut cs, &z, &sum); + + assert!(cs.is_sat()); + + // a + b != c + c += Scalar::one(); + let x = FieldAssignment::instance(&mut ncs, a); + let y = FieldAssignment::witness(&mut ncs, b); + let z = FieldAssignment::instance(&mut ncs, c); + let sum = &x + &y; + FieldAssignment::eq(&mut ncs, &z, &sum); + + assert!(!ncs.is_sat()) + } + + #[test] + fn field_mul_test() { + let mut cs: R1cs = R1cs::default(); + let mut ncs = cs.clone(); + let a = Scalar::random(OsRng); + let b = Scalar::random(OsRng); + let mut c = a * b; + + // a * b == c + let x = FieldAssignment::instance(&mut cs, a); + let y = FieldAssignment::witness(&mut cs, b); + let z = FieldAssignment::instance(&mut cs, c); + let product = FieldAssignment::mul(&mut cs, &x, &y); + FieldAssignment::eq(&mut cs, &z, &product); + + assert!(cs.is_sat()); + + // a * b != c + c += Scalar::one(); + let x = FieldAssignment::instance(&mut ncs, a); + let y = FieldAssignment::witness(&mut ncs, b); + let z = FieldAssignment::instance(&mut ncs, c); + let product = FieldAssignment::mul(&mut ncs, &x, &y); + FieldAssignment::eq(&mut ncs, &z, &product); + + assert!(!ncs.is_sat()) + } + + #[test] + fn field_ops_test() { + let mut cs: R1cs = R1cs::default(); + let mut ncs = cs.clone(); + let input = Scalar::from(3); + let c = Scalar::from(5); + let out = Scalar::from(35); + + // x^3 + x + 5 == 35 + let x = FieldAssignment::witness(&mut cs, input); + let c = FieldAssignment::constant(&c); + let z = FieldAssignment::instance(&mut cs, out); + let sym_1 = FieldAssignment::mul(&mut cs, &x, &x); + let y = FieldAssignment::mul(&mut cs, &sym_1, &x); + let sym_2 = &y + &x; + FieldAssignment::eq(&mut cs, &z, &(&sym_2 + &c)); + + assert!(cs.is_sat()); + + // x^3 + x + 5 != 36 + let c = Scalar::from(5); + let out = Scalar::from(36); + let x = FieldAssignment::witness(&mut ncs, input); + let c = FieldAssignment::constant(&c); + let z = FieldAssignment::instance(&mut ncs, out); + let sym_1 = FieldAssignment::mul(&mut ncs, &x, &x); + let y = FieldAssignment::mul(&mut ncs, &sym_1, &x); + let sym_2 = &y + &x; + FieldAssignment::eq(&mut ncs, &z, &(&sym_2 + &c)); + + assert!(!ncs.is_sat()); + } + + #[test] + fn curve_double_test() { + for _ in 0..100 { + let mut cs: R1cs = R1cs::default(); + let point = Affine::random(OsRng); + + let circuit_double = PointAssignment::instance( + &mut cs, + point.get_x(), + point.get_y(), + point.is_identity(), + ) + .double(&mut cs); + + let expected = point.to_extended().double(); + + circuit_double.assert_equal_public_point(&mut cs, expected); + + assert!(cs.is_sat()); + } + } + + #[test] + fn curve_add_test() { + // Identity addition test + { + let mut cs: R1cs = R1cs::default(); + let a = Affine::random(OsRng); + let b = Affine::ADDITIVE_IDENTITY; + + let a_assignment = + PointAssignment::instance(&mut cs, a.get_x(), a.get_y(), a.is_identity()); + let b_assignment = + PointAssignment::instance(&mut cs, b.get_x(), b.get_y(), b.is_identity()); + + let expected = a + b; + + let sum_circuit = a_assignment.add(&b_assignment, &mut cs); + + sum_circuit.assert_equal_public_point(&mut cs, expected); + + assert!(cs.is_sat()); + } + + for _ in 0..100 { + let mut cs: R1cs = R1cs::default(); + let a = Affine::random(OsRng); + let b = Affine::random(OsRng); + + let a_assignment = + PointAssignment::instance(&mut cs, a.get_x(), a.get_y(), a.is_identity()); + let b_assignment = + PointAssignment::instance(&mut cs, b.get_x(), b.get_y(), b.is_identity()); + + let expected = a.to_extended() + b.to_extended(); + + let sum_circuit = a_assignment.add(&b_assignment, &mut cs); + + sum_circuit.assert_equal_public_point(&mut cs, expected); + + assert!(cs.is_sat()); + } + } + + #[test] + fn curve_scalar_mul_test() { + for _ in 0..100 { + let mut cs: R1cs = R1cs::default(); + let x = Scalar::random(OsRng); + let p = Affine::random(OsRng); + + let x_assignment = FieldAssignment::instance(&mut cs, x); // Fr + let p_assignment = + PointAssignment::instance(&mut cs, p.get_x(), p.get_y(), p.is_identity()); + let expected = p * Base::from(x); + + assert_eq!(x.to_bits(), Base::from(x).to_bits()); + + let mul_circuit = p_assignment.scalar_point(&mut cs, &x_assignment); + + mul_circuit.assert_equal_public_point(&mut cs, expected); + + assert!(cs.is_sat()); + } + } +} diff --git a/zkstd/tests/grumpkin.rs b/zkstd/tests/grumpkin.rs index afd2e019..d3f4903e 100644 --- a/zkstd/tests/grumpkin.rs +++ b/zkstd/tests/grumpkin.rs @@ -73,24 +73,8 @@ pub(crate) const FQ_R3: [u64; 4] = [ /// INV = -(q^{-1} mod 2^64) mod 2^64 pub(crate) const FQ_INV: u64 = 0x87d20782e4866389; -curve_macro!(Fr, FR_GENERATOR, FR_MODULUS, FR_R, FR_R2, FR_R3, FR_INV); -curve_macro!(Fq, FQ_GENERATOR, FQ_MODULUS, FQ_R, FQ_R2, FQ_R3, FQ_INV); - -pub(crate) const FR_PARAM_B: Fr = Fr::new_unchecked([ - 0xdd7056026000005a, - 0x223fa97acb319311, - 0xcc388229877910c0, - 0x034394632b724eaa, -]); -pub const FR_PARAM_B3: Fr = FR_PARAM_B.add_const(FR_PARAM_B).add_const(FR_PARAM_B); - -pub(crate) const G1_GENERATOR_X: Fq = Fq::one(); -pub(crate) const G1_GENERATOR_Y: Fq = Fq::to_mont_form([2, 0, 0, 0]); -pub(crate) const G1_PARAM_B: Fq = Fq::to_mont_form([3, 0, 0, 0]); -pub const FQ_PARAM_B3: Fq = G1_PARAM_B.add_const(G1_PARAM_B).add_const(G1_PARAM_B); - #[macro_export] -macro_rules! curve_macro { +macro_rules! cycle_pair_field { ($field:ident, $generator:ident, $modulus:ident, $r:ident, $r2:ident, $r3:ident, $inv:ident) => { #[derive(Clone, Copy, Decode, Encode, Serialize, Deserialize)] pub struct $field(pub [u64; 4]); @@ -157,6 +141,22 @@ macro_rules! curve_macro { }; } +cycle_pair_field!(Fr, FR_GENERATOR, FR_MODULUS, FR_R, FR_R2, FR_R3, FR_INV); +cycle_pair_field!(Fq, FQ_GENERATOR, FQ_MODULUS, FQ_R, FQ_R2, FQ_R3, FQ_INV); + +pub(crate) const FR_PARAM_B: Fr = Fr::new_unchecked([ + 0xdd7056026000005a, + 0x223fa97acb319311, + 0xcc388229877910c0, + 0x034394632b724eaa, +]); +pub const FR_PARAM_B3: Fr = FR_PARAM_B.add_const(FR_PARAM_B).add_const(FR_PARAM_B); + +pub(crate) const G1_GENERATOR_X: Fq = Fq::one(); +pub(crate) const G1_GENERATOR_Y: Fq = Fq::to_mont_form([2, 0, 0, 0]); +pub(crate) const G1_PARAM_B: Fq = Fq::to_mont_form([3, 0, 0, 0]); +pub const FQ_PARAM_B3: Fq = G1_PARAM_B.add_const(G1_PARAM_B).add_const(G1_PARAM_B); + impl From for Fr { fn from(val: Fq) -> Fr { Self(to_mont_form( @@ -294,6 +294,133 @@ weierstrass_curve_operation!( G1_GENERATOR_Y ); +#[derive(Debug, Clone, Copy, Decode, Encode)] +pub struct Affine { + pub(crate) x: Fr, + pub(crate) y: Fr, + is_infinity: bool, +} +impl Add for Affine { + type Output = Projective; + + fn add(self, rhs: Affine) -> Self::Output { + add_affine_point(self, rhs) + } +} + +impl Neg for Affine { + type Output = Self; + + fn neg(self) -> Self { + Self { + x: self.x, + y: -self.y, + is_infinity: self.is_infinity, + } + } +} + +impl Sub for Affine { + type Output = Projective; + + fn sub(self, rhs: Affine) -> Self::Output { + add_affine_point(self, rhs.neg()) + } +} + +impl Mul for Affine { + type Output = Projective; + + fn mul(self, rhs: Fq) -> Self::Output { + scalar_point(self.to_extended(), &rhs) + } +} + +impl Mul for Fq { + type Output = Projective; + + fn mul(self, rhs: Affine) -> Self::Output { + scalar_point(rhs.to_extended(), &self) + } +} + +#[derive(Debug, Clone, Copy, Decode, Encode)] +pub struct Projective { + pub(crate) x: Fr, + pub(crate) y: Fr, + pub(crate) z: Fr, +} + +impl Add for Projective { + type Output = Self; + + fn add(self, rhs: Projective) -> Self { + add_projective_point(self, rhs) + } +} + +impl Neg for Projective { + type Output = Self; + + fn neg(self) -> Self { + Self { + x: self.x, + y: -self.y, + z: self.z, + } + } +} + +impl Sub for Projective { + type Output = Self; + + fn sub(self, rhs: Projective) -> Self { + add_projective_point(self, -rhs) + } +} + +impl Mul for Projective { + type Output = Projective; + + fn mul(self, rhs: Fq) -> Self::Output { + scalar_point(self, &rhs) + } +} + +impl Mul for Fq { + type Output = Projective; + + fn mul(self, rhs: Projective) -> Self::Output { + scalar_point(rhs, &self) + } +} + +pub const GENERATOR_X: Fr = Fr::one(); +pub const GENERATOR_Y: Fr = Fr::new_unchecked([ + 0x11b2dff1448c41d8, + 0x23d3446f21c77dc3, + 0xaa7b8cf435dfafbb, + 0x14b34cf69dc25d68, +]); +pub(crate) const PARAM_B: Fr = Fr::new_unchecked([ + 0xdd7056026000005a, + 0x223fa97acb319311, + 0xcc388229877910c0, + 0x034394632b724eaa, +]); +pub const PARAM_B3: Fr = PARAM_B.add_const(PARAM_B).add_const(PARAM_B); + +weierstrass_curve_operation!( + Fq, + Fr, + PARAM_B, + PARAM_B3, + Affine, + Projective, + GENERATOR_X, + GENERATOR_Y +); + #[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct GrumpkinDriver; From 78e675a2f04a23c71584b28fb1b75230b824efe2 Mon Sep 17 00:00:00 2001 From: ashWhiteHat Date: Fri, 24 Nov 2023 15:52:46 +0900 Subject: [PATCH 9/9] chore: fix clippy --- nova/src/lib.rs | 1 + zkstd/tests/grumpkin.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/nova/src/lib.rs b/nova/src/lib.rs index 247e999a..8513174f 100644 --- a/nova/src/lib.rs +++ b/nova/src/lib.rs @@ -1,4 +1,5 @@ #![doc = include_str!("../README.md")] +#![allow(unused_variables, dead_code)] mod circuit; mod function; diff --git a/zkstd/tests/grumpkin.rs b/zkstd/tests/grumpkin.rs index d3f4903e..9ad7c038 100644 --- a/zkstd/tests/grumpkin.rs +++ b/zkstd/tests/grumpkin.rs @@ -1,3 +1,6 @@ +#![allow(clippy::suspicious_arithmetic_impl)] +#![allow(clippy::suspicious_op_assign_impl)] + use zkstd::arithmetic::bits_256::*; use zkstd::arithmetic::weierstrass::*; use zkstd::circuit::CircuitDriver;