diff --git a/Cargo.toml b/Cargo.toml index 7e3e30b..3a3440a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" ark-crypto-primitives = { version = "0.5.0", features = [ "merkle_tree", "crh", - "r1cs", + "constraints", "sponge", ] } ark-ff = "0.5.0" @@ -29,10 +29,13 @@ ark-codes = { git = "https://github.com/dmpierre/ark-codes.git" } [patch.crates-io] -ark-crypto-primitives = { git = "https://github.com/benbencik/crypto-primitives.git", branch = "smallfp-absorb-trait" } +ark-crypto-primitives = { git = "https://github.com/benbencik/crypto-primitives.git", branch = "smallfp-absorb-clean" } ark-ff = { git = "https://github.com/arkworks-rs/algebra.git" } ark-poly = { git = "https://github.com/arkworks-rs/algebra.git" } ark-serialize = { git = "https://github.com/arkworks-rs/algebra.git" } +ark-r1cs-std = { git = "https://github.com/arkworks-rs/r1cs-std" } +ark-relations = { git = "https://github.com/arkworks-rs/snark.git" } +ark-snark = { git = "https://github.com/arkworks-rs/snark.git" } # resolve transitive pull of spongefish from efficient-sumcheck [patch."https://github.com/arkworks-rs/spongefish"] @@ -41,7 +44,7 @@ spongefish = { git = "https://github.com/z-tech/spongefish.git", branch = "small [dev-dependencies] ark-bls12-381 = "0.5.0" ark-bn254 = "0.5.0" -criterion = "0.7" +criterion = "0.8" [features] default = ["asm"] diff --git a/src/crypto/blake3_crh/fields.rs b/src/crypto/blake3_crh/fields.rs new file mode 100644 index 0000000..0cc9417 --- /dev/null +++ b/src/crypto/blake3_crh/fields.rs @@ -0,0 +1,35 @@ +use ark_ff::Field; +use ark_serialize::CanonicalSerialize; +use ark_std::rand::RngCore; +use core::borrow::Borrow; +use core::marker::PhantomData; + +use ark_crypto_primitives::{crh::CRHScheme, Error}; + +use super::GenericDigest; + +/// Blake3 leaf hash that takes field elements as input. +#[derive(Clone)] +pub struct Blake3F { + _f: PhantomData, +} + +impl CRHScheme for Blake3F { + type Input = [F]; + type Output = GenericDigest<32>; + type Parameters = (); + + fn setup(_: &mut R) -> Result { + Ok(()) + } + + fn evaluate>( + (): &Self::Parameters, + input: T, + ) -> Result { + let mut buf = Vec::new(); + input.borrow().serialize_compressed(&mut buf)?; + let output: [_; 32] = blake3::hash(&buf).into(); + Ok(output.into()) + } +} diff --git a/src/crypto/blake3_crh/mod.rs b/src/crypto/blake3_crh/mod.rs new file mode 100644 index 0000000..404033b --- /dev/null +++ b/src/crypto/blake3_crh/mod.rs @@ -0,0 +1,70 @@ +pub mod fields; + +use ark_crypto_primitives::{crh::TwoToOneCRHScheme, sponge::Absorb, Error}; +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use ark_std::rand::RngCore; +use core::borrow::Borrow; + +/// A generic fixed-size digest (copied from whir). +#[derive(Clone, Debug, Eq, PartialEq, Hash, CanonicalSerialize, CanonicalDeserialize)] +pub struct GenericDigest(pub [u8; N]); + +impl Default for GenericDigest { + fn default() -> Self { + Self([0; N]) + } +} + +impl AsRef<[u8]> for GenericDigest { + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + +impl From<[u8; N]> for GenericDigest { + fn from(value: [u8; N]) -> Self { + Self(value) + } +} + +impl Absorb for GenericDigest { + fn to_sponge_bytes(&self, dest: &mut Vec) { + dest.extend_from_slice(&self.0); + } + + fn to_sponge_field_elements(&self, dest: &mut Vec) { + dest.push(F::from_be_bytes_mod_order(&self.0)); + } +} + +/// Blake3 two-to-one hash for internal Merkle tree nodes. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Blake3; + +impl TwoToOneCRHScheme for Blake3 { + type Input = GenericDigest<32>; + type Output = GenericDigest<32>; + type Parameters = (); + + fn setup(_: &mut R) -> Result { + Ok(()) + } + + fn evaluate>( + (): &Self::Parameters, + left_input: T, + right_input: T, + ) -> Result { + let output: [_; 32] = + blake3::hash(&[left_input.borrow().0, right_input.borrow().0].concat()).into(); + Ok(output.into()) + } + + fn compress>( + parameters: &Self::Parameters, + left_input: T, + right_input: T, + ) -> Result { + Self::evaluate(parameters, left_input, right_input) + } +} diff --git a/src/crypto/merkle/blake3.rs b/src/crypto/merkle/blake3.rs index 963a7d4..e6ca88c 100644 --- a/src/crypto/merkle/blake3.rs +++ b/src/crypto/merkle/blake3.rs @@ -1,7 +1,6 @@ use super::parameters::MerkleTreeParams; -use ark_crypto_primitives::crh::blake3::fields::Blake3F; -use ark_crypto_primitives::crh::blake3::Blake3; -use ark_crypto_primitives::crh::blake3::GenericDigest; +use crate::crypto::blake3_crh::fields::Blake3F; +use crate::crypto::blake3_crh::{Blake3, GenericDigest}; use ark_crypto_primitives::{ crh::{CRHScheme, TwoToOneCRHScheme}, merkle_tree::{Config as MerkleConfig, IdentityDigestConverter}, diff --git a/src/crypto/mod.rs b/src/crypto/mod.rs index bdf9eb8..6a3489a 100644 --- a/src/crypto/mod.rs +++ b/src/crypto/mod.rs @@ -1 +1,2 @@ +pub mod blake3_crh; pub mod merkle; diff --git a/src/lib.rs b/src/lib.rs index 698dbdc..c05cc00 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -733,7 +733,6 @@ impl< )?; (rt[0] == computed_mt.root()).ok_or_err(DeciderError::MerkleRoot)?; (mt[0].root() == computed_mt.root()).ok_or_err(DeciderError::MerkleTrapDoor)?; - (mt[0].leaf_nodes == computed_mt.leaf_nodes).ok_or_err(DeciderError::MerkleRoot)?; let f_hat = DenseMultilinearExtension::from_evaluations_slice( log2(self.code.code_len()) as usize, diff --git a/src/relations/description.rs b/src/relations/description.rs index 032dfeb..16a749d 100644 --- a/src/relations/description.rs +++ b/src/relations/description.rs @@ -1,5 +1,5 @@ use ark_ff::Field; -use ark_relations::r1cs::{ConstraintMatrices, ConstraintSynthesizer, ConstraintSystem}; +use ark_relations::gr1cs::{ConstraintSynthesizer, ConstraintSystem, R1CS_PREDICATE_LABEL}; use serde::Serialize; #[derive(Serialize)] @@ -37,22 +37,26 @@ impl SerializableConstraintMatrices { .generate_constraints(constraint_system.clone()) .unwrap(); constraint_system.finalize(); - let matrices: ConstraintMatrices = constraint_system.to_matrices().unwrap(); - let serializable = SerializableConstraintMatrices::from(matrices); + + let cs = constraint_system.into_inner().unwrap(); + let all_matrices = cs.to_matrices().unwrap(); + let r1cs_matrices = all_matrices + .get(R1CS_PREDICATE_LABEL) + .expect("R1CS predicate must exist"); + + let num_constraints = cs + .get_predicate_num_constraints(R1CS_PREDICATE_LABEL) + .unwrap_or(0); + + let serializable = SerializableConstraintMatrices { + num_instance_variables: cs.num_instance_variables(), + num_witness_variables: cs.num_witness_variables(), + num_constraints, + a: Self::serialize_nested_field(r1cs_matrices[0].clone()), + b: Self::serialize_nested_field(r1cs_matrices[1].clone()), + c: Self::serialize_nested_field(r1cs_matrices[2].clone()), + }; let serialized = serde_json::to_string(&serializable).unwrap(); serialized.into_bytes() } } - -impl From> for SerializableConstraintMatrices { - fn from(m: ConstraintMatrices) -> Self { - Self { - num_instance_variables: m.num_instance_variables, - num_witness_variables: m.num_witness_variables, - num_constraints: m.num_constraints, - a: SerializableConstraintMatrices::serialize_nested_field(m.a), - b: SerializableConstraintMatrices::serialize_nested_field(m.b), - c: SerializableConstraintMatrices::serialize_nested_field(m.c), - } - } -} diff --git a/src/relations/r1cs/hashchain/mod.rs b/src/relations/r1cs/hashchain/mod.rs index 45c664c..4f34fe3 100644 --- a/src/relations/r1cs/hashchain/mod.rs +++ b/src/relations/r1cs/hashchain/mod.rs @@ -12,7 +12,7 @@ use ark_crypto_primitives::{ }; use ark_ff::PrimeField; use ark_r1cs_std::fields::fp::FpVar; -use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystem}; +use ark_relations::gr1cs::{ConstraintSynthesizer, ConstraintSystem}; pub use config::HashChainConfig; pub use instance::HashChainInstance; pub use relation::compute_hash_chain; diff --git a/src/relations/r1cs/hashchain/relation.rs b/src/relations/r1cs/hashchain/relation.rs index 6742e0a..e681158 100644 --- a/src/relations/r1cs/hashchain/relation.rs +++ b/src/relations/r1cs/hashchain/relation.rs @@ -4,7 +4,7 @@ use ark_crypto_primitives::{ }; use ark_ff::{Field, PrimeField}; use ark_r1cs_std::fields::fp::FpVar; -use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystem, ConstraintSystemRef}; +use ark_relations::gr1cs::{ConstraintSynthesizer, ConstraintSystem, ConstraintSystemRef}; use ark_serialize::CanonicalSerialize; use ark_std::marker::PhantomData; @@ -94,14 +94,22 @@ where .unwrap(); constraint_system.finalize(); - let cs = constraint_system.into_inner().unwrap(); + // Extract assignments via the ref (borrow the inner CS) + let x = constraint_system + .borrow() + .map(|cs| cs.instance_assignment().unwrap().to_vec()) + .unwrap(); + let w = constraint_system + .borrow() + .map(|cs| cs.witness_assignment().unwrap().to_vec()) + .unwrap(); Self { - constraint_system: ConstraintSystemRef::new(cs.clone()), + constraint_system, config: hash_config, instance, witness, - x: cs.instance_assignment, - w: cs.witness_assignment, + x, + w, _crhs_scheme: PhantomData, _crhs_scheme_gadget: PhantomData, } diff --git a/src/relations/r1cs/hashchain/synthesizer.rs b/src/relations/r1cs/hashchain/synthesizer.rs index beb4a90..511b1ff 100644 --- a/src/relations/r1cs/hashchain/synthesizer.rs +++ b/src/relations/r1cs/hashchain/synthesizer.rs @@ -1,7 +1,7 @@ use ark_crypto_primitives::crh::{CRHScheme, CRHSchemeGadget}; use ark_ff::{Field, PrimeField}; use ark_r1cs_std::{alloc::AllocVar, eq::EqGadget, fields::fp::FpVar}; -use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError}; +use ark_relations::gr1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError}; use ark_std::marker::PhantomData; use crate::relations::r1cs::hashchain::{HashChainInstance, HashChainWitness}; diff --git a/src/relations/r1cs/mod.rs b/src/relations/r1cs/mod.rs index 0232a7e..6377cfe 100644 --- a/src/relations/r1cs/mod.rs +++ b/src/relations/r1cs/mod.rs @@ -1,7 +1,7 @@ pub mod hashchain; use ark_ff::Field; -use ark_relations::r1cs::ConstraintSystemRef; +use ark_relations::gr1cs::ConstraintSystemRef; use efficient_sumcheck::{hypercube::Hypercube, order_strategy::AscendingOrder}; use crate::error::WARPError; @@ -27,21 +27,31 @@ impl TryFrom> for R1CS { type Error = WARPError; fn try_from(cs: ConstraintSystemRef) -> Result { - let matrices = cs.to_matrices().unwrap(); + use ark_relations::gr1cs::R1CS_PREDICATE_LABEL; + + let inner = cs.into_inner().unwrap(); + let all_matrices = inner.to_matrices().unwrap(); + let r1cs_matrices = all_matrices + .get(R1CS_PREDICATE_LABEL) + .expect("R1CS predicate must exist"); + + let num_constraints = inner + .get_predicate_num_constraints(R1CS_PREDICATE_LABEL) + .unwrap_or(0); // number of constraints should be to be power of 2 - let m = matrices.num_constraints.next_power_of_two(); - let n = matrices.num_instance_variables + matrices.num_witness_variables; - let k = matrices.num_witness_variables; + let m = num_constraints.next_power_of_two(); + let n = inner.num_instance_variables() + inner.num_witness_variables(); + let k = inner.num_witness_variables(); // both `unwrap()` calls below are safe since warp/lib.rs forbids compiling on platforms // with 16-bits pointers width let log_m = m.ilog2().try_into().unwrap(); let log_n = n.ilog2().try_into().unwrap(); - let mut a = matrices.a.into_iter(); - let mut b = matrices.b.into_iter(); - let mut c = matrices.c.into_iter(); + let mut a = r1cs_matrices[0].clone().into_iter(); + let mut b = r1cs_matrices[1].clone().into_iter(); + let mut c = r1cs_matrices[2].clone().into_iter(); let mut p = vec![]; for _ in 0..m { // when there are no constraints left, we store an empty one diff --git a/src/serialize.rs b/src/serialize.rs index e03ceff..5d5bb0d 100644 --- a/src/serialize.rs +++ b/src/serialize.rs @@ -29,9 +29,9 @@ pub struct AccWitnessSerializer< F: Field + PrimeField, MT: Config + From<[u8; 32]>>, > { - pub td: Vec, pub f: Vec, pub w: Vec, + _mt: std::marker::PhantomData, } impl + From<[u8; 32]>>> @@ -41,13 +41,10 @@ impl + Fr assert_eq!(acc_witness.0.len(), 1); assert_eq!(acc_witness.1.len(), 1); assert_eq!(acc_witness.2.len(), 1); - let f = acc_witness.1[0].clone(); - assert_eq!(f.len(), acc_witness.0[0].leaf_nodes.len()); - let w = acc_witness.2[0].clone(); Self { - td: acc_witness.0[0].clone().leaf_nodes, - f, - w, + f: acc_witness.1[0].clone(), + w: acc_witness.2[0].clone(), + _mt: std::marker::PhantomData, } } }