Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
6 changes: 3 additions & 3 deletions src/circuit/blake2s.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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());
Expand All @@ -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 {
Expand Down
7 changes: 7 additions & 0 deletions src/circuit/multipack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
11 changes: 3 additions & 8 deletions src/circuit/sapling/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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);

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

Expand Down Expand Up @@ -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,
Expand Down
10 changes: 2 additions & 8 deletions src/circuit/uint32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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() {
Expand Down
25 changes: 6 additions & 19 deletions src/group_hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ use jubjub::{
};

use pairing::{
PrimeField,
PrimeFieldRepr
PrimeField
};

use blake2_rfc::blake2s::Blake2s;
Expand All @@ -29,31 +28,19 @@ 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() {
Some(p)
} else {
None
}
} else {
None
}
} else {
None
},
Err(_) => None
}
}
25 changes: 2 additions & 23 deletions src/jubjub/edwards.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
//
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
13 changes: 12 additions & 1 deletion src/jubjub/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand All @@ -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);
}
24 changes: 7 additions & 17 deletions src/primitives/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use pedersen_hash::{
};

use byteorder::{
BigEndian,
LittleEndian,
WriteBytesExt
};

Expand All @@ -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,
Expand Down Expand Up @@ -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;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spec says to interpret the BLAKE2s output as a 256-bit integer mod 2livk, and livk = 251, so this is indeed equivalent to truncating by 5 bits.


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")
}
Expand Down Expand Up @@ -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();
Expand All @@ -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
);
Expand Down
21 changes: 3 additions & 18 deletions src/redjubjub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -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 {
Expand Down
28 changes: 0 additions & 28 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,10 @@ 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);
hasher.update(b);
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);
}
}