ark-r1cs-std/crypto-primitives/src/commitment/blake2s/constraints.rs
crypto-primitives/src/commitment/blake2s/constraints.rsRaw
1use r1cs_core::{Namespace, SynthesisError};
2
3use crate::{
4 commitment::blake2s,
5 commitment::CommitmentGadget,
6 prf::blake2s::constraints::{evaluate_blake2s, OutputVar},
7 Vec,
8};
9use algebra_core::{Field, PrimeField};
10use r1cs_std::prelude::*;
11
12use core::borrow::Borrow;
13
14#[derive(Clone)]
15pub struct ParametersVar;
16
17#[derive(Clone)]
18pub struct RandomnessVar<F: Field>(pub Vec<UInt8<F>>);
19
20pub struct CommGadget;
21
22impl<F: PrimeField> CommitmentGadget<blake2s::Commitment, F> for CommGadget {
23 type OutputVar = OutputVar<F>;
24 type ParametersVar = ParametersVar;
25 type RandomnessVar = RandomnessVar<F>;
26
27 #[tracing::instrument(target = "r1cs", skip(input, r))]
28 fn commit(
29 _: &Self::ParametersVar,
30 input: &[UInt8<F>],
31 r: &Self::RandomnessVar,
32 ) -> Result<Self::OutputVar, SynthesisError> {
33 let mut input_bits = Vec::with_capacity(512);
34 for byte in input.iter().chain(r.0.iter()) {
35 input_bits.extend_from_slice(&byte.to_bits_le()?);
36 }
37 let mut result = Vec::new();
38 for int in evaluate_blake2s(&input_bits)?.into_iter() {
39 let chunk = int.to_bytes()?;
40 result.extend_from_slice(&chunk);
41 }
42 Ok(OutputVar(result))
43 }
44}
45
46impl<ConstraintF: Field> AllocVar<(), ConstraintF> for ParametersVar {
47 #[tracing::instrument(target = "r1cs", skip(_cs, _f))]
48 fn new_variable<T: Borrow<()>>(
49 _cs: impl Into<Namespace<ConstraintF>>,
50 _f: impl FnOnce() -> Result<T, SynthesisError>,
51 _mode: AllocationMode,
52 ) -> Result<Self, SynthesisError> {
53 Ok(ParametersVar)
54 }
55}
56
57impl<ConstraintF: PrimeField> AllocVar<[u8; 32], ConstraintF> for RandomnessVar<ConstraintF> {
58 #[tracing::instrument(target = "r1cs", skip(cs, f))]
59 fn new_variable<T: Borrow<[u8; 32]>>(
60 cs: impl Into<Namespace<ConstraintF>>,
61 f: impl FnOnce() -> Result<T, SynthesisError>,
62 mode: AllocationMode,
63 ) -> Result<Self, SynthesisError> {
64 let bytes = f().map(|b| *b.borrow()).unwrap_or([0u8; 32]);
65 match mode {
66 AllocationMode::Constant => Ok(Self(UInt8::constant_vec(&bytes))),
67 AllocationMode::Input => UInt8::new_input_vec(cs, &bytes).map(Self),
68 AllocationMode::Witness => UInt8::new_witness_vec(cs, &bytes).map(Self),
69 }
70 }
71}
72
73#[cfg(test)]
74mod test {
75 use crate::{
76 commitment::blake2s::{
77 constraints::{CommGadget, RandomnessVar},
78 Commitment,
79 },
80 commitment::{CommitmentGadget, CommitmentScheme},
81 };
82 use algebra::{ed_on_bls12_381::Fq as Fr, test_rng};
83 use r1cs_core::ConstraintSystem;
84 use r1cs_std::prelude::*;
85 use rand::Rng;
86
87 #[test]
88 fn commitment_gadget_test() {
89 let cs = ConstraintSystem::<Fr>::new_ref();
90
91 let input = [1u8; 32];
92
93 let rng = &mut test_rng();
94
95 type TestCOMM = Commitment;
96 type TestCOMMGadget = CommGadget;
97
98 let mut randomness = [0u8; 32];
99 rng.fill(&mut randomness);
100
101 let parameters = ();
102 let primitive_result = Commitment::commit(¶meters, &input, &randomness).unwrap();
103
104 let mut input_var = vec![];
105 for byte in &input {
106 input_var.push(UInt8::new_witness(cs.clone(), || Ok(*byte)).unwrap());
107 }
108
109 let mut randomness_var = vec![];
110 for r_byte in randomness.iter() {
111 randomness_var.push(UInt8::new_witness(cs.clone(), || Ok(r_byte)).unwrap());
112 }
113 let randomness_var = RandomnessVar(randomness_var);
114
115 let parameters_var =
116 <TestCOMMGadget as CommitmentGadget<TestCOMM, Fr>>::ParametersVar::new_witness(
117 r1cs_core::ns!(cs, "gadget_parameters"),
118 || Ok(¶meters),
119 )
120 .unwrap();
121 let result_var = <TestCOMMGadget as CommitmentGadget<TestCOMM, Fr>>::commit(
122 ¶meters_var,
123 &input_var,
124 &randomness_var,
125 )
126 .unwrap();
127
128 for i in 0..32 {
129 assert_eq!(primitive_result[i], result_var.0[i].value().unwrap());
130 }
131 assert!(cs.is_satisfied().unwrap());
132 }
133}