Merge pull request #72 from ebfull/little-endian

Switch to little endian
This commit is contained in:
ebfull 2018-05-17 14:03:43 -06:00 committed by GitHub
commit eb409fa3cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 46 additions and 126 deletions

View File

@ -9,7 +9,7 @@ repository = "https://github.com/zcash-hackworks/sapling"
version = "0.0.1"
[dependencies.pairing]
version = "0.14"
version = "0.14.2"
features = ["expose-arith"]
[dependencies]

View File

@ -343,7 +343,7 @@ mod test {
let mut out = out.into_iter();
for b in expected.into_iter() {
for i in (0..8).rev() {
for i in 0..8 {
let c = out.next().unwrap().get_value().unwrap();
assert_eq!(c, (b >> i) & 1u8 == 1u8);
@ -405,7 +405,7 @@ mod test {
let mut input_bits = vec![];
for (byte_i, input_byte) in data.into_iter().enumerate() {
for bit_i in (0..8).rev() {
for bit_i in 0..8 {
let cs = cs.namespace(|| format!("input bit {} {}", byte_i, bit_i));
input_bits.push(AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8)).unwrap().into());
@ -417,7 +417,7 @@ mod test {
assert!(cs.is_satisfied());
let mut s = hash_result.as_ref().iter()
.flat_map(|&byte| (0..8).rev().map(move |i| (byte >> i) & 1u8 == 1u8));
.flat_map(|&byte| (0..8).map(move |i| (byte >> i) & 1u8 == 1u8));
for b in r {
match b {

View File

@ -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>

View File

@ -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,

View File

@ -114,10 +114,7 @@ impl UInt32 {
/// Turns this `UInt32` into its little-endian byte order representation.
pub fn into_bits(&self) -> Vec<Boolean> {
self.bits.chunks(8)
.flat_map(|v| v.iter().rev())
.cloned()
.collect()
self.bits.clone()
}
/// Converts a little-endian byte order representation of bits into a
@ -126,10 +123,7 @@ impl UInt32 {
{
assert_eq!(bits.len(), 32);
let new_bits = bits.chunks(8)
.flat_map(|v| v.iter().rev())
.cloned()
.collect::<Vec<_>>();
let new_bits = bits.to_vec();
let mut value = Some(0u32);
for b in new_bits.iter().rev() {

View File

@ -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
}
}

View File

@ -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

View File

@ -363,7 +363,7 @@ fn test_jubjub_bls12() {
tests::test_suite::<Bls12>(&params);
let test_repr = hex!("b9481dd1103b7d1f8578078eb429d3c476472f53e88c0eaefdf51334c7c8b98c");
let test_repr = hex!("9d12b88b08dcbef8a11ee0712d94cb236ee2f4ca17317075bfafc82ce3139d31");
let p = edwards::Point::<Bls12, _>::read(&test_repr[..], &params).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[..], &params).unwrap();
let q = edwards::Point::<Bls12, _>::get_for_y(
Fr::from_str("22440861827555040311190986994816762244378363690614952020532787748720529117853").unwrap(),
true,
&params
).unwrap();
assert!(p == q);
}

View File

@ -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
);

View File

@ -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 {

View File

@ -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);
}
}