From 543f5cd49c6cab469cbafc6f2b9d714d5bdb385d Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Mon, 5 Mar 2018 10:27:14 -0700 Subject: [PATCH] Change bit-endianness of into_bits/into_bits_strict. --- src/circuit/boolean.rs | 28 +++++++++++++++------------- src/circuit/ecc.rs | 8 ++------ src/circuit/mod.rs | 28 +++++++++++----------------- src/circuit/num.rs | 17 +++++++++++++---- 4 files changed, 41 insertions(+), 40 deletions(-) diff --git a/src/circuit/boolean.rs b/src/circuit/boolean.rs index 9209773..6da5398 100644 --- a/src/circuit/boolean.rs +++ b/src/circuit/boolean.rs @@ -301,11 +301,12 @@ pub fn u64_into_boolean_vec_le>( Ok(bits) } -pub fn field_into_allocated_bits_be, F: PrimeField>( +pub fn field_into_allocated_bits_le, F: PrimeField>( mut cs: CS, value: Option ) -> Result, SynthesisError> { + // Deconstruct in big-endian bit order let values = match value { Some(ref value) => { let mut field_char = BitIterator::new(F::char()); @@ -332,7 +333,8 @@ pub fn field_into_allocated_bits_be, F: Prime } }; - let bits = values.into_iter().enumerate().map(|(i, b)| { + // Allocate in little-endian order + let bits = values.into_iter().rev().enumerate().map(|(i, b)| { AllocatedBit::alloc( cs.namespace(|| format!("bit {}", i)), b @@ -512,7 +514,7 @@ mod test { use super::{ AllocatedBit, Boolean, - field_into_allocated_bits_be, + field_into_allocated_bits_le, u64_into_boolean_vec_le }; @@ -1003,24 +1005,24 @@ mod test { } #[test] - fn test_field_into_allocated_bits_be() { + fn test_field_into_allocated_bits_le() { let mut cs = TestConstraintSystem::::new(); let r = Fr::from_str("9147677615426976802526883532204139322118074541891858454835346926874644257775").unwrap(); - let bits = field_into_allocated_bits_be(&mut cs, Some(r)).unwrap(); + let bits = field_into_allocated_bits_le(&mut cs, Some(r)).unwrap(); assert!(cs.is_satisfied()); assert_eq!(bits.len(), 255); - assert_eq!(bits[0].value.unwrap(), false); - assert_eq!(bits[1].value.unwrap(), false); - assert_eq!(bits[2].value.unwrap(), true); - assert_eq!(bits[3].value.unwrap(), false); - assert_eq!(bits[4].value.unwrap(), true); - assert_eq!(bits[5].value.unwrap(), false); - assert_eq!(bits[20].value.unwrap(), true); - assert_eq!(bits[23].value.unwrap(), true); + assert_eq!(bits[254 - 0].value.unwrap(), false); + assert_eq!(bits[254 - 1].value.unwrap(), false); + assert_eq!(bits[254 - 2].value.unwrap(), true); + assert_eq!(bits[254 - 3].value.unwrap(), false); + assert_eq!(bits[254 - 4].value.unwrap(), true); + assert_eq!(bits[254 - 5].value.unwrap(), false); + assert_eq!(bits[254 - 20].value.unwrap(), true); + assert_eq!(bits[254 - 23].value.unwrap(), true); } } diff --git a/src/circuit/ecc.rs b/src/circuit/ecc.rs index 7642db4..3e84ede 100644 --- a/src/circuit/ecc.rs +++ b/src/circuit/ecc.rs @@ -105,18 +105,14 @@ impl EdwardsPoint { { let mut tmp = vec![]; - let mut x = self.x.into_bits_strict( + let x = self.x.into_bits_strict( cs.namespace(|| "unpack x") )?; - let mut y = self.y.into_bits_strict( + let y = self.y.into_bits_strict( cs.namespace(|| "unpack y") )?; - // We want the representation in little endian bit order - x.reverse(); - y.reverse(); - tmp.extend(y); tmp.push(x[0].clone()); diff --git a/src/circuit/mod.rs b/src/circuit/mod.rs index 093aa9d..9f8e1d2 100644 --- a/src/circuit/mod.rs +++ b/src/circuit/mod.rs @@ -81,12 +81,11 @@ impl<'a, E: JubjubEngine> Circuit for Spend<'a, E> { )?; // Booleanize the randomness - let hr = boolean::field_into_allocated_bits_be( + let hr = boolean::field_into_allocated_bits_le( cs.namespace(|| "hr"), self.value_randomness )? .into_iter() - .rev() // Little endian bit order .map(|e| boolean::Boolean::from(e)) .collect::>(); @@ -110,13 +109,13 @@ impl<'a, E: JubjubEngine> Circuit for Spend<'a, E> { let rk; { // Witness rsk as bits - let rsk = boolean::field_into_allocated_bits_be( + let rsk = boolean::field_into_allocated_bits_le( cs.namespace(|| "rsk"), self.rsk )? .into_iter() - .rev() // We need it in little endian bit order - .map(|e| boolean::Boolean::from(e)).collect::>(); + .map(|e| boolean::Boolean::from(e)) + .collect::>(); // NB: We don't ensure that the bit representation of rsk // is "in the field" (Fs) because it's not used except to @@ -206,12 +205,11 @@ impl<'a, E: JubjubEngine> Circuit for Spend<'a, E> { { // Booleanize the randomness - let cmr = boolean::field_into_allocated_bits_be( + let cmr = boolean::field_into_allocated_bits_le( cs.namespace(|| "cmr"), self.commitment_randomness )? .into_iter() - .rev() // We need it in little endian bit order .map(|e| boolean::Boolean::from(e)) .collect::>(); @@ -358,12 +356,11 @@ impl<'a, E: JubjubEngine> Circuit for Output<'a, E> { )?; // Booleanize the randomness - let hr = boolean::field_into_allocated_bits_be( + let hr = boolean::field_into_allocated_bits_le( cs.namespace(|| "hr"), self.value_randomness )? .into_iter() - .rev() // Little endian bit order .map(|e| boolean::Boolean::from(e)) .collect::>(); @@ -422,12 +419,11 @@ impl<'a, E: JubjubEngine> Circuit for Output<'a, E> { ); // Compute epk from esk - let esk = boolean::field_into_allocated_bits_be( + let esk = boolean::field_into_allocated_bits_le( cs.namespace(|| "esk"), self.esk )? .into_iter() - .rev() // We need it in little endian bit order .map(|e| boolean::Boolean::from(e)) .collect::>(); @@ -446,12 +442,11 @@ impl<'a, E: JubjubEngine> Circuit for Output<'a, E> { { let p_d = self.p_d.map(|e| e.into_xy()); - let y_contents = boolean::field_into_allocated_bits_be( + let y_contents = boolean::field_into_allocated_bits_le( cs.namespace(|| "p_d bits of y"), p_d.map(|e| e.1) )? .into_iter() - .rev() // We need it in little endian bit order .map(|e| boolean::Boolean::from(e)) .collect::>(); @@ -481,12 +476,11 @@ impl<'a, E: JubjubEngine> Circuit for Output<'a, E> { { // Booleanize the randomness - let cmr = boolean::field_into_allocated_bits_be( + let cmr = boolean::field_into_allocated_bits_le( cs.namespace(|| "cmr"), self.commitment_randomness )? .into_iter() - .rev() // We need it in little endian bit order .map(|e| boolean::Boolean::from(e)) .collect::>(); @@ -552,7 +546,7 @@ fn test_input_circuit_with_bls12_381() { assert!(cs.is_satisfied()); assert_eq!(cs.num_constraints(), 97379); - assert_eq!(cs.hash(), "a3ac418bbbe38d08295995c8cdcaebd6902fcfa9e4f7212c9742ed033c1edec3"); + assert_eq!(cs.hash(), "db283e10d01d6c3c4d23cd3c05a7ae8f1a7d8091a39f8d8b604e610ca6a3e496"); } } @@ -590,6 +584,6 @@ fn test_output_circuit_with_bls12_381() { assert!(cs.is_satisfied()); assert_eq!(cs.num_constraints(), 7827); - assert_eq!(cs.hash(), "b74e3ee749e1cbc405b5b4a1de3b11119084afda9b6f5e3a6865cbcc5c35e3d4"); + assert_eq!(cs.hash(), "ccb2ad9a6d492e708da155305064a3b8af5d29b4b766cf08ac415a478aae4cc6"); } } diff --git a/src/circuit/num.rs b/src/circuit/num.rs index 48f1fda..1325e90 100644 --- a/src/circuit/num.rs +++ b/src/circuit/num.rs @@ -83,6 +83,11 @@ impl AllocatedNum { Ok(()) } + /// Deconstructs this allocated number into its + /// boolean representation in little-endian bit + /// order, requiring that the representation + /// strictly exists "in the field" (i.e., a + /// congruency is not allowed.) pub fn into_bits_strict( &self, mut cs: CS @@ -208,16 +213,20 @@ impl AllocatedNum { |_| lc ); - Ok(result.into_iter().map(|b| Boolean::from(b)).collect()) + // Convert into booleans, and reverse for little-endian bit order + Ok(result.into_iter().map(|b| Boolean::from(b)).rev().collect()) } + /// Convert the allocated number into its little-endian representation. + /// Note that this does not strongly enforce that the commitment is + /// "in the field." pub fn into_bits( &self, mut cs: CS ) -> Result, SynthesisError> where CS: ConstraintSystem { - let bits = boolean::field_into_allocated_bits_be( + let bits = boolean::field_into_allocated_bits_le( &mut cs, self.value )?; @@ -225,7 +234,7 @@ impl AllocatedNum { let mut lc = LinearCombination::zero(); let mut coeff = E::Fr::one(); - for bit in bits.iter().rev() { + for bit in bits.iter() { lc = lc + (coeff, bit.get_variable()); coeff.double(); @@ -585,7 +594,7 @@ mod test { assert!(cs.is_satisfied()); - for (b, a) in BitIterator::new(r.into_repr()).skip(1).zip(bits.iter()) { + for (b, a) in BitIterator::new(r.into_repr()).skip(1).zip(bits.iter().rev()) { if let &Boolean::Is(ref a) = a { assert_eq!(b, a.get_value().unwrap()); } else {