diff --git a/Cargo.lock b/Cargo.lock index f47e6dcb5..92c711306 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -518,7 +518,7 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "bellman_ce" version = "0.3.2" -source = "git+https://github.com/matter-labs/bellman#5520aa2274afe73d281373c92b007a2ecdebfbea" +source = "git+https://github.com/matter-labs/bellman.git?rev=5520aa2#5520aa2274afe73d281373c92b007a2ecdebfbea" dependencies = [ "arrayvec 0.7.4", "bit-vec", @@ -627,7 +627,7 @@ dependencies = [ [[package]] name = "blake2s_const" version = "0.6.0" -source = "git+https://github.com/matter-labs/bellman#5520aa2274afe73d281373c92b007a2ecdebfbea" +source = "git+https://github.com/matter-labs/bellman.git?rev=5520aa2#5520aa2274afe73d281373c92b007a2ecdebfbea" dependencies = [ "arrayref", "arrayvec 0.5.2", @@ -4440,6 +4440,7 @@ dependencies = [ "memory-stats", "nova-snark", "pasta_curves", + "rand 0.4.6", "reqwest", "serde", "serde_json", diff --git a/crates/snark/Cargo.toml b/crates/snark/Cargo.toml index 9d2cfab67..9138b3078 100644 --- a/crates/snark/Cargo.toml +++ b/crates/snark/Cargo.toml @@ -26,7 +26,8 @@ log = { version = "0.4", features = ["std"] } pasta_curves = "0.5" # for load r1cs -bellman_ce = { git = "https://github.com/matter-labs/bellman", version = "0.3.2" } +bellman_ce = { version = "0.3.2", features = ["plonk"], git = "https://github.com/matter-labs/bellman.git", rev = "5520aa2" } +rand = "0.4.6" bellpepper-core = "0.4.0" byteorder = "1.4.3" crypto-bigint = { version = "0.5.2", features = ["serde"] } diff --git a/crates/snark/src/circuit/bellman.rs b/crates/snark/src/circuit/bellman.rs index 105ea6ef8..2d0f3ce8a 100644 --- a/crates/snark/src/circuit/bellman.rs +++ b/crates/snark/src/circuit/bellman.rs @@ -1,6 +1,7 @@ //! implement bellman proof system for circuit, this is useful for plonk and growth16 use super::Circuit; +use super::TrivialCircuit; use crate::prelude::bellman; use crate::prelude::bellman::pairing::Engine; use crate::prelude::bellman::ConstraintSystem; @@ -54,3 +55,13 @@ where E::Fr: ff::PrimeField Ok(()) } } + + +impl bellman::Circuit for TrivialCircuit +where E::Fr: ff::PrimeField +{ + //noinspection RsBorrowChecker + fn synthesize>(self, _cs: &mut CS) -> Result<(), SynthesisError> { + Ok(()) + } +} diff --git a/crates/snark/src/circuit/bellpepper.rs b/crates/snark/src/circuit/bellpepper.rs index 6b9b67532..edf18c16b 100644 --- a/crates/snark/src/circuit/bellpepper.rs +++ b/crates/snark/src/circuit/bellpepper.rs @@ -1,6 +1,7 @@ //! implement bellpepper proof system for circuit use super::Circuit; +use super::TrivialCircuit; use crate::prelude::bellpepper; use crate::prelude::bellpepper::num::AllocatedNum; use crate::prelude::bellpepper::ConstraintSystem; @@ -53,3 +54,9 @@ impl bellpepper::Circuit for Circuit { Ok(()) } } + +impl bellpepper::Circuit for TrivialCircuit { + fn synthesize>(self, _cs: &mut CS) -> Result<(), SynthesisError> { + Ok(()) + } +} diff --git a/crates/snark/src/circuit/mod.rs b/crates/snark/src/circuit/mod.rs index d10a55c24..3ee1792ee 100644 --- a/crates/snark/src/circuit/mod.rs +++ b/crates/snark/src/circuit/mod.rs @@ -25,7 +25,7 @@ pub mod bellpepper; /// Input of witness #[derive(Serialize, Deserialize, Clone)] -pub struct Input { +pub struct Input { /// inner input pub input: Vec<(String, Vec)>, } @@ -291,3 +291,25 @@ impl StepCircuit for Circuit { Ok(z_out) } } + + +/// A trivial step circuit that simply returns the input +/// from +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct TrivialCircuit { + _p: core::marker::PhantomData, +} + +impl StepCircuit for TrivialCircuit { + fn arity(&self) -> usize { + 1 + } + + fn synthesize>( + &self, + _cs: &mut CS, + z: &[AllocatedNum], + ) -> core::result::Result>, SynthesisError> { + Ok(z.to_vec()) + } +} diff --git a/crates/snark/src/ff.rs b/crates/snark/src/ff.rs new file mode 100644 index 000000000..39a715c78 --- /dev/null +++ b/crates/snark/src/ff.rs @@ -0,0 +1,303 @@ +//! PrimeField implementation of Rings Snark +//! =============== +use crate::prelude::bellman; +use crypto_bigint::rand_core::RngCore; +use crypto_bigint::rand_core; +use serde::de::Deserialize; +use serde::Serialize; +use std::hash::Hash; +use std::hash::Hasher; +use std::marker::PhantomData; + +/// We need this struct to make rand-0.4 and rand-0.8 compatible. +/// RngMutRef holding a mut ref of Rng +pub struct RngMutRef<'a, T: rand::Rng> { + inner: &'a mut T +} + +impl <'a, T: rand::Rng> From<&'a mut T> for RngMutRef<'a, T> { + fn from(inner: &'a mut T) -> Self { + Self { + inner + } + } +} + +impl RngCore for RngMutRef<'_, T> { + fn next_u32(&mut self) -> u32 { + self.inner.next_u32() + } + fn next_u64(&mut self) -> u64 { + self.inner.next_u64() + } + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.inner.fill_bytes(dest) + } + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { + Ok(self.inner.fill_bytes(dest)) + } +} + +/// A wrapper structure of [ff::PrimeField] +#[derive(Debug, Clone, Copy, Default, Eq, PartialEq)] +pub struct PrimeField { + inner: T, + _phantom: PhantomData + +} + +/// bellman::PrimeField::Repr Sized + Copy + Clone + Eq + Ord + Send + Sync + Default + Debug + Display + 'static + Rand + AsRef<[u64]> + AsMut<[u64]> + From + Hash + Serialize + DeserializeOwned +/// ff::PrimeField::Repr Copy + Default + Send + Sync + 'static + AsRef<[u8]> + AsMut<[u8]> +#[derive(Clone, Debug)] +pub struct PrimeFieldRepr { + _phantom: PhantomData, + data: Vec, +} + +impl From> for PrimeFieldRepr +where + F: ff::PrimeField, +{ + fn from(field: PrimeField) -> Self { + let repr = field.inner.to_repr(); + let data: &[u8] = repr.as_ref(); + let data = bytes_to_u64_vec_with_padding(data); + Self { + _phantom: PhantomData, + data: data + } + } +} + + +impl std::fmt::Display for PrimeFieldRepr +where + F: ff::PrimeField +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.data) + } +} + +impl From for PrimeFieldRepr +where + F: ff::PrimeField +{ + fn from(value: u64) -> Self { + let value = value as u128; + let field: PrimeField = F::from_u128(value).into(); + field.into() + } +} + +impl AsRef<[u64]> for PrimeFieldRepr +where + F: ff::PrimeField +{ + fn as_ref(&self) -> &[u64] { + &self.data + } +} + +impl AsMut<[u64]> for PrimeFieldRepr +where + F: ff::PrimeField +{ + fn as_mut(&mut self) -> &mut [u64] { + &mut self.data + } +} + + +impl From for PrimeField { + fn from(f: T) -> PrimeField { + Self { + inner: f, + _phantom: PhantomData + } + } +} + +impl Hash for PrimeField { + fn hash(&self, state: &mut H) { + let repr = self.inner.to_repr(); + repr.as_ref().hash(state); + } +} + +impl Serialize for PrimeField { + fn serialize(&self, serializer: S) -> Result + where S: serde::Serializer { + let data: Vec = self.inner.to_repr().as_ref().to_vec(); + data.serialize(serializer) + } +} + +impl<'de, T> Deserialize<'de> for PrimeField +where + T: ff::PrimeField, +{ + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let data: Vec = Vec::deserialize(deserializer)?; + let s = std::str::from_utf8(&data).expect("Found invalid UTF-8"); + if let Some(ret) = T::from_str_vartime(s).map(|inner| inner.into()) + { + Ok(ret) + } else { + Err(serde::de::Error::custom("Failed to parse str repr")) + } + } +} + +impl std::fmt::Display for PrimeField { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{:?}", self.inner) + } +} + +impl AsRef> for PrimeField { + fn as_ref(&self) -> &Self { + self + } +} + +impl AsRef for PrimeField { + fn as_ref(&self) -> &T { + &self.inner + } +} + +impl rand::Rand for PrimeField { + fn rand(rng: &mut R) -> Self { + let rng: RngMutRef = rng.into(); + T::random(rng).into() + } +} + +impl bellman::Field for PrimeField { + fn zero() -> Self { + T::ZERO.into() + } + fn one() -> Self { + T::ONE.into() + } + fn is_zero(&self) -> bool { + self.inner.is_zero().into() + } + fn square(&mut self) { + self.inner = self.inner.square(); + } + fn double(&mut self) { + self.inner = self.inner.double(); + } + fn negate(&mut self) { + self.inner = self.inner.neg(); + } + fn add_assign(&mut self, other: &Self) { + self.inner.add_assign(other.inner) + } + fn sub_assign(&mut self, other: &Self) { + self.inner.sub_assign(other.inner) + + } + fn mul_assign(&mut self, other: &Self) { + self.inner.mul_assign(other.inner) + + } + fn inverse(&self) -> Option { + let ret: Option = self.inner.invert().into(); + ret.map(|r| r.into()) + } + + // todo: just power? + fn frobenius_map(&mut self, power: usize) { + if power == 0 { + *self = Self::one(); + return; + } + + let mut result = Self::one(); + let mut base = self.clone(); + let mut exp = power; + + while exp > 0 { + if exp % 2 == 1 { + result.mul_assign(&base); + } + base.square(); + exp /= 2; + } + + *self = result; + } + +} + + +// impl bellman::PrimeField for PrimeField +// { +// type Repr = T::Repr; +// const NUM_BITS: u32 = T::NUM_BITS; +// const CAPACITY: u32 = T::CAPACITY; +// const S: u32 = T::S; + +// fn from_repr(repr: Self::Repr) -> Result { +// T::from_repr(repr) +// } +// fn from_raw_repr(repr: Self::Repr) -> Result { +// T::from_repr(repr) +// } +// fn into_repr(&self) -> Self::Repr { +// self.inner.to_repr() +// } +// fn into_raw_repr(&self) -> Self::Repr { +// self.inner.to_repr() +// } +// fn char() -> Self::Repr { +// T::Repr +// } +// fn multiplicative_generator() -> Self { +// Self +// } +// fn root_of_unity() -> Self { +// Self +// } + +// } + + +pub(crate) fn bytes_to_u64_vec_with_padding(bytes: &[u8]) -> Vec { + // Calculate the number of bytes needed to pad the array to a multiple of 8 + let padding = if bytes.len() % 8 == 0 { 0 } else { 8 - (bytes.len() % 8) }; + + // Create a new Vec and extend it with the original bytes plus necessary padding + let mut padded_bytes = Vec::with_capacity(bytes.len() + padding); + padded_bytes.extend_from_slice(bytes); + + // Pad with zeros to make the length a multiple of 8 + padded_bytes.resize(bytes.len() + padding, 0); + + // Convert the padded byte slice into a Vec + padded_bytes + .chunks(8) + .map(|chunk| { + let mut arr = [0u8; 8]; + arr.copy_from_slice(chunk); + u64::from_le_bytes(arr) // Or use from_be_bytes, depending on your byte order requirements + }) + .collect() +} + + +#[cfg(test)] +pub mod tests { + use super::*; + + fn test_bytes_to_u64() { + let bytes = &[1, 2, 3, 4, 5]; // Length is not a multiple of 8 + let u64_vec = bytes_to_u64_vec_with_padding(bytes); + } +} diff --git a/crates/snark/src/lib.rs b/crates/snark/src/lib.rs index 3864bb574..01b8da326 100644 --- a/crates/snark/src/lib.rs +++ b/crates/snark/src/lib.rs @@ -12,3 +12,4 @@ pub mod snark; #[cfg(test)] mod tests; pub mod witness; +pub mod ff; diff --git a/crates/snark/src/snark/engine.rs b/crates/snark/src/snark/engine.rs new file mode 100644 index 000000000..7fa36f780 --- /dev/null +++ b/crates/snark/src/snark/engine.rs @@ -0,0 +1,46 @@ +//! Engines of Rings Snark +//! ============ + +use crate::prelude::nova::provider::Bn256Engine; +//use crate::prelude::nova::provider::GrumpkinEngine; +use nova_snark::traits::Engine as NovaEngine; +use crate::prelude::bellman::ScalarEngine; +use crate::prelude::bellman::pairing::bn256::Bn256; +use crate::prelude::nova::traits::commitment::CommitmentEngineTrait; +use crate::prelude::nova::traits::TranscriptEngineTrait; + +/// A wrapper of Nova's Engine +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +pub struct Engine { + inner: T +} + +impl AsRef> for Engine { + fn as_ref(&self) -> &Self { + self + } +} + +impl AsRef for Engine { + fn as_ref(&self) -> &T { + &self.inner + } +} + +impl ScalarEngine for Engine { + type Fr = ::Fr; +} + +impl NovaEngine for Engine +where + ::CE: CommitmentEngineTrait>, + ::TE: TranscriptEngineTrait> +{ + type Base = ::Base; + type Scalar = ::Scalar; + type GE = ::GE; + type RO = ::RO; + type ROCircuit = ::ROCircuit; + type TE = ::TE; + type CE = ::CE; +} diff --git a/crates/snark/src/snark/impls.rs b/crates/snark/src/snark/impls.rs index afe190079..79a0aad1c 100644 --- a/crates/snark/src/snark/impls.rs +++ b/crates/snark/src/snark/impls.rs @@ -8,7 +8,7 @@ use super::VerifierKey; use super::SNARK; use crate::circuit::Circuit; use crate::prelude::nova; -use crate::prelude::nova::traits::circuit::TrivialCircuit; +use crate::circuit::TrivialCircuit; use crate::prelude::nova::traits::snark::RelaxedR1CSSNARKTrait; use crate::prelude::nova::traits::Engine; use crate::prelude::nova::RecursiveSNARK; diff --git a/crates/snark/src/snark/mod.rs b/crates/snark/src/snark/mod.rs index 64a55fddb..c74dc69e4 100644 --- a/crates/snark/src/snark/mod.rs +++ b/crates/snark/src/snark/mod.rs @@ -14,11 +14,14 @@ use utils::serialize_forward; use crate::circuit::Circuit; use crate::error::Result; use crate::prelude::nova; -use crate::prelude::nova::traits::circuit::TrivialCircuit; +use crate::circuit::TrivialCircuit; use crate::prelude::nova::traits::snark::RelaxedR1CSSNARKTrait; use crate::prelude::nova::traits::Engine; use crate::prelude::nova::RecursiveSNARK; +//pub mod plonk; +pub mod engine; + /// Rings Snark implementation, a wrapper of nova's recursion snark and compressed snark #[derive(Serialize, Deserialize, Clone, Debug)] pub struct SNARK diff --git a/crates/snark/src/tests/native/test_snark.rs b/crates/snark/src/tests/native/test_snark.rs index 170edae61..25a632e64 100644 --- a/crates/snark/src/tests/native/test_snark.rs +++ b/crates/snark/src/tests/native/test_snark.rs @@ -6,6 +6,7 @@ use crate::error::Result; use crate::prelude::nova::provider::ipa_pc::EvaluationEngine; use crate::prelude::nova::provider::PallasEngine; use crate::prelude::nova::provider::VestaEngine; +use crate::prelude::nova::provider::Bn256Engine; use crate::prelude::nova::spartan::snark::RelaxedR1CSSNARK; use crate::prelude::nova::traits::Engine; use crate::r1cs;