Blake PRF & R1CS Boolean Refactor (#132) * refactor(r1cs-std/boolean): expose enforcing value less than functionality * fix(r1cs-std/boolean): ensure num_bits is calculated correctly from the arg * feat(primitives/blake2s): allow creating Blake2s with custom params
Pratyush Mishra pratyushmishra@berkeley.edu
Thu, 05 Mar 2020 10:51:59 -0800
3 files changed,
142 insertions(+),
19 deletions(-)
M
crypto-primitives/src/prf/blake2s/constraints.rs
→
crypto-primitives/src/prf/blake2s/constraints.rs
@@ -313,20 +313,50 @@ // END FUNCTION.
// pub fn blake2s_gadget<ConstraintF: PrimeField, CS: ConstraintSystem<ConstraintF>>( + cs: CS, + input: &[Boolean], +) -> Result<Vec<UInt32>, SynthesisError> { + assert!(input.len() % 8 == 0); + let mut parameters = [0; 8]; + parameters[0] = 0x01010000 ^ 32; + blake2s_gadget_with_parameters(cs, input, ¶meters) +} + +pub fn blake2s_gadget_with_parameters< + ConstraintF: PrimeField, + CS: ConstraintSystem<ConstraintF>, +>( mut cs: CS, input: &[Boolean], + parameters: &[u32; 8], ) -> Result<Vec<UInt32>, SynthesisError> { assert!(input.len() % 8 == 0); let mut h = Vec::with_capacity(8); - h.push(UInt32::constant(0x6A09E667 ^ 0x01010000 ^ 32)); - h.push(UInt32::constant(0xBB67AE85)); - h.push(UInt32::constant(0x3C6EF372)); - 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)); + h.push( + UInt32::constant(0x6A09E667).xor(cs.ns(|| "xor h[0]"), &UInt32::constant(parameters[0]))?, + ); + h.push( + UInt32::constant(0xBB67AE85).xor(cs.ns(|| "xor h[1]"), &UInt32::constant(parameters[1]))?, + ); + h.push( + UInt32::constant(0x3C6EF372).xor(cs.ns(|| "xor h[2]"), &UInt32::constant(parameters[2]))?, + ); + h.push( + UInt32::constant(0xA54FF53A).xor(cs.ns(|| "xor h[3]"), &UInt32::constant(parameters[3]))?, + ); + h.push( + UInt32::constant(0x510E527F).xor(cs.ns(|| "xor h[4]"), &UInt32::constant(parameters[4]))?, + ); + h.push( + UInt32::constant(0x9B05688C).xor(cs.ns(|| "xor h[5]"), &UInt32::constant(parameters[5]))?, + ); + h.push( + UInt32::constant(0x1F83D9AB).xor(cs.ns(|| "xor h[6]"), &UInt32::constant(parameters[6]))?, + ); + h.push( + UInt32::constant(0x5BE0CD19).xor(cs.ns(|| "xor h[7]"), &UInt32::constant(parameters[7]))?, + ); let mut blocks: Vec<Vec<UInt32>> = vec![];
M
crypto-primitives/src/prf/blake2s/mod.rs
→
crypto-primitives/src/prf/blake2s/mod.rs
@@ -1,3 +1,4 @@
+use alloc::vec::Vec; use blake2::Blake2s as b2s; use digest::Digest;@@ -26,3 +27,63 @@ end_timer!(eval_time);
Ok(result) } } + +#[derive(Clone)] +pub struct Blake2sWithParameterBlock { + pub digest_length: u8, + pub key_length: u8, + pub fan_out: u8, + pub depth: u8, + pub leaf_length: u32, + pub node_offset: u32, + pub xof_digest_length: u16, + pub node_depth: u8, + pub inner_length: u8, + pub salt: [u8; 8], + pub personalization: [u8; 8], +} + +impl Blake2sWithParameterBlock { + pub fn parameters(&self) -> [u32; 8] { + let mut parameters = [0; 8]; + parameters[0] = u32::from_le_bytes([ + self.digest_length, + self.key_length, + self.fan_out, + self.depth, + ]); + parameters[1] = self.leaf_length; + parameters[2] = self.node_offset; + parameters[3] = u32::from_le_bytes([ + self.xof_digest_length as u8, + (self.xof_digest_length >> 8) as u8, + self.node_depth, + self.inner_length, + ]); + + let mut salt_bytes_1 = [0; 4]; + let mut salt_bytes_2 = [0; 4]; + let mut personalization_bytes_1 = [0; 4]; + let mut personalization_bytes_2 = [0; 4]; + for i in 0..4 { + salt_bytes_1[i] = self.salt[i]; + salt_bytes_2[i] = self.salt[4 + i]; + personalization_bytes_1[i] = self.personalization[i]; + personalization_bytes_2[i] = self.personalization[4 + i]; + } + parameters[4] = u32::from_le_bytes(salt_bytes_1); + parameters[5] = u32::from_le_bytes(salt_bytes_2); + parameters[6] = u32::from_le_bytes(personalization_bytes_1); + parameters[7] = u32::from_le_bytes(personalization_bytes_2); + + parameters + } + + pub fn evaluate(&self, input: &[u8]) -> Vec<u8> { + let eval_time = start_timer!(|| "Blake2sWithParameterBlock::Eval"); + let mut h = b2s::with_parameter_block(&self.parameters()); + h.input(input.as_ref()); + end_timer!(eval_time); + h.result().to_vec() + } +}
M
r1cs-std/src/bits/boolean.rs
→
r1cs-std/src/bits/boolean.rs
@@ -1,4 +1,4 @@
-use algebra::{BitIterator, Field, FpParameters, PrimeField}; +use algebra::{BitIterator, Field, PrimeField}; use crate::{prelude::*, Assignment, Vec}; use core::borrow::Borrow;@@ -576,19 +576,40 @@
/// Asserts that this bit_gadget representation is "in /// the field" when interpreted in big endian. pub fn enforce_in_field<ConstraintF, CS, F: PrimeField>( - mut cs: CS, + cs: CS, bits: &[Self], ) -> Result<(), SynthesisError> where ConstraintF: Field, CS: ConstraintSystem<ConstraintF>, { - let mut bits_iter = bits.iter(); - // b = char() - 1 let mut b = F::characteristic().to_vec(); assert_eq!(b[0] % 2, 1); b[0] -= 1; + let run = Self::enforce_smaller_or_equal_than::<_, _, F, _>(cs, bits, b)?; + + // We should always end in a "run" of zeros, because + // the characteristic is an odd prime. So, this should + // be empty. + assert!(run.is_empty()); + + Ok(()) + } + + /// Asserts that this bit_gadget representation is smaller + /// or equal than the provided element + pub fn enforce_smaller_or_equal_than<ConstraintF, CS, F: PrimeField, E: AsRef<[u64]>>( + mut cs: CS, + bits: &[Self], + element: E, + ) -> Result<Vec<Boolean>, SynthesisError> + where + ConstraintF: Field, + CS: ConstraintSystem<ConstraintF>, + { + let mut bits_iter = bits.iter(); + let b: &[u64] = element.as_ref(); // Runs of ones in r let mut last_run = Boolean::constant(true);@@ -598,7 +619,23 @@ let mut found_one = false;
let mut run_i = 0; let mut nand_i = 0; - let char_num_bits = <F as PrimeField>::Params::MODULUS_BITS as usize; + let char_num_bits = { + let mut leading_zeros = 0; + let mut total_bits = 0; + let mut found_one = false; + for b in BitIterator::new(b.clone()) { + total_bits += 1; + if !b && !found_one { + leading_zeros += 1 + } + if b { + found_one = true; + } + } + + total_bits - leading_zeros + }; + if bits.len() > char_num_bits { let num_extra_bits = bits.len() - char_num_bits; let mut or_result = Boolean::constant(false);@@ -651,12 +688,7 @@ }
} assert!(bits_iter.next().is_none()); - // We should always end in a "run" of zeros, because - // the characteristic is an odd prime. So, this should - // be empty. - assert!(current_run.is_empty()); - - Ok(()) + Ok(current_run) } }