From 8b6f113052ecd4c96d0490509c88b2395856dbde Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Sat, 17 Mar 2018 10:24:55 -0600 Subject: [PATCH] Change personalization to more closely align with the spec. --- src/circuit/sapling/mod.rs | 4 +- src/jubjub/mod.rs | 105 ++++++++++++++++++------------------- 2 files changed, 53 insertions(+), 56 deletions(-) diff --git a/src/circuit/sapling/mod.rs b/src/circuit/sapling/mod.rs index bc2178f..eacb48c 100644 --- a/src/circuit/sapling/mod.rs +++ b/src/circuit/sapling/mod.rs @@ -623,7 +623,7 @@ fn test_input_circuit_with_bls12_381() { assert!(cs.is_satisfied()); assert_eq!(cs.num_constraints(), 98776); - assert_eq!(cs.hash(), "729850617d4e6d95cbf348f07cbe0c63b01d35718f24cbcf7df79e2c3e1a7648"); + assert_eq!(cs.hash(), "d810fa887178359f3fc5723781a0750b750dd0c02aeb0b14ff19a343db9868f1"); assert_eq!(cs.num_inputs(), 8); assert_eq!(cs.get_input(0, "ONE"), Fr::one()); @@ -749,7 +749,7 @@ fn test_output_circuit_with_bls12_381() { assert!(cs.is_satisfied()); assert_eq!(cs.num_constraints(), 7827); - assert_eq!(cs.hash(), "0c3d4ee7b0ac346836f177a471b2453c3558ea5760c526faad72feb65caf275b"); + assert_eq!(cs.hash(), "e49724488227ae83b2360a5ddbda7e44c83e6f526a369cefeb747c5dd6aab7c7"); let expected_cm = payment_address.create_note( value_commitment.value, diff --git a/src/jubjub/mod.rs b/src/jubjub/mod.rs index a04fe40..8966c7b 100644 --- a/src/jubjub/mod.rs +++ b/src/jubjub/mod.rs @@ -192,25 +192,51 @@ impl JubjubBls12 { fixed_base_circuit_generators: vec![], }; - // Create the bases for the Pedersen hashes + fn find_group_hash( + m: &[u8], + personalization: &[u8; 8], + params: &E::Params + ) -> edwards::Point { - // TODO: This currently does not match the specification - let mut cur = 0; - let mut pedersen_hash_generators = vec![]; + let mut tag = m.to_vec(); + let i = tag.len(); + tag.push(0u8); + + loop { + let gh = group_hash( + &tag, + personalization, + params + ); - // TODO: This generates more bases for the Pedersen hashes - // than necessary, which is just a performance issue in - // practice. - while pedersen_hash_generators.len() < 5 { - let gh = group_hash(&[cur], constants::PEDERSEN_HASH_GENERATORS_PERSONALIZATION, &tmp_params); // We don't want to overflow and start reusing generators - assert!(cur != u8::max_value()); - cur += 1; + assert!(tag[i] != u8::max_value()); + tag[i] += 1; if let Some(gh) = gh { - pedersen_hash_generators.push(gh); + break gh; } } + } + + // Create the bases for the Pedersen hashes + { + let mut pedersen_hash_generators = vec![]; + + for m in 0..5 { + use byteorder::{WriteBytesExt, BigEndian}; + + let mut segment_number = [0u8; 4]; + (&mut segment_number[0..4]).write_u32::(m).unwrap(); + + pedersen_hash_generators.push( + find_group_hash( + &segment_number, + constants::PEDERSEN_HASH_GENERATORS_PERSONALIZATION, + &tmp_params + ) + ); + } // Check for duplicates, far worse than spec inconsistencies! for (i, p1) in pedersen_hash_generators.iter().enumerate() { @@ -232,52 +258,23 @@ impl JubjubBls12 { { 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 = 0u8; + fixed_base_generators[FixedGenerators::ProofGenerationKey as usize] = + find_group_hash(b"0", constants::PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION, &tmp_params); - loop { - let gh = group_hash::(&[cur], personalization, &tmp_params); - // We don't want to overflow. - assert!(cur != u8::max_value()); - cur += 1; + fixed_base_generators[FixedGenerators::NoteCommitmentRandomness as usize] = + find_group_hash(b"0", constants::NOTE_COMMITMENT_RANDOMNESS_GENERATOR_PERSONALIZATION, &tmp_params); - if let Some(gh) = gh { - break gh; - } - } - }; + fixed_base_generators[FixedGenerators::NullifierPosition as usize] = + find_group_hash(b"0", constants::NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION, &tmp_params); - // 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::ProofGenerationKey as usize) => { - constants::PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION - }, - c if c == (FixedGenerators::NoteCommitmentRandomness as usize) => { - constants::NOTE_COMMITMENT_RANDOMNESS_GENERATOR_PERSONALIZATION - }, - c if c == (FixedGenerators::NullifierPosition as usize) => { - constants::NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION - }, - c if c == (FixedGenerators::ValueCommitmentValue as usize) => { - constants::VALUE_COMMITMENT_VALUE_GENERATOR_PERSONALIZATION - }, - c if c == (FixedGenerators::ValueCommitmentRandomness as usize) => { - constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR_PERSONALIZATION - }, - c if c == (FixedGenerators::SpendingKeyGenerator as usize) => { - constants::SPENDING_KEY_GENERATOR_PERSONALIZATION - }, - _ => unreachable!() - }; + fixed_base_generators[FixedGenerators::ValueCommitmentValue as usize] = + find_group_hash(b"0", constants::VALUE_COMMITMENT_VALUE_GENERATOR_PERSONALIZATION, &tmp_params); - fixed_base_generators[c] = find_first_gh(p); - } - } + fixed_base_generators[FixedGenerators::ValueCommitmentRandomness as usize] = + find_group_hash(b"0", constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR_PERSONALIZATION, &tmp_params); + + fixed_base_generators[FixedGenerators::SpendingKeyGenerator as usize] = + find_group_hash(b"0", constants::SPENDING_KEY_GENERATOR_PERSONALIZATION, &tmp_params); // Check for duplicates, far worse than spec inconsistencies! for (i, p1) in fixed_base_generators.iter().enumerate() {