From f155c01cf540437ccab2a2575cc17a431a36dc7b Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Tue, 6 Mar 2018 08:30:28 -0700 Subject: [PATCH] Personalize GH for each generator independently. --- src/circuit/mod.rs | 4 +-- src/jubjub/mod.rs | 72 ++++++++++++++++++++++++++++++++++++++++------ src/lib.rs | 26 +++++++++++++---- 3 files changed, 85 insertions(+), 17 deletions(-) diff --git a/src/circuit/mod.rs b/src/circuit/mod.rs index 6ee8853..e461257 100644 --- a/src/circuit/mod.rs +++ b/src/circuit/mod.rs @@ -517,7 +517,7 @@ fn test_input_circuit_with_bls12_381() { assert!(cs.is_satisfied()); assert_eq!(cs.num_constraints(), 97395); - assert_eq!(cs.hash(), "9f730803965612392772c3c1fbb110c1539656e1bab40d5a9a124b06e927ef40"); + assert_eq!(cs.hash(), "9abc0559abf54a41da789313b1692dc744d940646bb7dd3e6c01ceb54d0cc261"); } } @@ -555,6 +555,6 @@ fn test_output_circuit_with_bls12_381() { assert!(cs.is_satisfied()); assert_eq!(cs.num_constraints(), 7827); - assert_eq!(cs.hash(), "f4219872738a81ef3ea66199ea5019d87f53ec369ee7f64d0b7c63ade6014114"); + assert_eq!(cs.hash(), "2896f259ad7a50c83604976ee9362358396d547b70f2feaf91d82d287e4ffc1d"); } } diff --git a/src/jubjub/mod.rs b/src/jubjub/mod.rs index c293b34..3b9a8d3 100644 --- a/src/jubjub/mod.rs +++ b/src/jubjub/mod.rs @@ -201,17 +201,65 @@ impl JubjubBls12 { // Create the bases for other parts of the protocol { - let mut cur = 0; - let mut fixed_base_generators = vec![]; + let mut fixed_base_generators = vec![edwards::Point::zero(); FixedGenerators::Max as usize]; + + { + // Each generator is found by invoking the group hash + // on tag 0x00, 0x01, ... until we find a valid result. + let find_first_gh = |personalization| { + let mut cur = 0; + + loop { + let gh = group_hash::(&[cur], personalization, &tmp); + // We don't want to overflow. + assert!(cur != u8::max_value()); + cur += 1; + + if let Some(gh) = gh { + break gh; + } + } + }; + + // Written this way for exhaustion (double entendre). There's no + // way to iterate over the variants of an enum, so it's hideous. + for c in 0..(FixedGenerators::Max as usize) { + let p = match c { + c if c == (FixedGenerators::ProvingPublicKey as usize) => { + ::PROVING_KEY_BASE_GENERATOR_PERSONALIZATION + }, + c if c == (FixedGenerators::NoteCommitmentRandomness as usize) => { + ::NOTE_COMMITMENT_RANDOMNESS_GENERATOR_PERSONALIZATION + }, + c if c == (FixedGenerators::NullifierPosition as usize) => { + ::NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION + }, + c if c == (FixedGenerators::ValueCommitmentValue as usize) => { + ::VALUE_COMMITMENT_VALUE_GENERATOR_PERSONALIZATION + }, + c if c == (FixedGenerators::ValueCommitmentRandomness as usize) => { + ::VALUE_COMMITMENT_RANDOMNESS_GENERATOR_PERSONALIZATION + }, + c if c == (FixedGenerators::SpendingKeyGenerator as usize) => { + ::SPENDING_KEY_GENERATOR_PERSONALIZATION + }, + _ => unreachable!() + }; + + fixed_base_generators[c] = find_first_gh(p); + } + } - while fixed_base_generators.len() < (FixedGenerators::Max as usize) { - let gh = group_hash(&[cur], ::OTHER_PERSONALIZATION, &tmp); - // We don't want to overflow and start reusing generators - assert!(cur != u8::max_value()); - cur += 1; + // Check for duplicates, far worse than spec inconsistencies! + for (i, p1) in fixed_base_generators.iter().enumerate() { + if p1 == &edwards::Point::zero() { + panic!("Neutral element!"); + } - if let Some(gh) = gh { - fixed_base_generators.push(gh); + for p2 in fixed_base_generators.iter().skip(i+1) { + if p1 == p2 { + panic!("Duplicate generator!"); + } } } @@ -223,18 +271,23 @@ impl JubjubBls12 { { let mut pedersen_circuit_generators = vec![]; + // Process each segment for mut gen in tmp.pedersen_hash_generators.iter().cloned() { let mut gen = montgomery::Point::from_edwards(&gen, &tmp); let mut windows = vec![]; for _ in 0..tmp.pedersen_hash_chunks_per_generator() { + // Create (x, y) coeffs for this chunk let mut coeffs = vec![]; let mut g = gen.clone(); + + // coeffs = g, g*2, g*3, g*4 for _ in 0..4 { coeffs.push(g.into_xy().expect("cannot produce O")); g = g.add(&gen, &tmp); } windows.push(coeffs); + // Our chunks are separated by 2 bits to prevent overlap. for _ in 0..4 { gen = gen.double(&tmp); } @@ -261,6 +314,7 @@ impl JubjubBls12 { } windows.push(coeffs); + // gen = gen * 8 gen = g; } fixed_base_circuit_generators.push(windows); diff --git a/src/lib.rs b/src/lib.rs index e14cd9b..1fa9fb4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,10 +16,24 @@ pub mod group_hash; pub mod pedersen_hash; pub mod primitives; -// BLAKE2s personalizations -pub const CRH_IVK_PERSONALIZATION: &'static [u8; 8] = b"Zcashivk"; -pub const PRF_NR_PERSONALIZATION: &'static [u8; 8] = b"WhatTheH"; -pub const PEDERSEN_HASH_GENERATORS_PERSONALIZATION: &'static [u8; 8] = b"PEDERSEN"; +// BLAKE2s invocation personalizations +/// BLAKE2s Personalization for CRH^ivk = BLAKE2s(ak | rk) +const CRH_IVK_PERSONALIZATION: &'static [u8; 8] = b"Zcashivk"; +/// BLAKE2s Personalization for PRF^nr = BLAKE2s(rk | cm + position) +const PRF_NR_PERSONALIZATION: &'static [u8; 8] = b"WhatTheH"; -// TODO: Expand the personalizations to the specific generators -pub const OTHER_PERSONALIZATION: &'static [u8; 8] = b"GOTOFAIL"; +// Group hash personalizations +/// BLAKE2s Personalization for Pedersen hash generators. +const PEDERSEN_HASH_GENERATORS_PERSONALIZATION: &'static [u8; 8] = b"PEDERSEN"; +/// BLAKE2s Personalization for the proof generation key base point +const PROVING_KEY_BASE_GENERATOR_PERSONALIZATION: &'static [u8; 8] = b"12345678"; +/// BLAKE2s Personalization for the note commitment randomness generator +const NOTE_COMMITMENT_RANDOMNESS_GENERATOR_PERSONALIZATION: &'static [u8; 8] = b"abcdefgh"; +/// BLAKE2s Personalization for the nullifier position generator (for PRF^nr) +const NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION: &'static [u8; 8] = b"nfnfnfnf"; +/// BLAKE2s Personalization for the value commitment generator for the value +const VALUE_COMMITMENT_VALUE_GENERATOR_PERSONALIZATION: &'static [u8; 8] = b"45u8gh45"; +/// BLAKE2s Personalization for the value commitment randomness generator +const VALUE_COMMITMENT_RANDOMNESS_GENERATOR_PERSONALIZATION: &'static [u8; 8] = b"11111111"; +/// BLAKE2s Personalization for the spending key base point +const SPENDING_KEY_GENERATOR_PERSONALIZATION: &'static [u8; 8] = b"sksksksk";