From a135971613779905fc2775fcfea2870148fb4543 Mon Sep 17 00:00:00 2001 From: Hossein Moghaddas Date: Sun, 7 Jan 2024 00:39:31 +0100 Subject: [PATCH] Fix according to breaking changes in `r1cs-std` (#126) Co-authored-by: Pratyush Mishra --- Cargo.toml | 2 +- src/commitment/blake2s/constraints.rs | 2 +- src/crh/bowe_hopwood/constraints.rs | 6 +- src/crh/injective_map/constraints.rs | 4 +- src/crh/pedersen/constraints.rs | 4 +- src/crh/sha256/constraints.rs | 87 ++++++++++-------- src/crh/sha256/mod.rs | 3 - src/crh/sha256/r1cs_utils.rs | 122 -------------------------- src/encryption/elgamal/constraints.rs | 2 +- src/merkle_tree/constraints.rs | 106 ++++++++++------------ src/merkle_tree/tests/constraints.rs | 7 +- src/prf/blake2s/constraints.rs | 68 ++++++-------- src/signature/schnorr/constraints.rs | 4 +- src/snark/constraints.rs | 61 +++++++------ src/sponge/constraints/absorb.rs | 14 +-- src/sponge/constraints/mod.rs | 60 ++++++------- src/sponge/mod.rs | 8 +- src/sponge/poseidon/constraints.rs | 6 +- 18 files changed, 214 insertions(+), 352 deletions(-) delete mode 100644 src/crh/sha256/r1cs_utils.rs diff --git a/Cargo.toml b/Cargo.toml index aa001515..5135b10b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -115,7 +115,7 @@ harness = false required-features = [ "merkle_tree" ] [patch.crates-io] -ark-r1cs-std = { git = "https://github.com/arkworks-rs/r1cs-std/" } +ark-r1cs-std = { git = "https://github.com/arkworks-rs/r1cs-std/", branch = "add-convert-traits-to-prelude" } ark-ff = { git = "https://github.com/arkworks-rs/algebra/" } ark-ec = { git = "https://github.com/arkworks-rs/algebra/" } ark-poly = { git = "https://github.com/arkworks-rs/algebra/" } diff --git a/src/commitment/blake2s/constraints.rs b/src/commitment/blake2s/constraints.rs index 4659faae..f38b7378 100644 --- a/src/commitment/blake2s/constraints.rs +++ b/src/commitment/blake2s/constraints.rs @@ -35,7 +35,7 @@ impl CommitmentGadget for CommGadget { } let mut result = Vec::new(); for int in evaluate_blake2s(&input_bits)?.into_iter() { - let chunk = int.to_bytes()?; + let chunk = int.to_bytes_le()?; result.extend_from_slice(&chunk); } Ok(OutputVar(result)) diff --git a/src/crh/bowe_hopwood/constraints.rs b/src/crh/bowe_hopwood/constraints.rs index ca2ae0ff..c58baeba 100644 --- a/src/crh/bowe_hopwood/constraints.rs +++ b/src/crh/bowe_hopwood/constraints.rs @@ -17,7 +17,7 @@ use ark_r1cs_std::{ use ark_relations::r1cs::{Namespace, SynthesisError}; use crate::crh::bowe_hopwood::{TwoToOneCRH, CRH}; -use ark_r1cs_std::bits::boolean::Boolean; +use ark_r1cs_std::boolean::Boolean; type ConstraintF

= <

::BaseField as Field>::BasePrimeField; @@ -140,8 +140,8 @@ where left_input: &Self::OutputVar, right_input: &Self::OutputVar, ) -> Result { - let left_input_bytes = left_input.to_bytes()?; - let right_input_bytes = right_input.to_bytes()?; + let left_input_bytes = left_input.to_bytes_le()?; + let right_input_bytes = right_input.to_bytes_le()?; Self::evaluate(parameters, &left_input_bytes, &right_input_bytes) } } diff --git a/src/crh/injective_map/constraints.rs b/src/crh/injective_map/constraints.rs index ef312709..8e9cd703 100644 --- a/src/crh/injective_map/constraints.rs +++ b/src/crh/injective_map/constraints.rs @@ -151,8 +151,8 @@ where left_input: &Self::OutputVar, right_input: &Self::OutputVar, ) -> Result { - let left_input_bytes = left_input.to_non_unique_bytes()?; - let right_input_bytes = right_input.to_non_unique_bytes()?; + let left_input_bytes = left_input.to_non_unique_bytes_le()?; + let right_input_bytes = right_input.to_non_unique_bytes_le()?; >::evaluate( parameters, &left_input_bytes, diff --git a/src/crh/pedersen/constraints.rs b/src/crh/pedersen/constraints.rs index 1b32a111..fdf2340a 100644 --- a/src/crh/pedersen/constraints.rs +++ b/src/crh/pedersen/constraints.rs @@ -127,8 +127,8 @@ where right_input: &Self::OutputVar, ) -> Result { // convert output to bytes - let left_input = left_input.to_bytes()?; - let right_input = right_input.to_bytes()?; + let left_input = left_input.to_bytes_le()?; + let right_input = right_input.to_bytes_le()?; Self::evaluate(parameters, &left_input, &right_input) } } diff --git a/src/crh/sha256/constraints.rs b/src/crh/sha256/constraints.rs index 60f5ee09..c7080809 100644 --- a/src/crh/sha256/constraints.rs +++ b/src/crh/sha256/constraints.rs @@ -3,19 +3,19 @@ // See LICENSE-MIT in the root directory for a copy of the license // Thank you! -use crate::crh::{ - sha256::{r1cs_utils::UInt32Ext, Sha256}, - CRHSchemeGadget, TwoToOneCRHSchemeGadget, -}; +use crate::crh::{sha256::Sha256, CRHSchemeGadget, TwoToOneCRHSchemeGadget}; use core::{borrow::Borrow, iter, marker::PhantomData}; use ark_ff::PrimeField; use ark_r1cs_std::{ alloc::{AllocVar, AllocationMode}, - bits::{boolean::Boolean, uint32::UInt32, uint8::UInt8, ToBytesGadget}, + boolean::Boolean, + convert::ToBytesGadget, eq::EqGadget, select::CondSelectGadget, + uint32::UInt32, + uint8::UInt8, R1CSVar, }; use ark_relations::r1cs::{ConstraintSystemRef, Namespace, SynthesisError}; @@ -75,61 +75,66 @@ impl Sha256Gadget { for i in 16..64 { let s0 = { - let x1 = w[i - 15].rotr(7); - let x2 = w[i - 15].rotr(18); - let x3 = w[i - 15].shr(3); - x1.xor(&x2)?.xor(&x3)? + let x1 = w[i - 15].rotate_right(7); + let x2 = w[i - 15].rotate_right(18); + let x3 = &w[i - 15] >> 3u8; + x1 ^ &x2 ^ &x3 }; let s1 = { - let x1 = w[i - 2].rotr(17); - let x2 = w[i - 2].rotr(19); - let x3 = w[i - 2].shr(10); - x1.xor(&x2)?.xor(&x3)? + let x1 = w[i - 2].rotate_right(17); + let x2 = w[i - 2].rotate_right(19); + let x3 = &w[i - 2] >> 10u8; + x1 ^ &x2 ^ &x3 }; - w[i] = UInt32::addmany(&[w[i - 16].clone(), s0, w[i - 7].clone(), s1])?; + w[i] = UInt32::wrapping_add_many(&[w[i - 16].clone(), s0, w[i - 7].clone(), s1])?; } let mut h = state.to_vec(); for i in 0..64 { let ch = { - let x1 = h[4].bitand(&h[5])?; - let x2 = h[4].not().bitand(&h[6])?; - x1.xor(&x2)? + let x1 = &h[4] & &h[5]; + let x2 = (!&h[4]) & &h[6]; + x1 ^ &x2 }; let ma = { - let x1 = h[0].bitand(&h[1])?; - let x2 = h[0].bitand(&h[2])?; - let x3 = h[1].bitand(&h[2])?; - x1.xor(&x2)?.xor(&x3)? + let x1 = &h[0] & &h[1]; + let x2 = &h[0] & &h[2]; + let x3 = &h[1] & &h[2]; + x1 ^ &x2 ^ &x3 }; let s0 = { - let x1 = h[0].rotr(2); - let x2 = h[0].rotr(13); - let x3 = h[0].rotr(22); - x1.xor(&x2)?.xor(&x3)? + let x1 = h[0].rotate_right(2); + let x2 = h[0].rotate_right(13); + let x3 = h[0].rotate_right(22); + x1 ^ &x2 ^ &x3 }; let s1 = { - let x1 = h[4].rotr(6); - let x2 = h[4].rotr(11); - let x3 = h[4].rotr(25); - x1.xor(&x2)?.xor(&x3)? + let x1 = h[4].rotate_right(6); + let x2 = h[4].rotate_right(11); + let x3 = h[4].rotate_right(25); + x1 ^ &x2 ^ &x3 }; - let t0 = - UInt32::addmany(&[h[7].clone(), s1, ch, UInt32::constant(K[i]), w[i].clone()])?; - let t1 = UInt32::addmany(&[s0, ma])?; + let t0 = UInt32::wrapping_add_many(&[ + h[7].clone(), + s1, + ch, + UInt32::constant(K[i]), + w[i].clone(), + ])?; + let t1 = s0.wrapping_add(&ma); h[7] = h[6].clone(); h[6] = h[5].clone(); h[5] = h[4].clone(); - h[4] = UInt32::addmany(&[h[3].clone(), t0.clone()])?; + h[4] = h[3].wrapping_add(&t0); h[3] = h[2].clone(); h[2] = h[1].clone(); h[1] = h[0].clone(); - h[0] = UInt32::addmany(&[t0, t1])?; + h[0] = t0.wrapping_add(&t1); } for (s, hi) in state.iter_mut().zip(h.iter()) { - *s = UInt32::addmany(&[s.clone(), hi.clone()])?; + *s = s.wrapping_add(hi); } Ok(()) @@ -192,7 +197,11 @@ impl Sha256Gadget { self.update(&pending[..offset + 8])?; // Collect the state into big-endian bytes - let bytes: Vec<_> = self.state.iter().flat_map(UInt32::to_bytes_be).collect(); + let bytes = Vec::from_iter( + self.state + .iter() + .flat_map(|i| UInt32::to_bytes_be(i).unwrap()), + ); Ok(DigestVar(bytes)) } @@ -221,7 +230,7 @@ where } impl ToBytesGadget for DigestVar { - fn to_bytes(&self) -> Result>, SynthesisError> { + fn to_bytes_le(&self) -> Result>, SynthesisError> { Ok(self.0.clone()) } } @@ -360,8 +369,8 @@ where right_input: &Self::OutputVar, ) -> Result { // Convert output to bytes - let left_input = left_input.to_bytes()?; - let right_input = right_input.to_bytes()?; + let left_input = left_input.to_bytes_le()?; + let right_input = right_input.to_bytes_le()?; >::evaluate( parameters, &left_input, diff --git a/src/crh/sha256/mod.rs b/src/crh/sha256/mod.rs index 5f89482e..6010be32 100644 --- a/src/crh/sha256/mod.rs +++ b/src/crh/sha256/mod.rs @@ -6,9 +6,6 @@ use ark_std::rand::Rng; // Re-export the RustCrypto Sha256 type and its associated traits pub use sha2::{digest, Sha256}; -#[cfg(feature = "r1cs")] -mod r1cs_utils; - #[cfg(feature = "r1cs")] pub mod constraints; diff --git a/src/crh/sha256/r1cs_utils.rs b/src/crh/sha256/r1cs_utils.rs deleted file mode 100644 index 88866313..00000000 --- a/src/crh/sha256/r1cs_utils.rs +++ /dev/null @@ -1,122 +0,0 @@ -use crate::Vec; - -use ark_ff::PrimeField; -use ark_r1cs_std::bits::{boolean::Boolean, uint32::UInt32, uint8::UInt8, ToBitsGadget}; -use ark_relations::r1cs::SynthesisError; -use core::iter; - -/// Extra traits not automatically implemented by UInt32 -pub(crate) trait UInt32Ext: Sized { - /// Right shift - fn shr(&self, by: usize) -> Self; - - /// Bitwise NOT - fn not(&self) -> Self; - - /// Bitwise AND - fn bitand(&self, rhs: &Self) -> Result; - - /// Converts from big-endian bytes - fn from_bytes_be(bytes: &[UInt8]) -> Result; - - /// Converts to big-endian bytes - fn to_bytes_be(&self) -> Vec>; -} - -impl UInt32Ext for UInt32 { - fn shr(&self, by: usize) -> Self { - assert!(by < 32); - - let zeros = iter::repeat(Boolean::constant(false)).take(by); - let new_bits: Vec<_> = self - .to_bits_le() - .into_iter() - .skip(by) - .chain(zeros) - .collect(); - UInt32::from_bits_le(&new_bits) - } - - fn not(&self) -> Self { - let new_bits: Vec<_> = self.to_bits_le().iter().map(Boolean::not).collect(); - UInt32::from_bits_le(&new_bits) - } - - fn bitand(&self, rhs: &Self) -> Result { - let new_bits: Result, SynthesisError> = self - .to_bits_le() - .into_iter() - .zip(rhs.to_bits_le().into_iter()) - .map(|(a, b)| a.and(&b)) - .collect(); - Ok(UInt32::from_bits_le(&new_bits?)) - } - - fn from_bytes_be(bytes: &[UInt8]) -> Result { - assert_eq!(bytes.len(), 4); - - let mut bits: Vec> = Vec::new(); - for byte in bytes.iter().rev() { - let b: Vec> = byte.to_bits_le()?; - bits.extend(b); - } - Ok(UInt32::from_bits_le(&bits)) - } - - fn to_bytes_be(&self) -> Vec> { - self.to_bits_le() - .chunks(8) - .rev() - .map(UInt8::from_bits_le) - .collect() - } -} - -#[cfg(test)] -mod test { - use super::*; - - use ark_bls12_377::Fr; - use ark_r1cs_std::{bits::uint32::UInt32, R1CSVar}; - use ark_std::rand::Rng; - - const NUM_TESTS: usize = 10_000; - - #[test] - fn test_shr() { - let mut rng = ark_std::test_rng(); - for _ in 0..NUM_TESTS { - let x = rng.gen::(); - let by = rng.gen::() % 32; - assert_eq!(UInt32::::constant(x).shr(by).value().unwrap(), x >> by); - } - } - - #[test] - fn test_bitand() { - let mut rng = ark_std::test_rng(); - for _ in 0..NUM_TESTS { - let x = rng.gen::(); - let y = rng.gen::(); - assert_eq!( - UInt32::::constant(x) - .bitand(&UInt32::constant(y)) - .unwrap() - .value() - .unwrap(), - x & y - ); - } - } - - #[test] - fn test_to_from_bytes_be() { - let mut rng = ark_std::test_rng(); - for _ in 0..NUM_TESTS { - let x = UInt32::::constant(rng.gen::()); - let bytes = x.to_bytes_be(); - let y = UInt32::from_bytes_be(&bytes).unwrap(); - assert_eq!(x.value(), y.value()); - } - } -} diff --git a/src/encryption/elgamal/constraints.rs b/src/encryption/elgamal/constraints.rs index 2846d307..7527352a 100644 --- a/src/encryption/elgamal/constraints.rs +++ b/src/encryption/elgamal/constraints.rs @@ -176,7 +176,7 @@ where { #[inline] fn is_eq(&self, other: &Self) -> Result>, SynthesisError> { - self.c1.is_eq(&other.c1)?.and(&self.c2.is_eq(&other.c2)?) + Ok(self.c1.is_eq(&other.c1)? & &self.c2.is_eq(&other.c2)?) } } diff --git a/src/merkle_tree/constraints.rs b/src/merkle_tree/constraints.rs index d5917b07..e243079c 100644 --- a/src/merkle_tree/constraints.rs +++ b/src/merkle_tree/constraints.rs @@ -1,12 +1,8 @@ use crate::crh::TwoToOneCRHSchemeGadget; use crate::merkle_tree::{Config, IdentityDigestConverter}; use crate::{crh::CRHSchemeGadget, merkle_tree::Path}; -use ark_ff::Field; -use ark_r1cs_std::alloc::AllocVar; -use ark_r1cs_std::boolean::Boolean; -#[allow(unused)] +use ark_ff::PrimeField; use ark_r1cs_std::prelude::*; -use ark_r1cs_std::ToBytesGadget; use ark_relations::r1cs::{Namespace, SynthesisError}; use ark_std::borrow::Borrow; use ark_std::fmt::Debug; @@ -25,91 +21,85 @@ impl DigestVarConverter for IdentityDigestConverter { } } -pub struct BytesVarDigestConverter, ConstraintF: Field> { +pub struct BytesVarDigestConverter, F: PrimeField> { _prev_layer_digest: T, - _constraint_field: ConstraintF, + _constraint_field: F, } -impl, ConstraintF: Field> DigestVarConverter]> - for BytesVarDigestConverter +impl, F: PrimeField> DigestVarConverter]> + for BytesVarDigestConverter { - type TargetType = Vec>; + type TargetType = Vec>; fn convert(from: T) -> Result { - from.to_non_unique_bytes() + from.to_non_unique_bytes_le() } } -pub trait ConfigGadget { +pub trait ConfigGadget { type Leaf: Debug + ?Sized; - type LeafDigest: AllocVar - + EqGadget - + ToBytesGadget - + CondSelectGadget - + R1CSVar + type LeafDigest: AllocVar + + EqGadget + + ToBytesGadget + + CondSelectGadget + + R1CSVar + Debug + Clone + Sized; type LeafInnerConverter: DigestVarConverter< Self::LeafDigest, - >::InputVar, + >::InputVar, >; - type InnerDigest: AllocVar - + EqGadget - + ToBytesGadget - + CondSelectGadget - + R1CSVar + type InnerDigest: AllocVar + + EqGadget + + ToBytesGadget + + CondSelectGadget + + R1CSVar + Debug + Clone + Sized; type LeafHash: CRHSchemeGadget< P::LeafHash, - ConstraintF, + F, InputVar = Self::Leaf, OutputVar = Self::LeafDigest, >; - type TwoToOneHash: TwoToOneCRHSchemeGadget< - P::TwoToOneHash, - ConstraintF, - OutputVar = Self::InnerDigest, - >; + type TwoToOneHash: TwoToOneCRHSchemeGadget; } -type LeafParam = - <>::LeafHash as CRHSchemeGadget< -

::LeafHash, - ConstraintF, - >>::ParametersVar; -type TwoToOneParam = - <>::TwoToOneHash as TwoToOneCRHSchemeGadget< +type LeafParam = <>::LeafHash as CRHSchemeGadget< +

::LeafHash, + F, +>>::ParametersVar; +type TwoToOneParam = + <>::TwoToOneHash as TwoToOneCRHSchemeGadget<

::TwoToOneHash, - ConstraintF, + F, >>::ParametersVar; /// Represents a merkle tree path gadget. #[derive(Debug, Derivative)] -#[derivative(Clone(bound = "P: Config, ConstraintF: Field, PG: ConfigGadget"))] -pub struct PathVar> { +#[derivative(Clone(bound = "P: Config, F: PrimeField, PG: ConfigGadget"))] +pub struct PathVar> { /// `path[i]` is 0 (false) iff ith non-leaf node from top to bottom is left. - path: Vec>, + path: Vec>, /// `auth_path[i]` is the entry of sibling of ith non-leaf node from top to bottom. auth_path: Vec, /// The sibling of leaf. leaf_sibling: PG::LeafDigest, /// Is this leaf the right child? - leaf_is_right_child: Boolean, + leaf_is_right_child: Boolean, } -impl> AllocVar, ConstraintF> - for PathVar +impl> AllocVar, F> for PathVar where P: Config, - ConstraintF: Field, + F: PrimeField, { #[tracing::instrument(target = "r1cs", skip(cs, f))] fn new_variable>>( - cs: impl Into>, + cs: impl Into>, f: impl FnOnce() -> Result, mode: AllocationMode, ) -> Result { @@ -148,12 +138,12 @@ where } } -impl> PathVar { +impl> PathVar { /// Set the leaf index of the path to a given value. Verifier can use function before calling `verify` /// to check the correctness leaf position. /// * `leaf_index`: leaf index encoded in little-endian format #[tracing::instrument(target = "r1cs", skip(self))] - pub fn set_leaf_position(&mut self, leaf_index: Vec>) { + pub fn set_leaf_position(&mut self, leaf_index: Vec>) { // The path to a leaf is described by the branching // decisions taken at each node. This corresponds to the position // of the leaf. @@ -180,7 +170,7 @@ impl> PathVar Vec> { + pub fn get_leaf_position(&self) -> Vec> { ark_std::iter::once(self.leaf_is_right_child.clone()) .chain(self.path.clone().into_iter().rev()) .collect() @@ -190,8 +180,8 @@ impl> PathVar, - two_to_one_params: &TwoToOneParam, + leaf_params: &LeafParam, + two_to_one_params: &TwoToOneParam, leaf: &PG::Leaf, ) -> Result { let claimed_leaf_hash = PG::LeafHash::evaluate(leaf_params, leaf)?; @@ -236,11 +226,11 @@ impl> PathVar, - two_to_one_params: &TwoToOneParam, + leaf_params: &LeafParam, + two_to_one_params: &TwoToOneParam, root: &PG::InnerDigest, leaf: &PG::Leaf, - ) -> Result, SynthesisError> { + ) -> Result, SynthesisError> { let expected_root = self.calculate_root(leaf_params, two_to_one_params, leaf)?; Ok(expected_root.is_eq(root)?) } @@ -250,8 +240,8 @@ impl> PathVar, - two_to_one_params: &TwoToOneParam, + leaf_params: &LeafParam, + two_to_one_params: &TwoToOneParam, old_root: &PG::InnerDigest, old_leaf: &PG::Leaf, new_leaf: &PG::Leaf, @@ -267,13 +257,13 @@ impl> PathVar, - two_to_one_params: &TwoToOneParam, + leaf_params: &LeafParam, + two_to_one_params: &TwoToOneParam, old_root: &PG::InnerDigest, new_root: &PG::InnerDigest, old_leaf: &PG::Leaf, new_leaf: &PG::Leaf, - ) -> Result, SynthesisError> { + ) -> Result, SynthesisError> { let actual_new_root = self.update_leaf(leaf_params, two_to_one_params, old_root, old_leaf, new_leaf)?; Ok(actual_new_root.is_eq(&new_root)?) diff --git a/src/merkle_tree/tests/constraints.rs b/src/merkle_tree/tests/constraints.rs index 8f1602d7..134e5092 100644 --- a/src/merkle_tree/tests/constraints.rs +++ b/src/merkle_tree/tests/constraints.rs @@ -5,9 +5,7 @@ mod byte_mt_tests { use crate::merkle_tree::constraints::{BytesVarDigestConverter, ConfigGadget}; use crate::merkle_tree::{constraints::PathVar, ByteDigestConverter, Config, MerkleTree}; use ark_ed_on_bls12_381::{constraints::EdwardsVar, EdwardsProjective as JubJub, Fq}; - #[allow(unused)] use ark_r1cs_std::prelude::*; - #[allow(unused)] use ark_relations::r1cs::ConstraintSystem; #[derive(Clone)] @@ -239,10 +237,10 @@ mod field_mt_tests { use crate::merkle_tree::constraints::ConfigGadget; use crate::merkle_tree::tests::test_utils::poseidon_parameters; use crate::merkle_tree::{constraints::PathVar, Config, IdentityDigestConverter, MerkleTree}; - use ark_r1cs_std::alloc::AllocVar; use ark_r1cs_std::fields::fp::FpVar; use ark_r1cs_std::uint32::UInt32; use ark_r1cs_std::R1CSVar; + use ark_r1cs_std::{alloc::AllocVar, convert::ToBitsGadget}; use ark_relations::r1cs::ConstraintSystem; use ark_std::{test_rng, One, UniformRand}; @@ -348,7 +346,8 @@ mod field_mt_tests { // try replace the path index let leaf_pos = UInt32::new_witness(cs.clone(), || Ok(i as u32)) .unwrap() - .to_bits_le(); + .to_bits_le() + .unwrap(); cw.set_leaf_position(leaf_pos.clone()); // check if get_leaf_position is correct diff --git a/src/prf/blake2s/constraints.rs b/src/prf/blake2s/constraints.rs index 31713cd3..cd52cf69 100644 --- a/src/prf/blake2s/constraints.rs +++ b/src/prf/blake2s/constraints.rs @@ -85,14 +85,14 @@ fn mixing_g( x: &UInt32, y: &UInt32, ) -> Result<(), SynthesisError> { - v[a] = UInt32::addmany(&[v[a].clone(), v[b].clone(), x.clone()])?; - v[d] = v[d].xor(&v[a])?.rotr(R1); - v[c] = UInt32::addmany(&[v[c].clone(), v[d].clone()])?; - v[b] = v[b].xor(&v[c])?.rotr(R2); - v[a] = UInt32::addmany(&[v[a].clone(), v[b].clone(), y.clone()])?; - v[d] = v[d].xor(&v[a])?.rotr(R3); - v[c] = UInt32::addmany(&[v[c].clone(), v[d].clone()])?; - v[b] = v[b].xor(&v[c])?.rotr(R4); + v[a] = UInt32::wrapping_add_many(&[v[a].clone(), v[b].clone(), x.clone()])?; + v[d] = (&v[d] ^ &v[a]).rotate_right(R1); + v[c] = v[c].wrapping_add(&v[d]); + v[b] = (&v[b] ^ &v[c]).rotate_right(R2); + v[a] = UInt32::wrapping_add_many(&[v[a].clone(), v[b].clone(), y.clone()])?; + v[d] = (&v[d] ^ &v[a]).rotate_right(R3); + v[c] = v[c].wrapping_add(&v[d]); + v[b] = (&v[b] ^ &v[c]).rotate_right(R4); Ok(()) } @@ -173,11 +173,11 @@ fn blake2s_compression( assert_eq!(v.len(), 16); - v[12] = v[12].xor(&UInt32::constant(t as u32))?; - v[13] = v[13].xor(&UInt32::constant((t >> 32) as u32))?; + v[12] ^= t as u32; + v[13] ^= (t >> 32) as u32; if f { - v[14] = v[14].xor(&UInt32::constant(u32::max_value()))?; + v[14] ^= u32::max_value(); } for i in 0..10 { @@ -194,8 +194,8 @@ fn blake2s_compression( } for i in 0..8 { - h[i] = h[i].xor(&v[i])?; - h[i] = h[i].xor(&v[i + 8])?; + h[i] ^= &v[i]; + h[i] ^= &v[i + 8]; } Ok(()) @@ -229,7 +229,7 @@ fn blake2s_compression( pub fn evaluate_blake2s( input: &[Boolean], -) -> Result>, SynthesisError> { +) -> Result<[UInt32; 8], SynthesisError> { assert!(input.len() % 8 == 0); let mut parameters = [0; 8]; parameters[0] = 0x01010000 ^ 32; @@ -239,18 +239,19 @@ pub fn evaluate_blake2s( pub fn evaluate_blake2s_with_parameters( input: &[Boolean], parameters: &[u32; 8], -) -> Result>, SynthesisError> { +) -> Result<[UInt32; 8], SynthesisError> { assert!(input.len() % 8 == 0); - let mut h = Vec::with_capacity(8); - h.push(UInt32::constant(0x6A09E667).xor(&UInt32::constant(parameters[0]))?); - h.push(UInt32::constant(0xBB67AE85).xor(&UInt32::constant(parameters[1]))?); - h.push(UInt32::constant(0x3C6EF372).xor(&UInt32::constant(parameters[2]))?); - h.push(UInt32::constant(0xA54FF53A).xor(&UInt32::constant(parameters[3]))?); - h.push(UInt32::constant(0x510E527F).xor(&UInt32::constant(parameters[4]))?); - h.push(UInt32::constant(0x9B05688C).xor(&UInt32::constant(parameters[5]))?); - h.push(UInt32::constant(0x1F83D9AB).xor(&UInt32::constant(parameters[6]))?); - h.push(UInt32::constant(0x5BE0CD19).xor(&UInt32::constant(parameters[7]))?); + let mut h = [ + UInt32::constant(0x6A09E667 ^ parameters[0]), + UInt32::constant(0xBB67AE85 ^ parameters[1]), + UInt32::constant(0x3C6EF372 ^ parameters[2]), + UInt32::constant(0xA54FF53A ^ parameters[3]), + UInt32::constant(0x510E527F ^ parameters[4]), + UInt32::constant(0x9B05688C ^ parameters[5]), + UInt32::constant(0x1F83D9AB ^ parameters[6]), + UInt32::constant(0x5BE0CD19 ^ parameters[7]), + ]; let mut blocks: Vec>> = vec![]; @@ -326,7 +327,7 @@ impl EqGadget for OutputVar { impl ToBytesGadget for OutputVar { #[inline] - fn to_bytes(&self) -> Result>, SynthesisError> { + fn to_bytes_le(&self) -> Result>, SynthesisError> { Ok(self.0.clone()) } } @@ -383,7 +384,7 @@ impl PRFGadget for Blake2sGadget { .collect(); let result: Vec<_> = evaluate_blake2s(&input)? .into_iter() - .flat_map(|int| int.to_bytes().unwrap()) + .flat_map(|int| int.to_bytes_le().unwrap()) .collect(); Ok(OutputVar(result)) } @@ -516,19 +517,8 @@ mod test { .flat_map(|&byte| (0..8).map(move |i| (byte >> i) & 1u8 == 1u8)); for chunk in r { - for b in chunk.to_bits_le() { - match b { - Boolean::Is(b) => { - assert!(s.next().unwrap() == b.value().unwrap()); - } - Boolean::Not(b) => { - assert!(s.next().unwrap() != b.value().unwrap()); - } - Boolean::Constant(b) => { - assert!(input_len == 0); - assert!(s.next().unwrap() == b); - } - } + for b in chunk.to_bits_le().unwrap() { + assert_eq!(s.next().unwrap(), b.value().unwrap()); } } } diff --git a/src/signature/schnorr/constraints.rs b/src/signature/schnorr/constraints.rs index 20dd2b47..0f663825 100644 --- a/src/signature/schnorr/constraints.rs +++ b/src/signature/schnorr/constraints.rs @@ -153,7 +153,7 @@ where GC: CurveVar>, for<'a> &'a GC: GroupOpsBounds<'a, C, GC>, { - fn to_bytes(&self) -> Result>>, SynthesisError> { - self.pub_key.to_bytes() + fn to_bytes_le(&self) -> Result>>, SynthesisError> { + self.pub_key.to_bytes_le() } } diff --git a/src/snark/constraints.rs b/src/snark/constraints.rs index 2f3388e6..66419198 100644 --- a/src/snark/constraints.rs +++ b/src/snark/constraints.rs @@ -1,13 +1,12 @@ use ark_ff::{BigInteger, PrimeField}; use ark_r1cs_std::prelude::*; use ark_r1cs_std::{ - bits::boolean::Boolean, fields::{ - fp::{AllocatedFp, FpVar}, - nonnative::{ + emulated_fp::{ params::{get_params, OptimizationType}, - AllocatedNonNativeFieldVar, NonNativeFieldVar, + AllocatedEmulatedFpVar, EmulatedFpVar, }, + fp::{AllocatedFp, FpVar}, }, R1CSVar, }; @@ -377,40 +376,40 @@ impl FromFieldElementsGadget for BooleanIn } } -/// Conversion of field elements by allocating them as nonnative field elements +/// Conversion of field elements by allocating them as "emulated" field elements /// Used by Marlin -pub struct NonNativeFieldInputVar +pub struct EmulatedFieldInputVar where F: PrimeField, CF: PrimeField, { - pub val: Vec>, + pub val: Vec>, } -impl NonNativeFieldInputVar +impl EmulatedFieldInputVar where F: PrimeField, CF: PrimeField, { - pub fn new(val: Vec>) -> Self { + pub fn new(val: Vec>) -> Self { Self { val } } } -impl IntoIterator for NonNativeFieldInputVar +impl IntoIterator for EmulatedFieldInputVar where F: PrimeField, CF: PrimeField, { - type Item = NonNativeFieldVar; - type IntoIter = IntoIter>; + type Item = EmulatedFpVar; + type IntoIter = IntoIter>; fn into_iter(self) -> Self::IntoIter { self.val.into_iter() } } -impl Clone for NonNativeFieldInputVar +impl Clone for EmulatedFieldInputVar where F: PrimeField, CF: PrimeField, @@ -422,7 +421,7 @@ where } } -impl AllocVar, CF> for NonNativeFieldInputVar +impl AllocVar, CF> for EmulatedFieldInputVar where F: PrimeField, CF: PrimeField, @@ -435,17 +434,17 @@ where if mode == AllocationMode::Input { Self::new_input(cs, f) } else { - // directly allocate them as nonnative field elements + // directly allocate them as emulated field elements let ns = cs.into(); let cs = ns.cs(); let t = f()?; let obj = t.borrow(); - let mut allocated = Vec::>::new(); + let mut allocated = Vec::>::new(); for elem in obj.iter() { - let elem_allocated = NonNativeFieldVar::::new_variable( + let elem_allocated = EmulatedFpVar::::new_variable( ns!(cs, "allocating element"), || Ok(elem), mode, @@ -461,7 +460,7 @@ where cs: impl Into>, f: impl FnOnce() -> Result, ) -> Result { - // allocate the nonnative field elements by squeezing the bits like in BooleanInputVar + // allocate the emulated field elements by squeezing the bits like in BooleanInputVar let ns = cs.into(); let cs = ns.cs(); @@ -485,11 +484,11 @@ where let boolean_allocation = BooleanInputVar::new_input(ns!(cs, "boolean"), || Ok(obj.borrow()))?; - // Step 2: allocating the nonnative field elements as witnesses - let mut field_allocation = Vec::>::new(); + // Step 2: allocating the emulated field elements as witnesses + let mut field_allocation = Vec::>::new(); for elem in obj.borrow().iter() { - let mut elem_allocated = AllocatedNonNativeFieldVar::::new_witness( + let mut elem_allocated = AllocatedEmulatedFpVar::::new_witness( ns!(cs, "allocating element"), || Ok(elem), )?; @@ -532,9 +531,9 @@ where } } - let mut wrapped_field_allocation = Vec::>::new(); + let mut wrapped_field_allocation = Vec::>::new(); for field_gadget in field_allocation.iter() { - wrapped_field_allocation.push(NonNativeFieldVar::Var(field_gadget.clone())); + wrapped_field_allocation.push(EmulatedFpVar::Var(field_gadget.clone())); } Ok(Self { val: wrapped_field_allocation, @@ -542,7 +541,7 @@ where } } -impl FromFieldElementsGadget for NonNativeFieldInputVar +impl FromFieldElementsGadget for EmulatedFieldInputVar where F: PrimeField, CF: PrimeField, @@ -558,8 +557,8 @@ where // Step 1: use BooleanInputVar to convert them into booleans let boolean_allocation = BooleanInputVar::::from_field_elements(src)?; - // Step 2: construct the nonnative field gadgets from bits - let mut field_allocation = Vec::>::new(); + // Step 2: construct the emulated field gadgets from bits + let mut field_allocation = Vec::>::new(); // reconstruct the field elements and check consistency for field_bits in boolean_allocation.val.iter() { @@ -576,7 +575,7 @@ where cur.double_in_place(); } - field_allocation.push(NonNativeFieldVar::Constant(value)); + field_allocation.push(EmulatedFpVar::Constant(value)); } Ok(Self { @@ -598,8 +597,8 @@ where // Step 1: use BooleanInputVar to convert them into booleans let boolean_allocation = BooleanInputVar::::from_field_elements(src)?; - // Step 2: construct the nonnative field gadgets from bits - let mut field_allocation = Vec::>::new(); + // Step 2: construct the emulated field gadgets from bits + let mut field_allocation = Vec::>::new(); // reconstruct the field elements and check consistency for field_bits in boolean_allocation.val.iter() { @@ -642,8 +641,8 @@ where limbs.push(FpVar::from(limb)); } - field_allocation.push(NonNativeFieldVar::::Var( - AllocatedNonNativeFieldVar:: { + field_allocation.push(EmulatedFpVar::::Var( + AllocatedEmulatedFpVar:: { cs: cs.clone(), limbs, num_of_additions_over_normal_form: CF::zero(), diff --git a/src/sponge/constraints/absorb.rs b/src/sponge/constraints/absorb.rs index 4ee6335c..58779a02 100644 --- a/src/sponge/constraints/absorb.rs +++ b/src/sponge/constraints/absorb.rs @@ -3,15 +3,15 @@ use ark_ec::{ twisted_edwards::TECurveConfig as TEModelParameters, CurveConfig as ModelParameters, }; use ark_ff::{Field, PrimeField}; -use ark_r1cs_std::bits::boolean::Boolean; -use ark_r1cs_std::bits::uint8::UInt8; +use ark_r1cs_std::boolean::Boolean; +use ark_r1cs_std::convert::{ToBytesGadget, ToConstraintFieldGadget}; use ark_r1cs_std::fields::fp::FpVar; use ark_r1cs_std::fields::{FieldOpsBounds, FieldVar}; use ark_r1cs_std::groups::curves::short_weierstrass::{ AffineVar as SWAffineVar, ProjectiveVar as SWProjectiveVar, }; use ark_r1cs_std::groups::curves::twisted_edwards::AffineVar as TEAffineVar; -use ark_r1cs_std::{ToBytesGadget, ToConstraintFieldGadget}; +use ark_r1cs_std::uint8::UInt8; use ark_relations::r1cs::SynthesisError; use ark_std::vec; use ark_std::vec::Vec; @@ -71,7 +71,7 @@ impl AbsorbGadget for UInt8 { impl AbsorbGadget for Boolean { fn to_sponge_bytes(&self) -> Result>, SynthesisError> { - self.to_bytes() + self.to_bytes_le() } fn to_sponge_field_elements(&self) -> Result>, SynthesisError> { @@ -81,7 +81,7 @@ impl AbsorbGadget for Boolean { impl AbsorbGadget for FpVar { fn to_sponge_bytes(&self) -> Result>, SynthesisError> { - self.to_bytes() + self.to_bytes_le() } fn to_sponge_field_elements(&self) -> Result>, SynthesisError> { @@ -125,7 +125,7 @@ where ) -> Result::BasePrimeField>>, SynthesisError> { let mut bytes = self.x.to_constraint_field()?.to_sponge_bytes()?; bytes.append(&mut self.y.to_constraint_field()?.to_sponge_bytes()?); - bytes.append(&mut self.infinity.to_bytes()?.to_sponge_bytes()?); + bytes.append(&mut self.infinity.to_bytes_le()?.to_sponge_bytes()?); Ok(bytes) } @@ -150,7 +150,7 @@ where Vec::BaseField as Field>::BasePrimeField>>, SynthesisError, > { - self.to_bytes() + self.to_bytes_le() } fn to_sponge_field_elements( diff --git a/src/sponge/constraints/mod.rs b/src/sponge/constraints/mod.rs index 18dfada3..0d29efe9 100644 --- a/src/sponge/constraints/mod.rs +++ b/src/sponge/constraints/mod.rs @@ -1,11 +1,11 @@ use crate::sponge::{Absorb, CryptographicSponge, FieldElementSize}; use ark_ff::PrimeField; use ark_r1cs_std::alloc::AllocVar; -use ark_r1cs_std::bits::boolean::Boolean; -use ark_r1cs_std::bits::uint8::UInt8; +use ark_r1cs_std::boolean::Boolean; +use ark_r1cs_std::fields::emulated_fp::params::{get_params, OptimizationType}; +use ark_r1cs_std::fields::emulated_fp::{AllocatedEmulatedFpVar, EmulatedFpVar}; use ark_r1cs_std::fields::fp::{AllocatedFp, FpVar}; -use ark_r1cs_std::fields::nonnative::params::{get_params, OptimizationType}; -use ark_r1cs_std::fields::nonnative::{AllocatedNonNativeFieldVar, NonNativeFieldVar}; +use ark_r1cs_std::uint8::UInt8; use ark_r1cs_std::R1CSVar; use ark_relations::lc; use ark_relations::r1cs::{ConstraintSystemRef, LinearCombination, SynthesisError}; @@ -15,25 +15,25 @@ use ark_std::vec::Vec; mod absorb; pub use absorb::*; -/// Converts little-endian bits to a list of nonnative elements. -pub fn bits_le_to_nonnative<'a, F: PrimeField, CF: PrimeField>( +/// Converts little-endian bits to a list of emulated elements. +pub fn bits_le_to_emulated<'a, F: PrimeField, CF: PrimeField>( cs: ConstraintSystemRef, - all_nonnative_bits_le: impl IntoIterator>>, -) -> Result>, SynthesisError> { - let all_nonnative_bits_le = all_nonnative_bits_le.into_iter().collect::>(); - if all_nonnative_bits_le.is_empty() { + all_emulated_bits_le: impl IntoIterator>>, +) -> Result>, SynthesisError> { + let all_emulated_bits_le = all_emulated_bits_le.into_iter().collect::>(); + if all_emulated_bits_le.is_empty() { return Ok(Vec::new()); } - let mut max_nonnative_bits = 0usize; - for bits in &all_nonnative_bits_le { - max_nonnative_bits = max_nonnative_bits.max(bits.len()); + let mut max_emulated_bits = 0usize; + for bits in &all_emulated_bits_le { + max_emulated_bits = max_emulated_bits.max(bits.len()); } let mut lookup_table = Vec::>::new(); let mut cur = F::one(); - for _ in 0..max_nonnative_bits { - let repr = AllocatedNonNativeFieldVar::::get_limbs_representations( + for _ in 0..max_emulated_bits { + let repr = AllocatedEmulatedFpVar::::get_limbs_representations( &cur, OptimizationType::Constraints, )?; @@ -47,12 +47,12 @@ pub fn bits_le_to_nonnative<'a, F: PrimeField, CF: PrimeField>( OptimizationType::Constraints, ); - let mut output = Vec::with_capacity(all_nonnative_bits_le.len()); - for nonnative_bits_le in all_nonnative_bits_le { + let mut output = Vec::with_capacity(all_emulated_bits_le.len()); + for emulated_bits_le in all_emulated_bits_le { let mut val = vec![CF::zero(); params.num_limbs]; let mut lc = vec![LinearCombination::::zero(); params.num_limbs]; - for (j, bit) in nonnative_bits_le.iter().enumerate() { + for (j, bit) in emulated_bits_le.iter().enumerate() { if bit.value().unwrap_or_default() { for (k, val) in val.iter_mut().enumerate().take(params.num_limbs) { *val += &lookup_table[j][k]; @@ -74,8 +74,8 @@ pub fn bits_le_to_nonnative<'a, F: PrimeField, CF: PrimeField>( limbs.push(FpVar::::from(gadget)); } - output.push(NonNativeFieldVar::::Var( - AllocatedNonNativeFieldVar:: { + output.push(EmulatedFpVar::::Var( + AllocatedEmulatedFpVar:: { cs: cs.clone(), limbs, num_of_additions_over_normal_form: CF::zero(), @@ -117,12 +117,12 @@ pub trait CryptographicSpongeVar: Clone /// Squeeze `num_bit` bits from the sponge. fn squeeze_bits(&mut self, num_bits: usize) -> Result>, SynthesisError>; - /// Squeeze `sizes.len()` nonnative field elements from the sponge, where the `i`-th element of + /// Squeeze `sizes.len()` emulated field elements from the sponge, where the `i`-th element of /// the output has size `sizes[i]`. - fn squeeze_nonnative_field_elements_with_sizes( + fn squeeze_emulated_field_elements_with_sizes( &mut self, sizes: &[FieldElementSize], - ) -> Result<(Vec>, Vec>>), SynthesisError> { + ) -> Result<(Vec>, Vec>>), SynthesisError> { if sizes.len() == 0 { return Ok((Vec::new(), Vec::new())); } @@ -141,23 +141,23 @@ pub trait CryptographicSpongeVar: Clone let mut bits_window = bits.as_slice(); for size in sizes { let num_bits = size.num_bits::(); - let nonnative_bits_le = bits_window[..num_bits].to_vec(); + let emulated_bits_le = bits_window[..num_bits].to_vec(); bits_window = &bits_window[num_bits..]; - dest_bits.push(nonnative_bits_le); + dest_bits.push(emulated_bits_le); } - let dest_gadgets = bits_le_to_nonnative(cs, dest_bits.iter())?; + let dest_gadgets = bits_le_to_emulated(cs, dest_bits.iter())?; Ok((dest_gadgets, dest_bits)) } - /// Squeeze `num_elements` nonnative field elements from the sponge. - fn squeeze_nonnative_field_elements( + /// Squeeze `num_elements` emulated field elements from the sponge. + fn squeeze_emulated_field_elements( &mut self, num_elements: usize, - ) -> Result<(Vec>, Vec>>), SynthesisError> { - self.squeeze_nonnative_field_elements_with_sizes::( + ) -> Result<(Vec>, Vec>>), SynthesisError> { + self.squeeze_emulated_field_elements_with_sizes::( vec![FieldElementSize::Full; num_elements].as_slice(), ) } diff --git a/src/sponge/mod.rs b/src/sponge/mod.rs index a81cf11c..bd8a1d92 100644 --- a/src/sponge/mod.rs +++ b/src/sponge/mod.rs @@ -68,10 +68,10 @@ pub(crate) fn squeeze_field_elements_with_sizes_default_impl( let mut output = Vec::with_capacity(sizes.len()); for size in sizes { let num_bits = size.num_bits::(); - let nonnative_bits_le: Vec = bits_window[..num_bits].to_vec(); + let emulated_bits_le: Vec = bits_window[..num_bits].to_vec(); bits_window = &bits_window[num_bits..]; - let nonnative_bytes = nonnative_bits_le + let emulated_bytes = emulated_bits_le .chunks(8) .map(|bits| { let mut byte = 0u8; @@ -84,7 +84,7 @@ pub(crate) fn squeeze_field_elements_with_sizes_default_impl( }) .collect::>(); - output.push(F::from_le_bytes_mod_order(nonnative_bytes.as_slice())); + output.push(F::from_le_bytes_mod_order(emulated_bytes.as_slice())); } output @@ -126,7 +126,7 @@ pub trait CryptographicSponge: Clone { squeeze_field_elements_with_sizes_default_impl(self, sizes) } - /// Squeeze `num_elements` nonnative field elements from the sponge. + /// Squeeze `num_elements` emulated field elements from the sponge. /// /// Because of rust limitation, for field-based implementation, using this method to squeeze /// native field elements will have runtime casting cost. For better efficiency, use `squeeze_native_field_elements`. diff --git a/src/sponge/poseidon/constraints.rs b/src/sponge/poseidon/constraints.rs index 160e74c6..8cbec6d2 100644 --- a/src/sponge/poseidon/constraints.rs +++ b/src/sponge/poseidon/constraints.rs @@ -240,7 +240,7 @@ impl CryptographicSpongeVar> for PoseidonSpo let mut bytes: Vec> = Vec::with_capacity(usable_bytes * num_elements); for elem in &src_elements { - bytes.extend_from_slice(&elem.to_bytes()?[..usable_bytes]); + bytes.extend_from_slice(&elem.to_bytes_le()?[..usable_bytes]); } bytes.truncate(num_bytes); @@ -365,7 +365,7 @@ mod tests { let mut constraint_sponge = PoseidonSpongeVar::::new(cs.clone(), &sponge_params); let (squeeze, bits) = constraint_sponge - .squeeze_nonnative_field_elements_with_sizes::(&[FieldElementSize::Truncated( + .squeeze_emulated_field_elements_with_sizes::(&[FieldElementSize::Truncated( squeeze_bits as usize, )]) .unwrap(); @@ -376,7 +376,7 @@ mod tests { // squeeze full let (_, bits) = constraint_sponge - .squeeze_nonnative_field_elements_with_sizes::(&[FieldElementSize::Full]) + .squeeze_emulated_field_elements_with_sizes::(&[FieldElementSize::Full]) .unwrap(); let bits = &bits[0]; assert_eq!(bits.len() as u32, Fr::MODULUS_BIT_SIZE - 1);