diff --git a/src/circuit/sapling/mod.rs b/src/circuit/sapling/mod.rs index 840ad9f..159381f 100644 --- a/src/circuit/sapling/mod.rs +++ b/src/circuit/sapling/mod.rs @@ -82,7 +82,7 @@ fn expose_value_commitment( CS: ConstraintSystem { // Booleanize the value into little-endian bit order - let mut value_bits = boolean::u64_into_boolean_vec_le( + let value_bits = boolean::u64_into_boolean_vec_le( cs.namespace(|| "value"), value_commitment.as_ref().map(|c| c.value) )?; @@ -121,9 +121,6 @@ fn expose_value_commitment( // Expose the commitment as an input to the circuit cv.inputize(cs.namespace(|| "commitment point"))?; - // Reorder value_bits so that it's big-endian - value_bits.reverse(); - Ok(value_bits) } @@ -624,7 +621,7 @@ fn test_input_circuit_with_bls12_381() { assert!(cs.is_satisfied()); assert_eq!(cs.num_constraints(), 98776); - assert_eq!(cs.hash(), "2080d5f350cd7eff7742ab05dff18f82c0a2f29a5d2a758d805236067b2ed31f"); + assert_eq!(cs.hash(), "ba8b2232a910b00399e90030c87c16a770e6e692fe3b4316675bdd7795df6e50"); assert_eq!(cs.num_inputs(), 8); assert_eq!(cs.get_input(0, "ONE"), Fr::one()); @@ -752,7 +749,7 @@ fn test_output_circuit_with_bls12_381() { assert!(cs.is_satisfied()); assert_eq!(cs.num_constraints(), 7827); - assert_eq!(cs.hash(), "a7810a444f7ef6d0caa8ba026ce06e64654863cd0557241282ca337858039a53"); + assert_eq!(cs.hash(), "8db50ff0e14fae19a7d83ef47f6da3a7e3e2644d251e37b387c6408d85df3ae7"); let expected_cm = payment_address.create_note( value_commitment.value, diff --git a/src/jubjub/edwards.rs b/src/jubjub/edwards.rs index e4f5e85..d1d2772 100644 --- a/src/jubjub/edwards.rs +++ b/src/jubjub/edwards.rs @@ -26,6 +26,8 @@ use std::io::{ Read }; +use util::swap_bits_u64; + // Represents the affine point (X/Z, Y/Z) via the extended // twisted Edwards coordinates. // @@ -89,34 +91,6 @@ impl PartialEq for Point { } } -fn swap_bits_u64(x: u64) -> u64 -{ - let mut tmp = 0; - for i in 0..64 { - tmp |= ((x >> i) & 1) << (63 - i); - } - tmp -} - -#[test] -fn test_swap_bits_u64() { - assert_eq!(swap_bits_u64(17182120934178543809), 0b1000001100011011110000011000111000101111111001001100111001110111); - assert_eq!(swap_bits_u64(15135675916470734665), 0b1001001011110010001101010010001110110000100111010011000001001011); - assert_eq!(swap_bits_u64(6724233301461108393), 0b1001010101100000100011100001010111110001011000101000101010111010); - assert_eq!(swap_bits_u64(206708183275952289), 0b1000010100011010001010100011101011111111111110100111101101000000); - assert_eq!(swap_bits_u64(12712751566144824320), 0b0000000000100110010110111000001110001100001000110011011000001101); - - let mut a = 15863238721320035327u64; - for _ in 0..1000 { - a = a.wrapping_mul(a); - - let swapped = swap_bits_u64(a); - let unswapped = swap_bits_u64(swapped); - - assert_eq!(a, unswapped); - } -} - impl Point { pub fn read( reader: R, diff --git a/src/lib.rs b/src/lib.rs index 0f5fded..a053dd1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,3 +15,4 @@ pub mod circuit; pub mod pedersen_hash; pub mod primitives; pub mod constants; +mod util; diff --git a/src/primitives/mod.rs b/src/primitives/mod.rs index bb1298b..d631eea 100644 --- a/src/primitives/mod.rs +++ b/src/primitives/mod.rs @@ -28,6 +28,8 @@ use jubjub::{ use blake2_rfc::blake2s::Blake2s; +use util::swap_bits_u64; + #[derive(Clone)] pub struct ValueCommitment { pub value: u64, @@ -193,8 +195,13 @@ impl Note { // Calculate the note contents, as bytes let mut note_contents = vec![]; - // Write the value in big endian - (&mut note_contents).write_u64::(self.value).unwrap(); + // Write the value in little-endian bit order + // swapping the bits to ensure the order is + // correct (LittleEndian byte order would + // be incorrect here.) + (&mut note_contents).write_u64::( + swap_bits_u64(self.value) + ).unwrap(); // Write g_d self.g_d.write(&mut note_contents).unwrap(); diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 0000000..5291fef --- /dev/null +++ b/src/util.rs @@ -0,0 +1,27 @@ +pub fn swap_bits_u64(x: u64) -> u64 +{ + let mut tmp = 0; + for i in 0..64 { + tmp |= ((x >> i) & 1) << (63 - i); + } + tmp +} + +#[test] +fn test_swap_bits_u64() { + assert_eq!(swap_bits_u64(17182120934178543809), 0b1000001100011011110000011000111000101111111001001100111001110111); + assert_eq!(swap_bits_u64(15135675916470734665), 0b1001001011110010001101010010001110110000100111010011000001001011); + assert_eq!(swap_bits_u64(6724233301461108393), 0b1001010101100000100011100001010111110001011000101000101010111010); + assert_eq!(swap_bits_u64(206708183275952289), 0b1000010100011010001010100011101011111111111110100111101101000000); + assert_eq!(swap_bits_u64(12712751566144824320), 0b0000000000100110010110111000001110001100001000110011011000001101); + + let mut a = 15863238721320035327u64; + for _ in 0..1000 { + a = a.wrapping_mul(a); + + let swapped = swap_bits_u64(a); + let unswapped = swap_bits_u64(swapped); + + assert_eq!(a, unswapped); + } +}