Adopt BLAKE2s personalization throughout protocol.

This commit is contained in:
Sean Bowe 2018-03-05 19:21:41 -07:00
parent d21ff08176
commit b831942501
No known key found for this signature in database
GPG Key ID: 95684257D8F8B031
7 changed files with 65 additions and 18 deletions

View File

@ -14,12 +14,14 @@ features = ["expose-arith"]
[dependencies]
rand = "0.4"
blake2-rfc = "0.2.18"
digest = "0.7"
bellman = "0.0.9"
byteorder = "1"
[dependencies.blake2-rfc]
git = "https://github.com/gtank/blake2-rfc"
rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9"
[dev-dependencies]
hex-literal = "0.1"

View File

@ -254,9 +254,13 @@ fn blake2s_compression<E: Engine, CS: ConstraintSystem<E>>(
pub fn blake2s<E: Engine, CS: ConstraintSystem<E>>(
mut cs: CS,
input: &[Boolean]
input: &[Boolean],
personalization: &[u8]
) -> Result<Vec<Boolean>, SynthesisError>
{
use byteorder::{ByteOrder, LittleEndian};
assert_eq!(personalization.len(), 8);
assert!(input.len() % 8 == 0);
let mut h = Vec::with_capacity(8);
@ -266,8 +270,10 @@ pub fn blake2s<E: Engine, CS: ConstraintSystem<E>>(
h.push(UInt32::constant(0xA54FF53A));
h.push(UInt32::constant(0x510E527F));
h.push(UInt32::constant(0x9B05688C));
h.push(UInt32::constant(0x1F83D9AB));
h.push(UInt32::constant(0x5BE0CD19));
// Personalization is stored here
h.push(UInt32::constant(0x1F83D9AB ^ LittleEndian::read_u32(&personalization[0..4])));
h.push(UInt32::constant(0x5BE0CD19 ^ LittleEndian::read_u32(&personalization[4..8])));
let mut blocks: Vec<Vec<UInt32>> = vec![];
@ -315,11 +321,34 @@ mod test {
use bellman::{ConstraintSystem};
use blake2_rfc::blake2s::Blake2s;
#[test]
fn test_blank_hash() {
let mut cs = TestConstraintSystem::<Bls12>::new();
let input_bits = vec![];
let out = blake2s(&mut cs, &input_bits, b"12345678").unwrap();
assert!(cs.is_satisfied());
assert_eq!(cs.num_constraints(), 0);
// >>> import blake2s from hashlib
// >>> h = blake2s(digest_size=32, person=b'12345678')
// >>> h.hexdigest()
let expected = hex!("c59f682376d137f3f255e671e207d1f2374ebe504e9314208a52d9f88d69e8c8");
let mut out = out.into_iter();
for b in expected.into_iter() {
for i in (0..8).rev() {
let c = out.next().unwrap().get_value().unwrap();
assert_eq!(c, (b >> i) & 1u8 == 1u8);
}
}
}
#[test]
fn test_blake2s_constraints() {
let mut cs = TestConstraintSystem::<Bls12>::new();
let input_bits: Vec<_> = (0..512).map(|i| AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true)).unwrap().into()).collect();
blake2s(&mut cs, &input_bits).unwrap();
blake2s(&mut cs, &input_bits, b"12345678").unwrap();
assert!(cs.is_satisfied());
assert_eq!(cs.num_constraints(), 21792);
}
@ -336,7 +365,7 @@ mod test {
.chain((0..512)
.map(|i| AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true)).unwrap().into()))
.collect();
blake2s(&mut cs, &input_bits).unwrap();
blake2s(&mut cs, &input_bits, b"12345678").unwrap();
assert!(cs.is_satisfied());
assert_eq!(cs.num_constraints(), 21792);
}
@ -346,7 +375,7 @@ mod test {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let input_bits: Vec<_> = (0..512).map(|_| Boolean::constant(rng.gen())).collect();
blake2s(&mut cs, &input_bits).unwrap();
blake2s(&mut cs, &input_bits, b"12345678").unwrap();
assert_eq!(cs.num_constraints(), 0);
}
@ -356,7 +385,7 @@ mod test {
for input_len in (0..32).chain((32..256).filter(|a| a % 8 == 0))
{
let mut h = Blake2s::new(32);
let mut h = Blake2s::with_params(32, &[], &[], b"12345678");
let data: Vec<u8> = (0..input_len).map(|_| rng.gen()).collect();
@ -376,7 +405,7 @@ mod test {
}
}
let r = blake2s(&mut cs, &input_bits).unwrap();
let r = blake2s(&mut cs, &input_bits, b"12345678").unwrap();
assert!(cs.is_satisfied());

View File

@ -156,7 +156,8 @@ impl<'a, E: JubjubEngine> Circuit<E> for Spend<'a, E> {
// Compute the incoming viewing key
let mut ivk = blake2s::blake2s(
cs.namespace(|| "computation of ivk"),
&vk
&vk,
::CRH_IVK_PERSONALIZATION
)?;
// Little endian bit order
@ -299,7 +300,8 @@ impl<'a, E: JubjubEngine> Circuit<E> for Spend<'a, E> {
let mut rho = blake2s::blake2s(
cs.namespace(|| "rho computation"),
&rho_preimage
&rho_preimage,
::PRF_NR_PERSONALIZATION
)?;
// Little endian bit order
@ -515,7 +517,7 @@ fn test_input_circuit_with_bls12_381() {
assert!(cs.is_satisfied());
assert_eq!(cs.num_constraints(), 97395);
assert_eq!(cs.hash(), "cdd3cde0a4e076b46a59ef85fb70369eb14e3ee921a06d88bad6be4f78b5f261");
assert_eq!(cs.hash(), "9f730803965612392772c3c1fbb110c1539656e1bab40d5a9a124b06e927ef40");
}
}
@ -553,6 +555,6 @@ fn test_output_circuit_with_bls12_381() {
assert!(cs.is_satisfied());
assert_eq!(cs.num_constraints(), 7827);
assert_eq!(cs.hash(), "67518baade37a3cf76453fa474cb8c9b2ee4223ed5502151e3b83dd1ec98a261");
assert_eq!(cs.hash(), "f4219872738a81ef3ea66199ea5019d87f53ec369ee7f64d0b7c63ade6014114");
}
}

View File

@ -12,13 +12,16 @@ pub const FIRST_BLOCK: &'static [u8; 64] = b"0000000000000000002ffe76b973aabaff1
/// identity.
pub fn group_hash<E: JubjubEngine>(
tag: &[u8],
personalization: &[u8],
params: &E::Params
) -> Option<edwards::Point<E, PrimeOrder>>
{
assert_eq!(personalization.len(), 8);
// Check to see that scalar field is 255 bits
assert!(E::Fr::NUM_BITS == 255);
let mut h = Blake2s::new(32);
let mut h = Blake2s::with_params(32, &[], &[], personalization);
h.update(FIRST_BLOCK);
h.update(tag);
let mut h = h.finalize().as_ref().to_vec();

View File

@ -186,7 +186,7 @@ impl JubjubBls12 {
let mut pedersen_hash_generators = vec![];
while pedersen_hash_generators.len() < 10 {
let gh = group_hash(&[cur], &tmp);
let gh = group_hash(&[cur], ::PEDERSEN_HASH_GENERATORS_PERSONALIZATION, &tmp);
// We don't want to overflow and start reusing generators
assert!(cur != u8::max_value());
cur += 1;
@ -205,7 +205,7 @@ impl JubjubBls12 {
let mut fixed_base_generators = vec![];
while fixed_base_generators.len() < (FixedGenerators::Max as usize) {
let gh = group_hash(&[cur], &tmp);
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;

View File

@ -15,3 +15,11 @@ pub mod circuit;
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";
// TODO: Expand the personalizations to the specific generators
pub const OTHER_PERSONALIZATION: &'static [u8; 8] = b"GOTOFAIL";

View File

@ -11,8 +11,11 @@ impl Personalization {
match *self {
Personalization::NoteCommitment =>
vec![true, true, true, true, true, true],
Personalization::MerkleTree(num) =>
Personalization::MerkleTree(num) => {
assert!(num < 63);
(0..6).map(|i| (num >> i) & 1 == 1).collect()
}
}
}
}