Use little endian for everything in Sapling.
This commit is contained in:
parent
f491e02b56
commit
2ff318eecb
|
@ -45,6 +45,13 @@ pub fn bytes_to_bits(bytes: &[u8]) -> Vec<bool>
|
|||
.collect()
|
||||
}
|
||||
|
||||
pub fn bytes_to_bits_le(bytes: &[u8]) -> Vec<bool>
|
||||
{
|
||||
bytes.iter()
|
||||
.flat_map(|&v| (0..8).map(move |i| (v >> i) & 1 == 1))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn compute_multipacking<E: Engine>(
|
||||
bits: &[bool]
|
||||
) -> Vec<E::Fr>
|
||||
|
|
|
@ -226,11 +226,6 @@ impl<'a, E: JubjubEngine> Circuit<E> for Spend<'a, E> {
|
|||
constants::CRH_IVK_PERSONALIZATION
|
||||
)?;
|
||||
|
||||
// Swap bit-endianness in each byte
|
||||
for ivk_byte in ivk.chunks_mut(8) {
|
||||
ivk_byte.reverse();
|
||||
}
|
||||
|
||||
// drop_5 to ensure it's in the field
|
||||
ivk.truncate(E::Fs::CAPACITY as usize);
|
||||
|
||||
|
@ -697,7 +692,7 @@ fn test_input_circuit_with_bls12_381() {
|
|||
}
|
||||
|
||||
let expected_nf = note.nf(&viewing_key, position, params);
|
||||
let expected_nf = multipack::bytes_to_bits(&expected_nf);
|
||||
let expected_nf = multipack::bytes_to_bits_le(&expected_nf);
|
||||
let expected_nf = multipack::compute_multipacking::<Bls12>(&expected_nf);
|
||||
assert_eq!(expected_nf.len(), 2);
|
||||
|
||||
|
@ -718,7 +713,7 @@ fn test_input_circuit_with_bls12_381() {
|
|||
|
||||
assert!(cs.is_satisfied());
|
||||
assert_eq!(cs.num_constraints(), 98777);
|
||||
assert_eq!(cs.hash(), "499305e409599a3e4fe0a885f6adf674e9f49ba4a21e47362356d2a89f15dc1f");
|
||||
assert_eq!(cs.hash(), "d37c738e83df5d9b0bb6495ac96abf21bcb2697477e2c15c2c7916ff7a3b6a89");
|
||||
|
||||
assert_eq!(cs.get("randomization of note commitment/x3/num"), cm);
|
||||
|
||||
|
@ -795,7 +790,7 @@ fn test_output_circuit_with_bls12_381() {
|
|||
|
||||
assert!(cs.is_satisfied());
|
||||
assert_eq!(cs.num_constraints(), 7827);
|
||||
assert_eq!(cs.hash(), "d18e83255220328a688134038ba4f82d5ce67ffe9f97b2ae2678042da0efad43");
|
||||
assert_eq!(cs.hash(), "c26d5cdfe6ccd65c03390902c02e11393ea6bb96aae32a7f2ecb12eb9103faee");
|
||||
|
||||
let expected_cm = payment_address.create_note(
|
||||
value_commitment.value,
|
||||
|
|
|
@ -5,8 +5,7 @@ use jubjub::{
|
|||
};
|
||||
|
||||
use pairing::{
|
||||
PrimeField,
|
||||
PrimeFieldRepr
|
||||
PrimeField
|
||||
};
|
||||
|
||||
use blake2_rfc::blake2s::Blake2s;
|
||||
|
@ -29,20 +28,11 @@ pub fn group_hash<E: JubjubEngine>(
|
|||
let mut h = Blake2s::with_params(32, &[], &[], personalization);
|
||||
h.update(constants::GH_FIRST_BLOCK);
|
||||
h.update(tag);
|
||||
let mut h = h.finalize().as_ref().to_vec();
|
||||
let h = h.finalize().as_ref().to_vec();
|
||||
assert!(h.len() == 32);
|
||||
|
||||
// Take first/unset first bit of hash
|
||||
let s = h[0] >> 7 == 1; // get s
|
||||
h[0] &= 0b0111_1111; // unset s from h
|
||||
|
||||
// cast to prime field representation
|
||||
let mut y0 = <E::Fr as PrimeField>::Repr::default();
|
||||
y0.read_be(&h[..]).expect("hash is sufficiently large");
|
||||
|
||||
if let Ok(y0) = E::Fr::from_repr(y0) {
|
||||
if let Some(p) = edwards::Point::<E, _>::get_for_y(y0, s, params) {
|
||||
// Enter into the prime order subgroup
|
||||
match edwards::Point::<E, _>::read(&h[..], params) {
|
||||
Ok(p) => {
|
||||
let p = p.mul_by_cofactor(params);
|
||||
|
||||
if p != edwards::Point::zero() {
|
||||
|
@ -50,10 +40,7 @@ pub fn group_hash<E: JubjubEngine>(
|
|||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
},
|
||||
Err(_) => None
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,8 +26,6 @@ use std::io::{
|
|||
Read
|
||||
};
|
||||
|
||||
use util::swap_bits_u64;
|
||||
|
||||
// Represents the affine point (X/Z, Y/Z) via the extended
|
||||
// twisted Edwards coordinates.
|
||||
//
|
||||
|
@ -97,21 +95,8 @@ impl<E: JubjubEngine> Point<E, Unknown> {
|
|||
params: &E::Params
|
||||
) -> io::Result<Self>
|
||||
{
|
||||
// Jubjub points are encoded least significant bit first.
|
||||
// The most significant bit (bit 254) encodes the parity
|
||||
// of the x-coordinate.
|
||||
|
||||
let mut y_repr = <E::Fr as PrimeField>::Repr::default();
|
||||
|
||||
// This reads in big-endian, so we perform a swap of the
|
||||
// limbs in the representation and swap the bit order.
|
||||
y_repr.read_be(reader)?;
|
||||
|
||||
y_repr.as_mut().reverse();
|
||||
|
||||
for b in y_repr.as_mut() {
|
||||
*b = swap_bits_u64(*b);
|
||||
}
|
||||
y_repr.read_le(reader)?;
|
||||
|
||||
let x_sign = (y_repr.as_ref()[3] >> 63) == 1;
|
||||
y_repr.as_mut()[3] &= 0x7fffffffffffffff;
|
||||
|
@ -216,13 +201,7 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
|||
y_repr.as_mut()[3] |= 0x8000000000000000u64;
|
||||
}
|
||||
|
||||
y_repr.as_mut().reverse();
|
||||
|
||||
for b in y_repr.as_mut() {
|
||||
*b = swap_bits_u64(*b);
|
||||
}
|
||||
|
||||
y_repr.write_be(writer)
|
||||
y_repr.write_le(writer)
|
||||
}
|
||||
|
||||
/// Convert from a Montgomery point
|
||||
|
|
|
@ -363,7 +363,7 @@ fn test_jubjub_bls12() {
|
|||
|
||||
tests::test_suite::<Bls12>(¶ms);
|
||||
|
||||
let test_repr = hex!("b9481dd1103b7d1f8578078eb429d3c476472f53e88c0eaefdf51334c7c8b98c");
|
||||
let test_repr = hex!("9d12b88b08dcbef8a11ee0712d94cb236ee2f4ca17317075bfafc82ce3139d31");
|
||||
let p = edwards::Point::<Bls12, _>::read(&test_repr[..], ¶ms).unwrap();
|
||||
let q = edwards::Point::<Bls12, _>::get_for_y(
|
||||
Fr::from_str("22440861827555040311190986994816762244378363690614952020532787748720529117853").unwrap(),
|
||||
|
@ -372,4 +372,15 @@ fn test_jubjub_bls12() {
|
|||
).unwrap();
|
||||
|
||||
assert!(p == q);
|
||||
|
||||
// Same thing, but sign bit set
|
||||
let test_repr = hex!("9d12b88b08dcbef8a11ee0712d94cb236ee2f4ca17317075bfafc82ce3139db1");
|
||||
let p = edwards::Point::<Bls12, _>::read(&test_repr[..], ¶ms).unwrap();
|
||||
let q = edwards::Point::<Bls12, _>::get_for_y(
|
||||
Fr::from_str("22440861827555040311190986994816762244378363690614952020532787748720529117853").unwrap(),
|
||||
true,
|
||||
¶ms
|
||||
).unwrap();
|
||||
|
||||
assert!(p == q);
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ use pedersen_hash::{
|
|||
};
|
||||
|
||||
use byteorder::{
|
||||
BigEndian,
|
||||
LittleEndian,
|
||||
WriteBytesExt
|
||||
};
|
||||
|
||||
|
@ -28,8 +28,6 @@ use jubjub::{
|
|||
|
||||
use blake2_rfc::blake2s::Blake2s;
|
||||
|
||||
use util::swap_bits_u64;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ValueCommitment<E: JubjubEngine> {
|
||||
pub value: u64,
|
||||
|
@ -96,14 +94,11 @@ impl<E: JubjubEngine> ViewingKey<E> {
|
|||
h.update(&preimage);
|
||||
let mut h = h.finalize().as_ref().to_vec();
|
||||
|
||||
// Reverse the bytes to interpret it in little-endian byte order
|
||||
h.reverse();
|
||||
|
||||
// Drop the first five bits, so it can be interpreted as a scalar.
|
||||
h[0] &= 0b0000_0111;
|
||||
// Drop the most significant five bits, so it can be interpreted as a scalar.
|
||||
h[31] &= 0b0000_0111;
|
||||
|
||||
let mut e = <E::Fs as PrimeField>::Repr::default();
|
||||
e.read_be(&h[..]).unwrap();
|
||||
e.read_le(&h[..]).unwrap();
|
||||
|
||||
E::Fs::from_repr(e).expect("should be a valid scalar")
|
||||
}
|
||||
|
@ -198,13 +193,8 @@ impl<E: JubjubEngine> Note<E> {
|
|||
// Calculate the note contents, as bytes
|
||||
let mut note_contents = vec![];
|
||||
|
||||
// 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::<BigEndian>(
|
||||
swap_bits_u64(self.value)
|
||||
).unwrap();
|
||||
// Writing the value in little endian
|
||||
(&mut note_contents).write_u64::<LittleEndian>(self.value).unwrap();
|
||||
|
||||
// Write g_d
|
||||
self.g_d.write(&mut note_contents).unwrap();
|
||||
|
@ -219,7 +209,7 @@ impl<E: JubjubEngine> Note<E> {
|
|||
Personalization::NoteCommitment,
|
||||
note_contents.into_iter()
|
||||
.flat_map(|byte| {
|
||||
(0..8).rev().map(move |i| ((byte >> i) & 1) == 1)
|
||||
(0..8).map(move |i| ((byte >> i) & 1) == 1)
|
||||
}),
|
||||
params
|
||||
);
|
||||
|
|
|
@ -6,18 +6,11 @@ use rand::Rng;
|
|||
use std::io::{self, Read, Write};
|
||||
|
||||
use jubjub::{FixedGenerators, JubjubEngine, JubjubParams, Unknown, edwards::Point};
|
||||
use util::{hash_to_scalar, swap_bits_u64};
|
||||
use util::{hash_to_scalar};
|
||||
|
||||
fn read_scalar<E: JubjubEngine, R: Read>(reader: R) -> io::Result<E::Fs> {
|
||||
let mut s_repr = <E::Fs as PrimeField>::Repr::default();
|
||||
|
||||
// This reads in big-endian, so we perform a swap of the
|
||||
// limbs in the representation and swap the bit order.
|
||||
s_repr.read_be(reader)?;
|
||||
s_repr.as_mut().reverse();
|
||||
for b in s_repr.as_mut() {
|
||||
*b = swap_bits_u64(*b);
|
||||
}
|
||||
s_repr.read_le(reader)?;
|
||||
|
||||
match E::Fs::from_repr(s_repr) {
|
||||
Ok(s) => Ok(s),
|
||||
|
@ -29,15 +22,7 @@ fn read_scalar<E: JubjubEngine, R: Read>(reader: R) -> io::Result<E::Fs> {
|
|||
}
|
||||
|
||||
fn write_scalar<E: JubjubEngine, W: Write>(s: &E::Fs, writer: W) -> io::Result<()> {
|
||||
let mut s_repr = s.into_repr();
|
||||
|
||||
// This writes in big-endian, so we perform a swap of the
|
||||
// limbs in the representation and swap the bit order.
|
||||
s_repr.as_mut().reverse();
|
||||
for b in s_repr.as_mut() {
|
||||
*b = swap_bits_u64(*b);
|
||||
}
|
||||
s_repr.write_be(writer)
|
||||
s.into_repr().write_le(writer)
|
||||
}
|
||||
|
||||
fn h_star<E: JubjubEngine>(a: &[u8], b: &[u8]) -> E::Fs {
|
||||
|
|
28
src/util.rs
28
src/util.rs
|
@ -2,15 +2,6 @@ use blake2_rfc::blake2b::Blake2b;
|
|||
|
||||
use jubjub::{JubjubEngine, ToUniform};
|
||||
|
||||
pub fn swap_bits_u64(x: u64) -> u64
|
||||
{
|
||||
let mut tmp = 0;
|
||||
for i in 0..64 {
|
||||
tmp |= ((x >> i) & 1) << (63 - i);
|
||||
}
|
||||
tmp
|
||||
}
|
||||
|
||||
pub fn hash_to_scalar<E: JubjubEngine>(persona: &[u8], a: &[u8], b: &[u8]) -> E::Fs {
|
||||
let mut hasher = Blake2b::with_params(64, &[], &[], persona);
|
||||
hasher.update(a);
|
||||
|
@ -18,22 +9,3 @@ pub fn hash_to_scalar<E: JubjubEngine>(persona: &[u8], a: &[u8], b: &[u8]) -> E:
|
|||
let ret = hasher.finalize();
|
||||
E::Fs::to_uniform(ret.as_ref())
|
||||
}
|
||||
|
||||
#[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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue