From 6cca9327be56eda49bf380af203ed8f2bb4b4b2b Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Fri, 28 Aug 2020 11:39:38 -0700 Subject: [PATCH] Refactor bit iteration infrastructure: * `to_bits` -> `to_bits_le` * `BitIterator` -> `BitIteratorLE` + `BitIteratorBE` * `found_one`/`seen_one` -> `BitIteratorBE::without_leading_zeros` --- cp-benches/benches/crypto_primitives/comm.rs | 2 +- cp-benches/benches/crypto_primitives/crh.rs | 4 +- .../src/commitment/blake2s/constraints.rs | 2 +- .../src/commitment/pedersen/constraints.rs | 15 +- .../src/commitment/pedersen/mod.rs | 7 +- .../src/crh/bowe_hopwood/constraints.rs | 5 +- crypto-primitives/src/crh/bowe_hopwood/mod.rs | 5 +- .../src/crh/pedersen/constraints.rs | 8 +- crypto-primitives/src/nizk/constraints.rs | 6 +- .../src/nizk/gm17/constraints.rs | 31 ++-- .../src/nizk/groth16/constraints.rs | 29 ++-- .../src/prf/blake2s/constraints.rs | 2 +- crypto-primitives/src/signature/mod.rs | 2 +- .../src/signature/schnorr/constraints.rs | 4 +- .../src/signature/schnorr/mod.rs | 14 +- r1cs-std/src/bits/boolean.rs | 120 ++++++++------- r1cs-std/src/bits/mod.rs | 53 ++++--- r1cs-std/src/bits/uint8.rs | 53 +++---- r1cs-std/src/fields/cubic_extension.rs | 16 +- r1cs-std/src/fields/fp/cmp.rs | 14 +- r1cs-std/src/fields/fp/mod.rs | 138 +++++++----------- r1cs-std/src/fields/mod.rs | 76 ++++++---- r1cs-std/src/fields/quadratic_extension.rs | 12 +- .../curves/short_weierstrass/bls12/mod.rs | 4 +- .../groups/curves/short_weierstrass/mod.rs | 73 ++++----- .../src/groups/curves/twisted_edwards/mod.rs | 78 ++++------ r1cs-std/src/groups/mod.rs | 36 +++-- r1cs-std/src/pairing/bls12/mod.rs | 4 +- r1cs-std/src/pairing/mnt4/mod.rs | 17 +-- r1cs-std/src/pairing/mnt6/mod.rs | 17 +-- r1cs-std/src/pairing/mod.rs | 6 +- 31 files changed, 398 insertions(+), 455 deletions(-) diff --git a/cp-benches/benches/crypto_primitives/comm.rs b/cp-benches/benches/crypto_primitives/comm.rs index c94d53a..759c687 100644 --- a/cp-benches/benches/crypto_primitives/comm.rs +++ b/cp-benches/benches/crypto_primitives/comm.rs @@ -33,7 +33,7 @@ fn pedersen_comm_eval(c: &mut Criterion) { let rng = &mut rand::thread_rng(); let commitment_randomness = Randomness::rand(rng); Commitment::::commit(¶meters, &input, &commitment_randomness) - .unwrap(); + .unwrap() }) }); } diff --git a/cp-benches/benches/crypto_primitives/crh.rs b/cp-benches/benches/crypto_primitives/crh.rs index 975e42b..3157cef 100644 --- a/cp-benches/benches/crypto_primitives/crh.rs +++ b/cp-benches/benches/crypto_primitives/crh.rs @@ -29,9 +29,7 @@ fn pedersen_crh_eval(c: &mut Criterion) { let parameters = CRH::::setup(&mut rng).unwrap(); let input = vec![5u8; 128]; c.bench_function("Pedersen CRH Eval", move |b| { - b.iter(|| { - CRH::::evaluate(¶meters, &input).unwrap(); - }) + b.iter(|| CRH::::evaluate(¶meters, &input).unwrap()) }); } diff --git a/crypto-primitives/src/commitment/blake2s/constraints.rs b/crypto-primitives/src/commitment/blake2s/constraints.rs index 9305e1b..9fa601f 100644 --- a/crypto-primitives/src/commitment/blake2s/constraints.rs +++ b/crypto-primitives/src/commitment/blake2s/constraints.rs @@ -31,7 +31,7 @@ impl CommitmentGadget for CommGadget { ) -> Result { let mut input_bits = Vec::with_capacity(512); for byte in input.iter().chain(r.0.iter()) { - input_bits.extend_from_slice(&byte.into_bits_le()); + input_bits.extend_from_slice(&byte.to_bits_le()?); } let mut result = Vec::new(); for int in evaluate_blake2s(&input_bits)?.into_iter() { diff --git a/crypto-primitives/src/commitment/pedersen/constraints.rs b/crypto-primitives/src/commitment/pedersen/constraints.rs index 5bff1b4..11f3e94 100644 --- a/crypto-primitives/src/commitment/pedersen/constraints.rs +++ b/crypto-primitives/src/commitment/pedersen/constraints.rs @@ -5,7 +5,7 @@ use crate::{ }; use algebra_core::{ fields::{Field, PrimeField}, - to_bytes, ProjectiveCurve, ToBytes, Zero, + to_bytes, ProjectiveCurve, Zero, }; use r1cs_core::{Namespace, SynthesisError}; @@ -73,17 +73,20 @@ where assert_eq!(parameters.params.generators.len(), W::NUM_WINDOWS); // Allocate new variable for commitment output. - let input_in_bits: Vec<_> = padded_input + let input_in_bits: Vec> = padded_input .iter() - .flat_map(|byte| byte.into_bits_le()) + .flat_map(|byte| byte.to_bits_le().unwrap()) .collect(); let input_in_bits = input_in_bits.chunks(W::WINDOW_SIZE); let mut result = - GG::precomputed_base_multiscalar_mul(¶meters.params.generators, input_in_bits)?; + GG::precomputed_base_multiscalar_mul_le(¶meters.params.generators, input_in_bits)?; // Compute h^r - let rand_bits: Vec<_> = r.0.iter().flat_map(|byte| byte.into_bits_le()).collect(); - result.precomputed_base_scalar_mul( + let rand_bits: Vec<_> = + r.0.iter() + .flat_map(|byte| byte.to_bits_le().unwrap()) + .collect(); + result.precomputed_base_scalar_mul_le( rand_bits .iter() .zip(¶meters.params.randomness_generator), diff --git a/crypto-primitives/src/commitment/pedersen/mod.rs b/crypto-primitives/src/commitment/pedersen/mod.rs index a668eb9..c12d7fc 100644 --- a/crypto-primitives/src/commitment/pedersen/mod.rs +++ b/crypto-primitives/src/commitment/pedersen/mod.rs @@ -2,7 +2,8 @@ use crate::{Error, Vec}; use algebra_core::{ bytes::ToBytes, io::{Result as IoResult, Write}, - BitIterator, Field, FpParameters, PrimeField, ProjectiveCurve, ToConstraintField, UniformRand, + BitIteratorLE, Field, FpParameters, PrimeField, ProjectiveCurve, ToConstraintField, + UniformRand, }; use core::marker::PhantomData; @@ -99,9 +100,7 @@ impl CommitmentScheme for Commitment { let randomize_time = start_timer!(|| "Randomize"); // Compute h^r. - let mut scalar_bits = BitIterator::new(randomness.0.into_repr()).collect::>(); - scalar_bits.reverse(); - for (bit, power) in scalar_bits + for (bit, power) in BitIteratorLE::new(randomness.0.into_repr()) .into_iter() .zip(¶meters.randomness_generator) { diff --git a/crypto-primitives/src/crh/bowe_hopwood/constraints.rs b/crypto-primitives/src/crh/bowe_hopwood/constraints.rs index d1309bb..1a7cc7d 100644 --- a/crypto-primitives/src/crh/bowe_hopwood/constraints.rs +++ b/crypto-primitives/src/crh/bowe_hopwood/constraints.rs @@ -56,7 +56,10 @@ where input: &[UInt8>], ) -> Result { // Pad the input if it is not the current length. - let mut input_in_bits: Vec<_> = input.iter().flat_map(|byte| byte.into_bits_le()).collect(); + let mut input_in_bits: Vec> = input + .iter() + .flat_map(|byte| byte.to_bits_le().unwrap()) + .collect(); if (input_in_bits.len()) % CHUNK_SIZE != 0 { let current_length = input_in_bits.len(); for _ in 0..(CHUNK_SIZE - current_length % CHUNK_SIZE) { diff --git a/crypto-primitives/src/crh/bowe_hopwood/mod.rs b/crypto-primitives/src/crh/bowe_hopwood/mod.rs index e3417eb..3d5f5d2 100644 --- a/crypto-primitives/src/crh/bowe_hopwood/mod.rs +++ b/crypto-primitives/src/crh/bowe_hopwood/mod.rs @@ -190,7 +190,8 @@ mod test { let rng = &mut test_rng(); let params = as FixedLengthCRH>::setup(rng).unwrap(); - as FixedLengthCRH>::evaluate(¶ms, &[1, 2, 3]) - .unwrap(); + let _ = + as FixedLengthCRH>::evaluate(¶ms, &[1, 2, 3]) + .unwrap(); } } diff --git a/crypto-primitives/src/crh/pedersen/constraints.rs b/crypto-primitives/src/crh/pedersen/constraints.rs index f6d7871..cd257b1 100644 --- a/crypto-primitives/src/crh/pedersen/constraints.rs +++ b/crypto-primitives/src/crh/pedersen/constraints.rs @@ -61,11 +61,13 @@ where assert_eq!(parameters.params.generators.len(), W::NUM_WINDOWS); // Allocate new variable for the result. - let input_in_bits: Vec<_> = padded_input.iter().flat_map(|b| b.into_bits_le()).collect(); + let input_in_bits: Vec> = padded_input + .iter() + .flat_map(|b| b.to_bits_le().unwrap()) + .collect(); let input_in_bits = input_in_bits.chunks(W::WINDOW_SIZE); let result = - GG::precomputed_base_multiscalar_mul(¶meters.params.generators, input_in_bits)?; - + GG::precomputed_base_multiscalar_mul_le(¶meters.params.generators, input_in_bits)?; Ok(result) } } diff --git a/crypto-primitives/src/nizk/constraints.rs b/crypto-primitives/src/nizk/constraints.rs index 40c91c7..e727e6e 100644 --- a/crypto-primitives/src/nizk/constraints.rs +++ b/crypto-primitives/src/nizk/constraints.rs @@ -37,7 +37,7 @@ pub trait NIZKVerifierGadget { fn verify<'a, T: 'a + ToBitsGadget + ?Sized>( verification_key: &Self::VerificationKeyVar, - input: impl Iterator, + input: impl IntoIterator, proof: &Self::ProofVar, ) -> Result<(), SynthesisError> { Self::conditional_verify(verification_key, input, proof, &Boolean::constant(true)) @@ -45,14 +45,14 @@ pub trait NIZKVerifierGadget { fn conditional_verify<'a, T: 'a + ToBitsGadget + ?Sized>( verification_key: &Self::VerificationKeyVar, - input: impl Iterator, + input: impl IntoIterator, proof: &Self::ProofVar, condition: &Boolean, ) -> Result<(), SynthesisError>; fn conditional_verify_prepared<'a, T: 'a + ToBitsGadget + ?Sized>( prepared_verification_key: &Self::PreparedVerificationKeyVar, - input: impl Iterator, + input: impl IntoIterator, proof: &Self::ProofVar, condition: &Boolean, ) -> Result<(), SynthesisError>; diff --git a/crypto-primitives/src/nizk/gm17/constraints.rs b/crypto-primitives/src/nizk/gm17/constraints.rs index 6c293f1..810f6d4 100644 --- a/crypto-primitives/src/nizk/gm17/constraints.rs +++ b/crypto-primitives/src/nizk/gm17/constraints.rs @@ -178,7 +178,7 @@ where fn conditional_verify<'a, T: 'a + ToBitsGadget + ?Sized>( vk: &Self::VerificationKeyVar, - input: impl Iterator, + input: impl IntoIterator, proof: &Self::ProofVar, condition: &Boolean, ) -> Result<(), SynthesisError> { @@ -190,7 +190,7 @@ where fn conditional_verify_prepared<'a, T: 'a + ToBitsGadget + ?Sized>( pvk: &Self::PreparedVerificationKeyVar, - mut input: impl Iterator, + input: impl IntoIterator, proof: &Self::ProofVar, condition: &Boolean, ) -> Result<(), SynthesisError> { @@ -200,9 +200,10 @@ where let g_psi = { let mut g_psi = pvk.query[0].clone(); let mut input_len = 1; + let mut input = input.into_iter(); for (input, b) in input.by_ref().zip(pvk.query.iter().skip(1)) { - let input_bits = input.to_bits()?; - g_psi += b.mul_bits(input_bits.iter())?; + let input_bits = input.to_bits_le()?; + g_psi += b.scalar_mul_le(input_bits.iter())?; input_len += 1; } // Check that the input and the query in the verification are of the @@ -398,7 +399,7 @@ mod test { use super::*; use algebra::{ bls12_377::{Bls12_377, Fq, Fr}, - test_rng, BitIterator, Field, PrimeField, + test_rng, BitIteratorLE, Field, PrimeField, }; use r1cs_std::{bls12_377::PairingVar as Bls12_377PairingVar, boolean::Boolean, Assignment}; use rand::Rng; @@ -486,10 +487,7 @@ mod test { { for (i, input) in inputs.into_iter().enumerate() { - let mut input_bits = BitIterator::new(input.into_repr()).collect::>(); - // Input must be in little-endian, but BitIterator outputs in big-endian. - input_bits.reverse(); - + let input_bits: Vec<_> = BitIteratorLE::new(input.into_repr()).collect(); let input_bits = Vec::>::new_input(cs.ns(format!("Input {}", i)), || { Ok(input_bits) @@ -505,7 +503,7 @@ mod test { println!("Time to verify!\n\n\n\n"); >::verify( &vk_gadget, - input_gadgets.iter(), + &input_gadgets, &proof_gadget, ) .unwrap(); @@ -637,7 +635,7 @@ mod test_recursive { .map(|chunk| { chunk .iter() - .flat_map(|byte| byte.into_bits_le()) + .flat_map(|byte| byte.to_bits_le().unwrap()) .collect::>() }) .collect::>(); @@ -648,7 +646,7 @@ mod test_recursive { TestProofVar1::new_witness(cs.ns("Proof"), || Ok(proof.clone())).unwrap(); >::verify( &vk_gadget, - input_gadgets.iter(), + &input_gadgets, &proof_gadget, )?; Ok(()) @@ -721,12 +719,7 @@ mod test_recursive { for (i, input) in inputs.into_iter().enumerate() { let input_gadget = FpVar::new_input(cs.ns(format!("Input {}", i)), || Ok(input)).unwrap(); - let mut fp_bits = input_gadget.to_bits().unwrap(); - - // FpVar::to_bits outputs a big-endian binary representation of - // fe_gadget's value, so we have to reverse it to get the little-endian - // form. - fp_bits.reverse(); + let mut fp_bits = input_gadget.to_bits_le().unwrap(); // Use 320 bits per element. for _ in fp_bits.len()..bigint_size { @@ -756,7 +749,7 @@ mod test_recursive { println!("Time to verify!\n\n\n\n"); >::verify( &vk_gadget, - input_gadgets.iter(), + &input_gadgets, &proof_gadget, ) .unwrap(); diff --git a/crypto-primitives/src/nizk/groth16/constraints.rs b/crypto-primitives/src/nizk/groth16/constraints.rs index 5b90ad3..c43f30b 100644 --- a/crypto-primitives/src/nizk/groth16/constraints.rs +++ b/crypto-primitives/src/nizk/groth16/constraints.rs @@ -166,7 +166,7 @@ where fn conditional_verify<'a, T: 'a + ToBitsGadget + ?Sized>( vk: &Self::VerificationKeyVar, - input: impl Iterator, + input: impl IntoIterator, proof: &Self::ProofVar, condition: &Boolean, ) -> Result<(), SynthesisError> { @@ -178,7 +178,7 @@ where fn conditional_verify_prepared<'a, T: 'a + ToBitsGadget + ?Sized>( pvk: &Self::PreparedVerificationKeyVar, - mut public_inputs: impl Iterator, + public_inputs: impl IntoIterator, proof: &Self::ProofVar, condition: &Boolean, ) -> Result<(), SynthesisError> { @@ -187,8 +187,9 @@ where let g_ic = { let mut g_ic: P::G1Var = pvk.gamma_abc_g1[0].clone(); let mut input_len = 1; + let mut public_inputs = public_inputs.into_iter(); for (input, b) in public_inputs.by_ref().zip(pvk.gamma_abc_g1.iter().skip(1)) { - let encoded_input_i: P::G1Var = b.mul_bits(input.to_bits()?.iter())?; + let encoded_input_i: P::G1Var = b.scalar_mul_le(input.to_bits_le()?.iter())?; g_ic += encoded_input_i; input_len += 1; } @@ -359,7 +360,7 @@ mod test { use super::*; use algebra::{ bls12_377::{Bls12_377, Fq, Fr}, - test_rng, BitIterator, Field, PrimeField, + test_rng, BitIteratorLE, Field, PrimeField, }; use r1cs_std::{bls12_377::PairingVar as Bls12_377PairingVar, boolean::Boolean, Assignment}; use rand::Rng; @@ -447,9 +448,7 @@ mod test { { for (i, input) in inputs.into_iter().enumerate() { - let mut input_bits = BitIterator::new(input.into_repr()).collect::>(); - // Input must be in little-endian, but BitIterator outputs in big-endian. - input_bits.reverse(); + let input_bits = BitIteratorLE::new(input.into_repr()).collect::>(); let input_bits = Vec::>::new_input(cs.ns(format!("Input {}", i)), || { @@ -466,7 +465,7 @@ mod test { println!("Time to verify!\n\n\n\n"); >::verify( &vk_gadget, - input_gadgets.iter(), + &input_gadgets, &proof_gadget, ) .unwrap(); @@ -598,7 +597,7 @@ mod test_recursive { .map(|chunk| { chunk .iter() - .flat_map(|byte| byte.into_bits_le()) + .flat_map(|byte| byte.to_bits_le().unwrap()) .collect::>() }) .collect::>(); @@ -609,7 +608,7 @@ mod test_recursive { TestProofVar1::new_witness(cs.ns("Proof"), || Ok(proof.clone())).unwrap(); >::verify( &vk_gadget, - input_gadgets.iter(), + &input_gadgets, &proof_gadget, )?; Ok(()) @@ -682,12 +681,7 @@ mod test_recursive { for (i, input) in inputs.into_iter().enumerate() { let input_gadget = FpVar::new_input(cs.ns(format!("Input {}", i)), || Ok(input)).unwrap(); - let mut fp_bits = input_gadget.to_bits().unwrap(); - - // FpVar::to_bits outputs a big-endian binary representation of - // fe_gadget's value, so we have to reverse it to get the little-endian - // form. - fp_bits.reverse(); + let mut fp_bits = input_gadget.to_bits_le().unwrap(); // Use 320 bits per element. for _ in fp_bits.len()..bigint_size { @@ -717,7 +711,7 @@ mod test_recursive { println!("Time to verify!\n\n\n\n"); >::verify( &vk_gadget, - input_gadgets.iter(), + &input_gadgets, &proof_gadget, ) .unwrap(); @@ -728,7 +722,6 @@ mod test_recursive { println!("========================================================="); } - // cs.print_named_objects(); assert!(cs.is_satisfied().unwrap()); } } diff --git a/crypto-primitives/src/prf/blake2s/constraints.rs b/crypto-primitives/src/prf/blake2s/constraints.rs index 9dd3103..68e20be 100644 --- a/crypto-primitives/src/prf/blake2s/constraints.rs +++ b/crypto-primitives/src/prf/blake2s/constraints.rs @@ -371,7 +371,7 @@ impl PRFGadget for Blake2sGadget { let input: Vec<_> = seed .iter() .chain(input) - .flat_map(|b| b.into_bits_le()) + .flat_map(|b| b.to_bits_le().unwrap()) .collect(); let result: Vec<_> = evaluate_blake2s(&input)? .into_iter() diff --git a/crypto-primitives/src/signature/mod.rs b/crypto-primitives/src/signature/mod.rs index d59e079..76c89c5 100644 --- a/crypto-primitives/src/signature/mod.rs +++ b/crypto-primitives/src/signature/mod.rs @@ -54,7 +54,7 @@ pub trait SignatureScheme { mod test { use crate::signature::{schnorr, *}; use algebra::{ - ed_on_bls12_381::EdwardsProjective as JubJub, groups::Group, test_rng, to_bytes, ToBytes, + ed_on_bls12_381::EdwardsProjective as JubJub, groups::Group, test_rng, to_bytes, UniformRand, }; use blake2::Blake2s; diff --git a/crypto-primitives/src/signature/schnorr/constraints.rs b/crypto-primitives/src/signature/schnorr/constraints.rs index bdc176c..f6f01c8 100644 --- a/crypto-primitives/src/signature/schnorr/constraints.rs +++ b/crypto-primitives/src/signature/schnorr/constraints.rs @@ -64,9 +64,9 @@ where let base = parameters.generator.clone(); let randomness = randomness .iter() - .flat_map(|b| b.into_bits_le()) + .flat_map(|b| b.to_bits_le().unwrap()) .collect::>(); - let rand_pk = &public_key.pub_key + &base.mul_bits(randomness.iter())?; + let rand_pk = &public_key.pub_key + &base.scalar_mul_le(randomness.iter())?; Ok(PublicKeyVar { pub_key: rand_pk, _group: PhantomData, diff --git a/crypto-primitives/src/signature/schnorr/mod.rs b/crypto-primitives/src/signature/schnorr/mod.rs index 20f2d98..eab96bd 100644 --- a/crypto-primitives/src/signature/schnorr/mod.rs +++ b/crypto-primitives/src/signature/schnorr/mod.rs @@ -163,14 +163,12 @@ where let randomized_pk = *public_key; let base = parameters.generator; let mut encoded = C::zero(); - let mut found_one = false; - for bit in bytes_to_bits(randomness).into_iter().rev() { - if found_one { - encoded.double_in_place(); - } else { - found_one |= bit; - } - + for bit in bytes_to_bits(randomness) + .into_iter() + .rev() + .skip_while(|b| !b) + { + encoded.double_in_place(); if bit { encoded.add_assign_mixed(&base) } diff --git a/r1cs-std/src/bits/boolean.rs b/r1cs-std/src/bits/boolean.rs index 8fe60b3..1f23b93 100644 --- a/r1cs-std/src/bits/boolean.rs +++ b/r1cs-std/src/bits/boolean.rs @@ -1,4 +1,4 @@ -use algebra::{BitIterator, Field}; +use algebra::{BitIteratorBE, Field}; use crate::{prelude::*, Assignment, Vec}; use core::borrow::Borrow; @@ -373,14 +373,15 @@ impl Boolean { } } - /// Asserts that this bit_gadget representation is "in - /// the field" when interpreted in big endian. - pub fn enforce_in_field(bits: &[Self]) -> Result<(), SynthesisError> { - // b = char() - 1 + /// Enforces that `bits`, when interpreted as a integer, is less than `F::characteristic()`, + /// That is, interpret bits as a little-endian integer, and enforce that this integer + /// is "in the field F". + pub fn enforce_in_field_le(bits: &[Self]) -> Result<(), SynthesisError> { + // `bits` < F::characteristic() <==> `bits` <= F::characteristic() -1 let mut b = F::characteristic().to_vec(); assert_eq!(b[0] % 2, 1); - b[0] -= 1; - let run = Self::enforce_smaller_or_equal_than(bits, b)?; + b[0] -= 1; // This works, because the LSB is one, so there's no borrows. + let run = Self::enforce_smaller_or_equal_than_le(bits, b)?; // We should always end in a "run" of zeros, because // the characteristic is an odd prime. So, this should @@ -390,57 +391,35 @@ impl Boolean { Ok(()) } - /// Asserts that this bit_gadget representation is smaller - /// or equal than the provided element - pub fn enforce_smaller_or_equal_than( + /// Enforces that `bits` is less than or equal to `element`, + /// when both are interpreted as (little-endian) integers. + pub fn enforce_smaller_or_equal_than_le<'a>( bits: &[Self], element: impl AsRef<[u64]>, ) -> Result, SynthesisError> { - let mut bits_iter = bits.iter(); let b: &[u64] = element.as_ref(); + let mut bits_iter = bits.iter().rev(); // Iterate in big-endian + // Runs of ones in r let mut last_run = Boolean::constant(true); let mut current_run = vec![]; - let mut found_one = false; - - let char_num_bits = { - let mut leading_zeros = 0; - let mut total_bits = 0; - let mut found_one = false; - for b in BitIterator::new(b.clone()) { - total_bits += 1; - if !b && !found_one { - leading_zeros += 1 - } - if b { - found_one = true; - } - } - - total_bits - leading_zeros - }; + let mut element_num_bits = 0; + for _ in BitIteratorBE::without_leading_zeros(b) { + element_num_bits += 1; + } - if bits.len() > char_num_bits { - let num_extra_bits = bits.len() - char_num_bits; + if bits.len() > element_num_bits { let mut or_result = Boolean::constant(false); - for should_be_zero in &bits[0..num_extra_bits] { + for should_be_zero in &bits[element_num_bits..] { or_result = or_result.or(should_be_zero)?; let _ = bits_iter.next().unwrap(); } or_result.enforce_equal(&Boolean::constant(false))?; } - for b in BitIterator::new(b) { - // Skip over unset bits at the beginning - found_one |= b; - if !found_one { - continue; - } - - let a = bits_iter.next().unwrap(); - + for (b, a) in BitIteratorBE::without_leading_zeros(b).zip(bits_iter.by_ref()) { if b { // This is part of a run of ones. current_run.push(a.clone()); @@ -586,9 +565,8 @@ impl EqGadget for Boolean { impl ToBytesGadget for Boolean { /// Outputs `1u8` if `self` is true, and `0u8` otherwise. fn to_bytes(&self) -> Result>, SynthesisError> { - let mut bits = vec![Boolean::constant(false); 7]; - bits.push(self.clone()); - bits.reverse(); + let mut bits = vec![self.clone()]; + bits.extend(vec![Boolean::constant(false); 7]); let value = self.value().map(|val| val as u8).ok(); let byte = UInt8 { bits, value }; Ok(vec![byte]) @@ -655,7 +633,9 @@ impl CondSelectGadget for Boolean { mod test { use super::{AllocatedBit, Boolean}; use crate::prelude::*; - use algebra::{bls12_381::Fr, BitIterator, Field, One, PrimeField, UniformRand, Zero}; + use algebra::{ + bls12_381::Fr, BitIteratorBE, BitIteratorLE, Field, One, PrimeField, UniformRand, Zero, + }; use r1cs_core::{ConstraintSystem, Namespace, SynthesisError}; use rand::SeedableRng; use rand_xorshift::XorShiftRng; @@ -1331,17 +1311,58 @@ mod test { Ok(()) } + #[test] + fn test_smaller_than_or_equal_to() -> Result<(), SynthesisError> { + let mut rng = XorShiftRng::seed_from_u64(1231275789u64); + for _ in 0..1000 { + let mut r = Fr::rand(&mut rng); + let mut s = Fr::rand(&mut rng); + if r > s { + core::mem::swap(&mut r, &mut s) + } + + let cs = ConstraintSystem::::new_ref(); + + let native_bits: Vec<_> = BitIteratorLE::new(r.into_repr()).collect(); + let bits = Vec::new_witness(cs.clone(), || Ok(native_bits))?; + Boolean::enforce_smaller_or_equal_than_le(&bits, s.into_repr())?; + + assert!(cs.is_satisfied().unwrap()); + } + + for _ in 0..1000 { + let r = Fr::rand(&mut rng); + if r == -Fr::one() { + continue; + } + let s = r + Fr::one(); + let s2 = r.double(); + let cs = ConstraintSystem::::new_ref(); + + let native_bits: Vec<_> = BitIteratorLE::new(r.into_repr()).collect(); + let bits = Vec::new_witness(cs.clone(), || Ok(native_bits))?; + Boolean::enforce_smaller_or_equal_than_le(&bits, s.into_repr())?; + if r < s2 { + Boolean::enforce_smaller_or_equal_than_le(&bits, s2.into_repr())?; + } + + assert!(cs.is_satisfied().unwrap()); + } + Ok(()) + } + #[test] fn test_enforce_in_field() -> Result<(), SynthesisError> { { let cs = ConstraintSystem::::new_ref(); let mut bits = vec![]; - for b in BitIterator::new(Fr::characteristic()).skip(1) { + for b in BitIteratorBE::new(Fr::characteristic()).skip(1) { bits.push(Boolean::new_witness(cs.clone(), || Ok(b))?); } + bits.reverse(); - Boolean::enforce_in_field(&bits)?; + Boolean::enforce_in_field_le(&bits)?; assert!(!cs.is_satisfied().unwrap()); } @@ -1353,11 +1374,12 @@ mod test { let cs = ConstraintSystem::::new_ref(); let mut bits = vec![]; - for b in BitIterator::new(r.into_repr()).skip(1) { + for b in BitIteratorBE::new(r.into_repr()).skip(1) { bits.push(Boolean::new_witness(cs.clone(), || Ok(b))?); } + bits.reverse(); - Boolean::enforce_in_field(&bits)?; + Boolean::enforce_in_field_le(&bits)?; assert!(cs.is_satisfied().unwrap()); } diff --git a/r1cs-std/src/bits/mod.rs b/r1cs-std/src/bits/mod.rs index 3a48248..a0d03c6 100644 --- a/r1cs-std/src/bits/mod.rs +++ b/r1cs-std/src/bits/mod.rs @@ -15,66 +15,63 @@ make_uint!(UInt32, 32, u32, uint32); make_uint!(UInt64, 64, u64, uint64); pub trait ToBitsGadget { - /// Outputs the canonical bit-wise representation of `self`. + /// Outputs the canonical little-endian bit-wise representation of `self`. /// /// This is the correct default for 99% of use cases. - fn to_bits(&self) -> Result>, SynthesisError>; + fn to_bits_le(&self) -> Result>, SynthesisError>; /// Outputs a possibly non-unique bit-wise representation of `self`. /// /// If you're not absolutely certain that your usecase can get away with a /// non-canonical representation, please use `self.to_bits(cs)` instead. - fn to_non_unique_bits(&self) -> Result>, SynthesisError> { - self.to_bits() + fn to_non_unique_bits_le(&self) -> Result>, SynthesisError> { + self.to_bits_le() } } impl ToBitsGadget for Boolean { - fn to_bits(&self) -> Result>, SynthesisError> { + fn to_bits_le(&self) -> Result>, SynthesisError> { Ok(vec![self.clone()]) } } impl ToBitsGadget for [Boolean] { - fn to_bits(&self) -> Result>, SynthesisError> { + /// Outputs `self`. + fn to_bits_le(&self) -> Result>, SynthesisError> { Ok(self.to_vec()) } } -impl ToBitsGadget for Vec> { - fn to_bits(&self) -> Result>, SynthesisError> { - Ok(self.clone()) - } -} - impl ToBitsGadget for UInt8 { - fn to_bits(&self) -> Result>, SynthesisError> { - Ok(self.into_bits_le()) + fn to_bits_le(&self) -> Result>, SynthesisError> { + Ok(self.bits.to_vec()) } } impl ToBitsGadget for [UInt8] { - fn to_bits(&self) -> Result>, SynthesisError> { - let mut result = Vec::with_capacity(&self.len() * 8); - for byte in self { - result.extend_from_slice(&byte.into_bits_le()); - } - Ok(result) + /// Interprets `self` as an integer, and outputs the little-endian + /// bit-wise decomposition of that integer. + fn to_bits_le(&self) -> Result>, SynthesisError> { + let bits = self.iter().flat_map(|b| &b.bits).cloned().collect(); + Ok(bits) } } -impl ToBitsGadget for Vec> { - fn to_bits(&self) -> Result>, SynthesisError> { - let mut result = Vec::with_capacity(&self.len() * 8); - for byte in self { - result.extend_from_slice(&byte.into_bits_le()); - } - Ok(result) +impl ToBitsGadget for Vec +where + [T]: ToBitsGadget, +{ + fn to_bits_le(&self) -> Result>, SynthesisError> { + self.as_slice().to_bits_le().map(|v| v.to_vec()) + } + + fn to_non_unique_bits_le(&self) -> Result>, SynthesisError> { + self.as_slice().to_non_unique_bits_le().map(|v| v.to_vec()) } } pub trait ToBytesGadget { - /// Outputs a canonical byte-wise representation of `self`. + /// Outputs a canonical, little-endian, byte decomposition of `self`. /// /// This is the correct default for 99% of use cases. fn to_bytes(&self) -> Result>, SynthesisError>; diff --git a/r1cs-std/src/bits/uint8.rs b/r1cs-std/src/bits/uint8.rs index 51b52aa..662dc7c 100644 --- a/r1cs-std/src/bits/uint8.rs +++ b/r1cs-std/src/bits/uint8.rs @@ -98,11 +98,7 @@ impl UInt8 { let mut allocated_bits = Vec::new(); for field_element in field_elements.into_iter() { let fe = AllocatedFp::new_input(cs.clone(), || Ok(field_element))?; - let mut fe_bits = fe.to_bits()?; - // FpGadget::to_bits outputs a big-endian binary representation of - // fe_gadget's value, so we have to reverse it to get the little-endian - // form. - fe_bits.reverse(); + let fe_bits = fe.to_bits_le()?; // Remove the most significant bit, because we know it should be zero // because `values.to_field_elements()` only @@ -113,19 +109,12 @@ impl UInt8 { } // Chunk up slices of 8 bit into bytes. - Ok(allocated_bits[0..8 * values_len] + Ok(allocated_bits[0..(8 * values_len)] .chunks(8) .map(Self::from_bits_le) .collect()) } - /// Turns this `UInt8` into its little-endian byte order representation. - /// LSB-first means that we can easily get the corresponding field element - /// via double and add. - pub fn into_bits_le(&self) -> Vec> { - self.bits.to_vec() - } - /// Converts a little-endian byte order representation of bits into a /// `UInt8`. pub fn from_bits_le(bits: &[Boolean]) -> Self { @@ -134,25 +123,10 @@ impl UInt8 { let bits = bits.to_vec(); let mut value = Some(0u8); - for b in bits.iter().rev() { - value.as_mut().map(|v| *v <<= 1); - - match *b { - Boolean::Constant(b) => { - value.as_mut().map(|v| *v |= u8::from(b)); - } - Boolean::Is(ref b) => match b.value() { - Ok(b) => { - value.as_mut().map(|v| *v |= u8::from(b)); - } - Err(_) => value = None, - }, - Boolean::Not(ref b) => match b.value() { - Ok(b) => { - value.as_mut().map(|v| *v |= u8::from(!b)); - } - Err(_) => value = None, - }, + for (i, b) in bits.iter().enumerate() { + value = match b.value().ok() { + Some(b) => value.map(|v| v + (u8::from(b) << i)), + None => None, } } @@ -241,7 +215,7 @@ mod test { let cs = ConstraintSystem::::new_ref(); let byte_val = 0b01110001; let byte = UInt8::new_witness(cs.ns("alloc value"), || Ok(byte_val)).unwrap(); - let bits = byte.into_bits_le(); + let bits = byte.to_bits_le()?; for (i, bit) in bits.iter().enumerate() { assert_eq!(bit.value()?, (byte_val >> i) & 1 == 1) } @@ -253,10 +227,17 @@ mod test { let cs = ConstraintSystem::::new_ref(); let byte_vals = (64u8..128u8).collect::>(); let bytes = UInt8::new_input_vec(cs.ns("alloc value"), &byte_vals).unwrap(); + dbg!(bytes.value())?; for (native, variable) in byte_vals.into_iter().zip(bytes) { - let bits = variable.into_bits_le(); + let bits = variable.to_bits_le()?; for (i, bit) in bits.iter().enumerate() { - assert_eq!(bit.value()?, (native >> i) & 1 == 1) + assert_eq!( + bit.value()?, + (native >> i) & 1 == 1, + "native value {}: bit {:?}", + native, + i + ) } } Ok(()) @@ -280,7 +261,7 @@ mod test { } } - let expected_to_be_same = val.into_bits_le(); + let expected_to_be_same = val.to_bits_le()?; for x in v.iter().zip(expected_to_be_same.iter()) { match x { diff --git a/r1cs-std/src/fields/cubic_extension.rs b/r1cs-std/src/fields/cubic_extension.rs index a6e7f6d..12b4633 100644 --- a/r1cs-std/src/fields/cubic_extension.rs +++ b/r1cs-std/src/fields/cubic_extension.rs @@ -376,19 +376,19 @@ where for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>, P: CubicExtVarParams, { - fn to_bits(&self) -> Result>, SynthesisError> { - let mut c0 = self.c0.to_bits()?; - let mut c1 = self.c1.to_bits()?; - let mut c2 = self.c2.to_bits()?; + fn to_bits_le(&self) -> Result>, SynthesisError> { + let mut c0 = self.c0.to_bits_le()?; + let mut c1 = self.c1.to_bits_le()?; + let mut c2 = self.c2.to_bits_le()?; c0.append(&mut c1); c0.append(&mut c2); Ok(c0) } - fn to_non_unique_bits(&self) -> Result>, SynthesisError> { - let mut c0 = self.c0.to_non_unique_bits()?; - let mut c1 = self.c1.to_non_unique_bits()?; - let mut c2 = self.c2.to_non_unique_bits()?; + fn to_non_unique_bits_le(&self) -> Result>, SynthesisError> { + let mut c0 = self.c0.to_non_unique_bits_le()?; + let mut c1 = self.c1.to_non_unique_bits_le()?; + let mut c2 = self.c2.to_non_unique_bits_le()?; c0.append(&mut c1); c0.append(&mut c2); Ok(c0) diff --git a/r1cs-std/src/fields/fp/cmp.rs b/r1cs-std/src/fields/fp/cmp.rs index 7f53828..72cc89b 100644 --- a/r1cs-std/src/fields/fp/cmp.rs +++ b/r1cs-std/src/fields/fp/cmp.rs @@ -95,8 +95,10 @@ impl FpVar { pub fn enforce_smaller_or_equal_than_mod_minus_one_div_two( &self, ) -> Result<(), SynthesisError> { - let _ = Boolean::enforce_smaller_or_equal_than( - &self.to_bits()?, + // It's okay to use `to_non_unique_bits` bits here because we're enforcing + // self <= (p-1)/2, which implies self < p. + let _ = Boolean::enforce_smaller_or_equal_than_le( + &self.to_non_unique_bits_le()?, F::modulus_minus_one_div_two(), )?; Ok(()) @@ -114,7 +116,12 @@ impl FpVar { /// assumes `self` and `other` are `<= (p-1)/2` and does not generate constraints /// to verify that. fn is_smaller_than_unchecked(&self, other: &FpVar) -> Result, SynthesisError> { - Ok((self - other).double()?.to_bits()?.last().unwrap().clone()) + Ok((self - other) + .double()? + .to_bits_le()? + .first() + .unwrap() + .clone()) } /// Helper function to enforce `self < other`. This function verifies `self` and `other` @@ -186,6 +193,7 @@ mod test { } assert!(cs.is_satisfied().unwrap()); } + println!("Finished with satisfaction tests"); for _i in 0..10 { let cs = ConstraintSystem::::new_ref(); diff --git a/r1cs-std/src/fields/fp/mod.rs b/r1cs-std/src/fields/fp/mod.rs index 672e29b..606258a 100644 --- a/r1cs-std/src/fields/fp/mod.rs +++ b/r1cs-std/src/fields/fp/mod.rs @@ -1,10 +1,10 @@ -use algebra::{bytes::ToBytes, FpParameters, PrimeField}; +use algebra::{BigInteger, FpParameters, PrimeField}; use r1cs_core::{lc, ConstraintSystemRef, LinearCombination, Namespace, SynthesisError, Variable}; use core::borrow::Borrow; use crate::fields::{FieldOpsBounds, FieldVar}; -use crate::{boolean::AllocatedBit, prelude::*, Assignment, Vec}; +use crate::{prelude::*, Assignment, Vec}; pub mod cmp; @@ -338,48 +338,41 @@ impl AllocatedFp { impl ToBitsGadget for AllocatedFp { /// Outputs the unique bit-wise decomposition of `self` in *big-endian* /// form. - fn to_bits(&self) -> Result>, SynthesisError> { - let bits = self.to_non_unique_bits()?; - Boolean::enforce_in_field(&bits)?; + fn to_bits_le(&self) -> Result>, SynthesisError> { + let bits = self.to_non_unique_bits_le()?; + Boolean::enforce_in_field_le(&bits)?; Ok(bits) } - fn to_non_unique_bits(&self) -> Result>, SynthesisError> { + fn to_non_unique_bits_le(&self) -> Result>, SynthesisError> { let cs = self.cs.clone(); - let num_bits = F::Params::MODULUS_BITS; - use algebra::BitIterator; - let bit_values = match self.value { - Some(value) => { - let mut field_char = BitIterator::new(F::characteristic()); - let mut tmp = Vec::with_capacity(num_bits as usize); - let mut found_one = false; - for b in BitIterator::new(value.into_repr()) { - // Skip leading bits - found_one |= field_char.next().unwrap(); - if !found_one { - continue; - } - - tmp.push(Some(b)); - } - - assert_eq!(tmp.len(), num_bits as usize); - - tmp - } - None => vec![None; num_bits as usize], + use algebra::BitIteratorBE; + let mut bits = if let Some(value) = self.value { + let field_char = BitIteratorBE::new(F::characteristic()); + let bits: Vec<_> = BitIteratorBE::new(value.into_repr()) + .zip(field_char) + .skip_while(|(_, c)| !c) + .map(|(b, _)| Some(b)) + .collect(); + assert_eq!(bits.len(), F::Params::MODULUS_BITS as usize); + bits + } else { + vec![None; F::Params::MODULUS_BITS as usize] }; - let mut bits = vec![]; - for b in bit_values { - bits.push(AllocatedBit::new_witness(cs.clone(), || b.get())?); - } + // Convert to little-endian + bits.reverse(); + + let bits: Vec<_> = bits + .into_iter() + .map(|b| Boolean::new_witness(cs.clone(), || b.get())) + .collect::>()?; let mut lc = LinearCombination::zero(); let mut coeff = F::one(); - for bit in bits.iter().rev() { - lc += (coeff, bit.variable()); + for bit in bits.iter() { + lc = &lc + bit.lc() * coeff; coeff.double_in_place(); } @@ -388,7 +381,7 @@ impl ToBitsGadget for AllocatedFp { cs.enforce_constraint(lc!(), lc!(), lc)?; - Ok(bits.into_iter().map(Boolean::from).collect()) + Ok(bits) } } @@ -396,52 +389,26 @@ impl ToBytesGadget for AllocatedFp { /// Outputs the unique byte decomposition of `self` in *little-endian* /// form. fn to_bytes(&self) -> Result>, SynthesisError> { - let bytes = self.to_non_unique_bytes()?; - Boolean::enforce_in_field( - &bytes.iter() - .flat_map(|b| b.into_bits_le()) - // This reverse maps the bits into big-endian form, as required by `enforce_in_field`. - .rev() - .collect::>(), - )?; - + let num_bits = F::BigInt::NUM_LIMBS * 64; + let mut bits = self.to_bits_le()?; + let remainder = core::iter::repeat(Boolean::constant(false)).take(num_bits - bits.len()); + bits.extend(remainder); + let bytes = bits + .chunks(8) + .map(|chunk| UInt8::from_bits_le(chunk)) + .collect(); Ok(bytes) } fn to_non_unique_bytes(&self) -> Result>, SynthesisError> { - let cs = self.cs.clone(); - let byte_values = match self.value { - Some(value) => to_bytes![&value.into_repr()] - .unwrap() - .into_iter() - .map(Some) - .collect::>(), - None => { - let default = F::default(); - let default_len = to_bytes![&default].unwrap().len(); - vec![None; default_len] - } - }; - - let bytes = UInt8::new_witness_vec(cs.clone(), &byte_values)?; - - let mut lc = LinearCombination::zero(); - let mut coeff = F::one(); - - for bit in bytes.iter().flat_map(|b| b.bits.clone()) { - match bit { - Boolean::Is(bit) => { - lc += (coeff, bit.variable()); - coeff.double_in_place(); - } - Boolean::Constant(_) | Boolean::Not(_) => unreachable!(), - } - } - - lc = lc - &self.variable; - - cs.enforce_constraint(lc!(), lc!(), lc)?; - + let num_bits = F::BigInt::NUM_LIMBS * 64; + let mut bits = self.to_non_unique_bits_le()?; + let remainder = core::iter::repeat(Boolean::constant(false)).take(num_bits - bits.len()); + bits.extend(remainder); + let bytes = bits + .chunks(8) + .map(|chunk| UInt8::from_bits_le(chunk)) + .collect(); Ok(bytes) } } @@ -806,19 +773,20 @@ impl EqGadget for FpVar { } impl ToBitsGadget for FpVar { - /// Outputs the unique bit-wise decomposition of `self` in *big-endian* - /// form. - fn to_bits(&self) -> Result>, SynthesisError> { + fn to_bits_le(&self) -> Result>, SynthesisError> { match self { - Self::Constant(c) => UInt8::constant_vec(&to_bytes![c].unwrap()).to_bits(), - Self::Var(v) => v.to_bits(), + Self::Constant(_) => self.to_non_unique_bits_le(), + Self::Var(v) => v.to_bits_le(), } } - fn to_non_unique_bits(&self) -> Result>, SynthesisError> { + fn to_non_unique_bits_le(&self) -> Result>, SynthesisError> { + use algebra::BitIteratorLE; match self { - Self::Constant(c) => UInt8::constant_vec(&to_bytes![c].unwrap()).to_non_unique_bits(), - Self::Var(v) => v.to_non_unique_bits(), + Self::Constant(c) => Ok(BitIteratorLE::without_trailing_zeros(&c.into_repr()) + .map(Boolean::constant) + .collect::>()), + Self::Var(v) => v.to_non_unique_bits_le(), } } } diff --git a/r1cs-std/src/fields/mod.rs b/r1cs-std/src/fields/mod.rs index a733f13..30d7675 100644 --- a/r1cs-std/src/fields/mod.rs +++ b/r1cs-std/src/fields/mod.rs @@ -1,4 +1,4 @@ -use algebra::{prelude::*, BitIterator}; +use algebra::{prelude::*, BitIteratorBE}; use core::{ fmt::Debug, ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign}, @@ -132,37 +132,28 @@ pub trait FieldVar: Ok(self) } - /// Accepts as input a list of bits which, when interpreted in little-endian - /// form, are a scalar. - // - // TODO: check that the input really should be in little-endian or not... - fn pow(&self, bits: &[Boolean]) -> Result { + /// Comptues `self^bits`, where `bits` is a *little-endian* bit-wise decomposition + /// of the exponent. + fn pow_le(&self, bits: &[Boolean]) -> Result { let mut res = Self::one(); - for bit in bits.iter() { - res.square_in_place()?; - let tmp = res.clone() * self; + let mut power = self.clone(); + for bit in bits { + let tmp = res.clone() * &power; res = bit.select(&tmp, &res)?; + power.square_in_place()?; } Ok(res) } + /// Computes `self^S`, where S is interpreted as an integer. fn pow_by_constant>(&self, exp: S) -> Result { - let mut res = self.clone(); - let mut found_one = false; - - for bit in BitIterator::new(exp) { - if found_one { - res = res.square()?; - } - - if bit { - if found_one { - res *= self; - } - found_one = true; + let mut res = Self::one(); + for i in BitIteratorBE::without_leading_zeros(exp) { + res.square_in_place()?; + if i { + res *= self; } } - Ok(res) } } @@ -173,7 +164,7 @@ pub(crate) mod tests { use rand_xorshift::XorShiftRng; use crate::{fields::*, Vec}; - use algebra::{test_rng, BitIterator, Field, UniformRand}; + use algebra::{test_rng, BitIteratorLE, Field, UniformRand}; use r1cs_core::{ConstraintSystem, SynthesisError}; #[allow(dead_code)] @@ -303,13 +294,14 @@ pub(crate) mod tests { assert_eq!(a_b_inv.value()?, a_native * b_native.inverse().unwrap()); // a * a * a = a^3 - let bits = BitIterator::new([0x3]) + let bits = BitIteratorLE::without_trailing_zeros([3u64]) .map(Boolean::constant) .collect::>(); - assert_eq!(a_native.pow([0x3]), a.pow(&bits)?.value()?); + assert_eq!(a_native.pow([0x3]), a.pow_le(&bits)?.value()?); // a * a * a = a^3 - assert_eq!(a_native.pow([0x3]), a.pow_by_constant(&[3])?.value()?); + assert_eq!(a_native.pow([0x3]), a.pow_by_constant(&[0x3])?.value()?); + assert!(cs.is_satisfied().unwrap()); // a * a * a = a^3 let mut constants = [F::zero(); 4]; @@ -322,12 +314,34 @@ pub(crate) mod tests { ]; let lookup_result = AF::two_bit_lookup(&bits, constants.as_ref())?; assert_eq!(lookup_result.value()?, constants[2]); + assert!(cs.is_satisfied().unwrap()); + + let f = F::from(1u128 << 64); + let f_bits = algebra::BitIteratorLE::new(&[0u64, 1u64]).collect::>(); + let fv = AF::new_witness(cs.ns("alloc u128"), || Ok(f))?; + assert_eq!(fv.to_bits_le()?.value().unwrap()[..128], f_bits[..128]); + assert!(cs.is_satisfied().unwrap()); - let negone: F = UniformRand::rand(&mut test_rng()); + let r_native: F = UniformRand::rand(&mut test_rng()); - let n = AF::new_witness(cs.ns("alloc new var"), || Ok(negone)).unwrap(); - let _ = n.to_bytes()?; - let _ = n.to_non_unique_bytes()?; + let r = AF::new_witness(cs.ns("r_native"), || Ok(r_native)).unwrap(); + let _ = r.to_non_unique_bits_le()?; + assert!(cs.is_satisfied().unwrap()); + let _ = r.to_bits_le()?; + assert!(cs.is_satisfied().unwrap()); + + let bytes = r.to_non_unique_bytes()?; + assert_eq!( + algebra::to_bytes!(r_native).unwrap(), + bytes.value().unwrap() + ); + assert!(cs.is_satisfied().unwrap()); + let bytes = r.to_bytes()?; + assert_eq!( + algebra::to_bytes!(r_native).unwrap(), + bytes.value().unwrap() + ); + assert!(cs.is_satisfied().unwrap()); let ab_false = &a + (AF::from(Boolean::Constant(false)) * b_native); assert_eq!(ab_false.value()?, a_native); diff --git a/r1cs-std/src/fields/quadratic_extension.rs b/r1cs-std/src/fields/quadratic_extension.rs index 7b3db2d..8bdb282 100644 --- a/r1cs-std/src/fields/quadratic_extension.rs +++ b/r1cs-std/src/fields/quadratic_extension.rs @@ -379,16 +379,16 @@ where for<'b> &'b BF: FieldOpsBounds<'b, P::BaseField, BF>, P: QuadExtVarParams, { - fn to_bits(&self) -> Result>, SynthesisError> { - let mut c0 = self.c0.to_bits()?; - let mut c1 = self.c1.to_bits()?; + fn to_bits_le(&self) -> Result>, SynthesisError> { + let mut c0 = self.c0.to_bits_le()?; + let mut c1 = self.c1.to_bits_le()?; c0.append(&mut c1); Ok(c0) } - fn to_non_unique_bits(&self) -> Result>, SynthesisError> { - let mut c0 = self.c0.to_non_unique_bits()?; - let mut c1 = self.c1.to_non_unique_bits()?; + fn to_non_unique_bits_le(&self) -> Result>, SynthesisError> { + let mut c0 = self.c0.to_non_unique_bits_le()?; + let mut c1 = self.c1.to_non_unique_bits_le()?; c0.append(&mut c1); Ok(c0) } diff --git a/r1cs-std/src/groups/curves/short_weierstrass/bls12/mod.rs b/r1cs-std/src/groups/curves/short_weierstrass/bls12/mod.rs index d189d1e..bd73f18 100644 --- a/r1cs-std/src/groups/curves/short_weierstrass/bls12/mod.rs +++ b/r1cs-std/src/groups/curves/short_weierstrass/bls12/mod.rs @@ -4,7 +4,7 @@ use algebra::{ short_weierstrass_jacobian::GroupAffine, }, fields::Field, - BitIterator, One, + BitIteratorBE, One, }; use r1cs_core::SynthesisError; @@ -164,7 +164,7 @@ impl G2PreparedVar

{ let mut ell_coeffs = vec![]; let mut r = q.clone(); - for i in BitIterator::new(P::X).skip(1) { + for i in BitIteratorBE::new(P::X).skip(1) { ell_coeffs.push(Self::double(&mut r, &two_inv)?); if i { diff --git a/r1cs-std/src/groups/curves/short_weierstrass/mod.rs b/r1cs-std/src/groups/curves/short_weierstrass/mod.rs index c7bf7a7..b07d764 100644 --- a/r1cs-std/src/groups/curves/short_weierstrass/mod.rs +++ b/r1cs-std/src/groups/curves/short_weierstrass/mod.rs @@ -3,7 +3,7 @@ use algebra::{ short_weierstrass_jacobian::{GroupAffine as SWAffine, GroupProjective as SWProjective}, SWModelParameters, }, - AffineCurve, BigInteger, BitIterator, Field, One, PrimeField, ProjectiveCurve, Zero, + AffineCurve, BigInteger, BitIteratorBE, Field, One, PrimeField, ProjectiveCurve, Zero, }; use core::{borrow::Borrow, marker::PhantomData}; use r1cs_core::{ConstraintSystemRef, Namespace, SynthesisError}; @@ -255,22 +255,12 @@ where fn enforce_prime_order(&self) -> Result<(), SynthesisError> { let r_minus_1 = (-P::ScalarField::one()).into_repr(); - let mut seen_one = false; let mut result = Self::zero(); - for b in BitIterator::new(r_minus_1) { - let old_seen_one = seen_one; - if seen_one { - result.double_in_place()?; - } else { - seen_one = b; - } + for b in BitIteratorBE::without_leading_zeros(r_minus_1) { + result.double_in_place()?; if b { - result = if old_seen_one { - result + self - } else { - self.clone() - }; + result += self; } } self.negate()?.enforce_equal(&result)?; @@ -527,10 +517,12 @@ where power_of_2 += 1; } - let cofactor_weight = BitIterator::new(cofactor.as_slice()).filter(|b| *b).count(); + let cofactor_weight = BitIteratorBE::new(cofactor.as_slice()) + .filter(|b| *b) + .count(); let modulus_minus_1 = (-P::ScalarField::one()).into_repr(); // r - 1 let modulus_minus_1_weight = - BitIterator::new(modulus_minus_1).filter(|b| *b).count(); + BitIteratorBE::new(modulus_minus_1).filter(|b| *b).count(); // We pick the most efficient method of performing the prime order check: // If the cofactor has lower hamming weight than the scalar field's modulus, @@ -546,7 +538,10 @@ where || f().map(|g| g.borrow().into_affine().mul_by_cofactor_inv().into()), mode, )?; - (ge, BitIterator::new(cofactor.as_slice())) + ( + ge, + BitIteratorBE::without_leading_zeros(cofactor.as_slice()), + ) } else { let ge = Self::new_variable_omit_prime_order_check( cs.ns("Witness without subgroup check with `r` check"), @@ -555,37 +550,31 @@ where let g = g.into_affine(); let mut power_of_two = P::ScalarField::one().into_repr(); power_of_two.muln(power_of_2); - let power_of_two_inv = - P::ScalarField::from(power_of_two).inverse().unwrap(); + let power_of_two_inv = P::ScalarField::from_repr(power_of_two) + .and_then(|n| n.inverse()) + .unwrap(); g.mul(power_of_two_inv) }) }, mode, )?; - (ge, BitIterator::new(modulus_minus_1.as_ref())) + ( + ge, + BitIteratorBE::without_leading_zeros(modulus_minus_1.as_ref()), + ) }; // Remove the even part of the cofactor for _ in 0..power_of_2 { ge.double_in_place()?; } - let mut seen_one = false; let mut result = Self::zero(); for b in iter { - let old_seen_one = seen_one; - if seen_one { - result.double_in_place()?; - } else { - seen_one = b; - } + result.double_in_place()?; if b { - result = if old_seen_one { - result + &ge - } else { - ge.clone() - }; + result += &ge } } if cofactor_weight < modulus_minus_1_weight { @@ -616,23 +605,23 @@ where F: FieldVar::BasePrimeField>, for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, { - fn to_bits( + fn to_bits_le( &self, ) -> Result::BasePrimeField>>, SynthesisError> { let g = self.to_affine()?; - let mut bits = g.x.to_bits()?; - let y_bits = g.y.to_bits()?; + let mut bits = g.x.to_bits_le()?; + let y_bits = g.y.to_bits_le()?; bits.extend_from_slice(&y_bits); bits.push(g.infinity); Ok(bits) } - fn to_non_unique_bits( + fn to_non_unique_bits_le( &self, ) -> Result::BasePrimeField>>, SynthesisError> { let g = self.to_affine()?; - let mut bits = g.x.to_non_unique_bits()?; - let y_bits = g.y.to_non_unique_bits()?; + let mut bits = g.x.to_non_unique_bits_le()?; + let y_bits = g.y.to_non_unique_bits_le()?; bits.extend_from_slice(&y_bits); bits.push(g.infinity); Ok(bits) @@ -679,7 +668,7 @@ where for<'a> &'a GG: GroupOpsBounds<'a, SWProjective

, GG>, { use crate::prelude::*; - use algebra::{test_rng, Group, UniformRand}; + use algebra::{test_rng, BitIteratorLE, Group, UniformRand}; use r1cs_core::ConstraintSystem; crate::groups::test::group_test::, _, GG>()?; @@ -739,11 +728,9 @@ where let native_result = aa.into_affine().mul(scalar); let native_result = native_result.into_affine(); - let mut scalar: Vec = BitIterator::new(scalar.into_repr()).collect(); - // Get the scalar bits into little-endian form. - scalar.reverse(); + let scalar: Vec = BitIteratorLE::new(scalar.into_repr()).collect(); let input: Vec> = Vec::new_witness(cs.ns("bits"), || Ok(scalar)).unwrap(); - let result = gadget_a.mul_bits(input.iter())?; + let result = gadget_a.scalar_mul_le(input.iter())?; let result_val = result.value()?.into_affine(); assert_eq!( result_val, native_result, diff --git a/r1cs-std/src/groups/curves/twisted_edwards/mod.rs b/r1cs-std/src/groups/curves/twisted_edwards/mod.rs index ab13a45..c506fbb 100644 --- a/r1cs-std/src/groups/curves/twisted_edwards/mod.rs +++ b/r1cs-std/src/groups/curves/twisted_edwards/mod.rs @@ -3,7 +3,7 @@ use algebra::{ twisted_edwards_extended::{GroupAffine as TEAffine, GroupProjective as TEProjective}, AffineCurve, MontgomeryModelParameters, ProjectiveCurve, TEModelParameters, }, - BigInteger, BitIterator, Field, One, PrimeField, Zero, + BigInteger, BitIteratorBE, Field, One, PrimeField, Zero, }; use r1cs_core::{ConstraintSystemRef, Namespace, SynthesisError}; @@ -328,22 +328,12 @@ where fn enforce_prime_order(&self) -> Result<(), SynthesisError> { let r_minus_1 = (-P::ScalarField::one()).into_repr(); - let mut seen_one = false; let mut result = Self::zero(); - for b in BitIterator::new(r_minus_1) { - let old_seen_one = seen_one; - if seen_one { - result.double_in_place()?; - } else { - seen_one = b; - } + for b in BitIteratorBE::without_leading_zeros(r_minus_1) { + result.double_in_place()?; if b { - result = if old_seen_one { - result + self - } else { - self.clone() - }; + result += self; } } self.negate()?.enforce_equal(&result)?; @@ -398,7 +388,7 @@ where Ok(Self::new(self.x.negate()?, self.y.clone())) } - fn precomputed_base_scalar_mul<'a, I, B>( + fn precomputed_base_scalar_mul_le<'a, I, B>( &mut self, scalar_bits_with_base_powers: I, ) -> Result<(), SynthesisError> @@ -477,7 +467,7 @@ where acc_power += base_power; } - let bits = bits.borrow().to_bits()?; + let bits = bits.borrow().to_bits_le()?; if bits.len() != CHUNK_SIZE { return Err(SynthesisError::Unsatisfiable); } @@ -552,10 +542,12 @@ where power_of_2 += 1; } - let cofactor_weight = BitIterator::new(cofactor.as_slice()).filter(|b| *b).count(); + let cofactor_weight = BitIteratorBE::new(cofactor.as_slice()) + .filter(|b| *b) + .count(); let modulus_minus_1 = (-P::ScalarField::one()).into_repr(); // r - 1 let modulus_minus_1_weight = - BitIterator::new(modulus_minus_1).filter(|b| *b).count(); + BitIteratorBE::new(modulus_minus_1).filter(|b| *b).count(); // We pick the most efficient method of performing the prime order check: // If the cofactor has lower hamming weight than the scalar field's modulus, @@ -571,7 +563,10 @@ where || f().map(|g| g.borrow().into_affine().mul_by_cofactor_inv().into()), mode, )?; - (ge, BitIterator::new(cofactor.as_slice())) + ( + ge, + BitIteratorBE::without_leading_zeros(cofactor.as_slice()), + ) } else { let ge = Self::new_variable_omit_prime_order_check( cs.ns("Witness without subgroup check with `r` check"), @@ -580,37 +575,30 @@ where let g = g.into_affine(); let mut power_of_two = P::ScalarField::one().into_repr(); power_of_two.muln(power_of_2); - let power_of_two_inv = - P::ScalarField::from(power_of_two).inverse().unwrap(); + let power_of_two_inv = P::ScalarField::from_repr(power_of_two) + .and_then(|n| n.inverse()) + .unwrap(); g.mul(power_of_two_inv) }) }, mode, )?; - (ge, BitIterator::new(modulus_minus_1.as_ref())) + ( + ge, + BitIteratorBE::without_leading_zeros(modulus_minus_1.as_ref()), + ) }; // Remove the even part of the cofactor for _ in 0..power_of_2 { ge.double_in_place()?; } - let mut seen_one = false; let mut result = Self::zero(); for b in iter { - let old_seen_one = seen_one; - if seen_one { - result.double_in_place()?; - } else { - seen_one = b; - } - + result.double_in_place()?; if b { - result = if old_seen_one { - result + &ge - } else { - ge.clone() - }; + result += ≥ } } if cofactor_weight < modulus_minus_1_weight { @@ -829,20 +817,20 @@ where F: FieldVar::BasePrimeField>, for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>, { - fn to_bits( + fn to_bits_le( &self, ) -> Result::BasePrimeField>>, SynthesisError> { - let mut x_bits = self.x.to_bits()?; - let y_bits = self.y.to_bits()?; + let mut x_bits = self.x.to_bits_le()?; + let y_bits = self.y.to_bits_le()?; x_bits.extend_from_slice(&y_bits); Ok(x_bits) } - fn to_non_unique_bits( + fn to_non_unique_bits_le( &self, ) -> Result::BasePrimeField>>, SynthesisError> { - let mut x_bits = self.x.to_non_unique_bits()?; - let y_bits = self.y.to_non_unique_bits()?; + let mut x_bits = self.x.to_non_unique_bits_le()?; + let y_bits = self.y.to_non_unique_bits_le()?; x_bits.extend_from_slice(&y_bits); Ok(x_bits) @@ -884,7 +872,7 @@ where for<'a> &'a GG: GroupOpsBounds<'a, TEProjective

, GG>, { use crate::prelude::*; - use algebra::{test_rng, Group, UniformRand}; + use algebra::{test_rng, BitIteratorLE, Group, UniformRand}; use r1cs_core::ConstraintSystem; crate::groups::test::group_test::, _, GG>()?; @@ -944,11 +932,9 @@ where let native_result = AffineCurve::mul(&aa.into_affine(), scalar); let native_result = native_result.into_affine(); - let mut scalar: Vec = BitIterator::new(scalar.into_repr()).collect(); - // Get the scalar bits into little-endian form. - scalar.reverse(); + let scalar: Vec = BitIteratorLE::new(scalar.into_repr()).collect(); let input: Vec> = Vec::new_witness(cs.ns("bits"), || Ok(scalar)).unwrap(); - let result = gadget_a.mul_bits(input.iter())?; + let result = gadget_a.scalar_mul_le(input.iter())?; let result_val = result.value()?.into_affine(); assert_eq!( result_val, native_result, diff --git a/r1cs-std/src/groups/mod.rs b/r1cs-std/src/groups/mod.rs index b3b3290..fbe398a 100644 --- a/r1cs-std/src/groups/mod.rs +++ b/r1cs-std/src/groups/mod.rs @@ -72,24 +72,28 @@ pub trait CurveVar: fn negate(&self) -> Result; - /// Inputs must be specified in *little-endian* form. - /// If the addition law is incomplete for the identity element, - /// `result` must not be the identity element. - fn mul_bits<'a>( + /// Computes `bits * self`, where `bits` is a little-endian + /// `Boolean` representation of a scalar. + fn scalar_mul_le<'a>( &self, bits: impl Iterator>, ) -> Result { - let mut power = self.clone(); - let mut result = Self::zero(); + let mut res = Self::zero(); + let mut multiple = self.clone(); for bit in bits { - let new_encoded = result.clone() + &power; - result = bit.borrow().select(&new_encoded, &result)?; - power.double_in_place()?; + let tmp = res.clone() + &multiple; + res = bit.select(&tmp, &res)?; + multiple.double_in_place()?; } - Ok(result) + Ok(res) } - fn precomputed_base_scalar_mul<'a, I, B>( + /// Computes a `I * self` in place, where `I` is a `Boolean` *little-endian* + /// representation of the scalar. + /// + /// The base powers are precomputed power-of-two multiples of a single + /// base. + fn precomputed_base_scalar_mul_le<'a, I, B>( &mut self, scalar_bits_with_base_powers: I, ) -> Result<(), SynthesisError> @@ -117,7 +121,9 @@ pub trait CurveVar: Err(SynthesisError::AssignmentMissing) } - fn precomputed_base_multiscalar_mul<'a, T, I, B>( + /// Computes a `\sum I_j * B_j`, where `I_j` is a `Boolean` + /// representation of the j-th scalar. + fn precomputed_base_multiscalar_mul_le<'a, T, I, B>( bases: &[B], scalars: I, ) -> Result @@ -130,8 +136,8 @@ pub trait CurveVar: // Compute ∏(h_i^{m_i}) for all i. for (bits, base_powers) in scalars.zip(bases) { let base_powers = base_powers.borrow(); - let bits = bits.to_bits()?; - result.precomputed_base_scalar_mul(bits.iter().zip(base_powers))?; + let bits = bits.to_bits_le()?; + result.precomputed_base_scalar_mul_le(bits.iter().zip(base_powers))?; } Ok(result) } @@ -201,7 +207,9 @@ mod test { assert_eq!(b2.value()?, b_b.value()?); let _ = a.to_bytes()?; + assert!(cs.is_satisfied().unwrap()); let _ = a.to_non_unique_bytes()?; + assert!(cs.is_satisfied().unwrap()); let _ = b.to_bytes()?; let _ = b.to_non_unique_bytes()?; diff --git a/r1cs-std/src/pairing/bls12/mod.rs b/r1cs-std/src/pairing/bls12/mod.rs index f3b662a..7e6d7df 100644 --- a/r1cs-std/src/pairing/bls12/mod.rs +++ b/r1cs-std/src/pairing/bls12/mod.rs @@ -8,7 +8,7 @@ use crate::{ }; use algebra::{ curves::bls12::{Bls12, Bls12Parameters, TwistType}, - fields::BitIterator, + fields::BitIteratorBE, }; use core::marker::PhantomData; @@ -75,7 +75,7 @@ impl PG, P::Fp> for PairingVar

{ } let mut f = Self::GTVar::one(); - for i in BitIterator::new(P::X).skip(1) { + for i in BitIteratorBE::new(P::X).skip(1) { f.square_in_place()?; for &mut (p, ref mut coeffs) in pairs.iter_mut() { diff --git a/r1cs-std/src/pairing/mnt4/mod.rs b/r1cs-std/src/pairing/mnt4/mod.rs index 5b9b448..83646a9 100644 --- a/r1cs-std/src/pairing/mnt4/mod.rs +++ b/r1cs-std/src/pairing/mnt4/mod.rs @@ -11,7 +11,7 @@ use crate::{ }; use algebra::{ curves::mnt4::{MNT4Parameters, MNT4}, - fields::BitIterator, + fields::BitIteratorBE, }; use core::marker::PhantomData; @@ -100,18 +100,9 @@ impl PairingVar

{ let mut dbl_idx: usize = 0; let mut add_idx: usize = 0; - let mut found_one = false; - - for bit in BitIterator::new(P::ATE_LOOP_COUNT) { - // code below gets executed for all bits (EXCEPT the MSB itself) of - // mnt6_param_p (skipping leading zeros) in MSB to LSB order - if !found_one && bit { - found_one = true; - continue; - } else if !found_one { - continue; - } - + // code below gets executed for all bits (EXCEPT the MSB itself) of + // mnt6_param_p (skipping leading zeros) in MSB to LSB order + for bit in BitIteratorBE::without_leading_zeros(P::ATE_LOOP_COUNT).skip(1) { let dc = &q.double_coefficients[dbl_idx]; dbl_idx += 1; diff --git a/r1cs-std/src/pairing/mnt6/mod.rs b/r1cs-std/src/pairing/mnt6/mod.rs index 7d1a1ce..4f0bb84 100644 --- a/r1cs-std/src/pairing/mnt6/mod.rs +++ b/r1cs-std/src/pairing/mnt6/mod.rs @@ -11,7 +11,7 @@ use crate::{ }; use algebra::{ curves::mnt6::{MNT6Parameters, MNT6}, - fields::BitIterator, + fields::BitIteratorBE, }; use core::marker::PhantomData; @@ -96,18 +96,9 @@ impl PairingVar

{ let mut dbl_idx: usize = 0; let mut add_idx: usize = 0; - let mut found_one = false; - - for bit in BitIterator::new(P::ATE_LOOP_COUNT) { - // code below gets executed for all bits (EXCEPT the MSB itself) of - // mnt6_param_p (skipping leading zeros) in MSB to LSB order - if !found_one && bit { - found_one = true; - continue; - } else if !found_one { - continue; - } - + // code below gets executed for all bits (EXCEPT the MSB itself) of + // mnt6_param_p (skipping leading zeros) in MSB to LSB order + for bit in BitIteratorBE::without_leading_zeros(P::ATE_LOOP_COUNT).skip(1) { let dc = &q.double_coefficients[dbl_idx]; dbl_idx += 1; diff --git a/r1cs-std/src/pairing/mod.rs b/r1cs-std/src/pairing/mod.rs index 7a6b97a..6be2daf 100644 --- a/r1cs-std/src/pairing/mod.rs +++ b/r1cs-std/src/pairing/mod.rs @@ -60,7 +60,7 @@ pub trait PairingVar pub(crate) mod tests { use crate::{prelude::*, Vec}; use algebra::{ - test_rng, BitIterator, Field, PairingEngine, PrimeField, ProjectiveCurve, UniformRand, + test_rng, BitIteratorLE, Field, PairingEngine, PrimeField, ProjectiveCurve, UniformRand, }; use r1cs_core::{ConstraintSystem, SynthesisError}; @@ -125,14 +125,14 @@ pub(crate) mod tests { }; let (ans3_g, ans3_n) = { - let s_iter = BitIterator::new(s.into_repr()) + let s_iter = BitIteratorLE::without_trailing_zeros(s.into_repr()) .map(Boolean::constant) .collect::>(); let mut ans_g = P::pairing(a_prep_g, b_prep_g)?; let mut ans_n = E::pairing(a, b); ans_n = ans_n.pow(s.into_repr()); - ans_g = ans_g.pow(&s_iter)?; + ans_g = ans_g.pow_le(&s_iter)?; (ans_g, ans_n) };