mirror of
https://github.com/arnaucube/ark-r1cs-std.git
synced 2026-01-10 16:01:28 +01:00
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
This commit is contained in:
@@ -313,20 +313,50 @@ fn blake2s_compression<ConstraintF: PrimeField, CS: ConstraintSystem<ConstraintF
|
|||||||
//
|
//
|
||||||
|
|
||||||
pub fn blake2s_gadget<ConstraintF: PrimeField, CS: ConstraintSystem<ConstraintF>>(
|
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,
|
mut cs: CS,
|
||||||
input: &[Boolean],
|
input: &[Boolean],
|
||||||
|
parameters: &[u32; 8],
|
||||||
) -> Result<Vec<UInt32>, SynthesisError> {
|
) -> Result<Vec<UInt32>, SynthesisError> {
|
||||||
assert!(input.len() % 8 == 0);
|
assert!(input.len() % 8 == 0);
|
||||||
|
|
||||||
let mut h = Vec::with_capacity(8);
|
let mut h = Vec::with_capacity(8);
|
||||||
h.push(UInt32::constant(0x6A09E667 ^ 0x01010000 ^ 32));
|
h.push(
|
||||||
h.push(UInt32::constant(0xBB67AE85));
|
UInt32::constant(0x6A09E667).xor(cs.ns(|| "xor h[0]"), &UInt32::constant(parameters[0]))?,
|
||||||
h.push(UInt32::constant(0x3C6EF372));
|
);
|
||||||
h.push(UInt32::constant(0xA54FF53A));
|
h.push(
|
||||||
h.push(UInt32::constant(0x510E527F));
|
UInt32::constant(0xBB67AE85).xor(cs.ns(|| "xor h[1]"), &UInt32::constant(parameters[1]))?,
|
||||||
h.push(UInt32::constant(0x9B05688C));
|
);
|
||||||
h.push(UInt32::constant(0x1F83D9AB));
|
h.push(
|
||||||
h.push(UInt32::constant(0x5BE0CD19));
|
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![];
|
let mut blocks: Vec<Vec<UInt32>> = vec![];
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use alloc::vec::Vec;
|
||||||
use blake2::Blake2s as b2s;
|
use blake2::Blake2s as b2s;
|
||||||
use digest::Digest;
|
use digest::Digest;
|
||||||
|
|
||||||
@@ -26,3 +27,63 @@ impl PRF for Blake2s {
|
|||||||
Ok(result)
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use algebra::{BitIterator, Field, FpParameters, PrimeField};
|
use algebra::{BitIterator, Field, PrimeField};
|
||||||
|
|
||||||
use crate::{prelude::*, Assignment, Vec};
|
use crate::{prelude::*, Assignment, Vec};
|
||||||
use core::borrow::Borrow;
|
use core::borrow::Borrow;
|
||||||
@@ -576,19 +576,40 @@ impl Boolean {
|
|||||||
/// Asserts that this bit_gadget representation is "in
|
/// Asserts that this bit_gadget representation is "in
|
||||||
/// the field" when interpreted in big endian.
|
/// the field" when interpreted in big endian.
|
||||||
pub fn enforce_in_field<ConstraintF, CS, F: PrimeField>(
|
pub fn enforce_in_field<ConstraintF, CS, F: PrimeField>(
|
||||||
mut cs: CS,
|
cs: CS,
|
||||||
bits: &[Self],
|
bits: &[Self],
|
||||||
) -> Result<(), SynthesisError>
|
) -> Result<(), SynthesisError>
|
||||||
where
|
where
|
||||||
ConstraintF: Field,
|
ConstraintF: Field,
|
||||||
CS: ConstraintSystem<ConstraintF>,
|
CS: ConstraintSystem<ConstraintF>,
|
||||||
{
|
{
|
||||||
let mut bits_iter = bits.iter();
|
|
||||||
|
|
||||||
// b = char() - 1
|
// b = char() - 1
|
||||||
let mut b = F::characteristic().to_vec();
|
let mut b = F::characteristic().to_vec();
|
||||||
assert_eq!(b[0] % 2, 1);
|
assert_eq!(b[0] % 2, 1);
|
||||||
b[0] -= 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
|
// Runs of ones in r
|
||||||
let mut last_run = Boolean::constant(true);
|
let mut last_run = Boolean::constant(true);
|
||||||
@@ -598,7 +619,23 @@ impl Boolean {
|
|||||||
let mut run_i = 0;
|
let mut run_i = 0;
|
||||||
let mut nand_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 {
|
if bits.len() > char_num_bits {
|
||||||
let num_extra_bits = bits.len() - char_num_bits;
|
let num_extra_bits = bits.len() - char_num_bits;
|
||||||
let mut or_result = Boolean::constant(false);
|
let mut or_result = Boolean::constant(false);
|
||||||
@@ -651,12 +688,7 @@ impl Boolean {
|
|||||||
}
|
}
|
||||||
assert!(bits_iter.next().is_none());
|
assert!(bits_iter.next().is_none());
|
||||||
|
|
||||||
// We should always end in a "run" of zeros, because
|
Ok(current_run)
|
||||||
// the characteristic is an odd prime. So, this should
|
|
||||||
// be empty.
|
|
||||||
assert!(current_run.is_empty());
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user