ark-r1cs-std/crypto-primitives/src/commitment/blake2s/constraints.rs
crypto-primitives/src/commitment/blake2s/constraints.rsRaw
1use r1cs_core::{ConstraintSystem, SynthesisError};
2
3use crate::{
4 commitment::blake2s::Blake2sCommitment,
5 prf::blake2s::constraints::{blake2s_gadget, Blake2sOutputGadget},
6 CommitmentGadget, Vec,
7};
8use algebra_core::{Field, PrimeField};
9use r1cs_std::prelude::*;
10
11use core::borrow::Borrow;
12
13#[derive(Clone)]
14pub struct Blake2sParametersGadget;
15
16#[derive(Clone)]
17pub struct Blake2sRandomnessGadget(pub Vec<UInt8>);
18
19pub struct Blake2sCommitmentGadget;
20
21impl<ConstraintF: PrimeField> CommitmentGadget<Blake2sCommitment, ConstraintF>
22 for Blake2sCommitmentGadget
23{
24 type OutputGadget = Blake2sOutputGadget;
25 type ParametersGadget = Blake2sParametersGadget;
26 type RandomnessGadget = Blake2sRandomnessGadget;
27
28 fn check_commitment_gadget<CS: ConstraintSystem<ConstraintF>>(
29 mut cs: CS,
30 _: &Self::ParametersGadget,
31 input: &[UInt8],
32 r: &Self::RandomnessGadget,
33 ) -> Result<Self::OutputGadget, SynthesisError> {
34 let mut input_bits = Vec::with_capacity(512);
35 for byte in input.iter().chain(r.0.iter()) {
36 input_bits.extend_from_slice(&byte.into_bits_le());
37 }
38 let mut result = Vec::new();
39 for (i, int) in blake2s_gadget(cs.ns(|| "Blake2s Eval"), &input_bits)?
40 .into_iter()
41 .enumerate()
42 {
43 let chunk = int.to_bytes(&mut cs.ns(|| format!("Result ToBytes {}", i)))?;
44 result.extend_from_slice(&chunk);
45 }
46 Ok(Blake2sOutputGadget(result))
47 }
48}
49
50impl<ConstraintF: Field> AllocGadget<(), ConstraintF> for Blake2sParametersGadget {
51 fn alloc_constant<T, CS: ConstraintSystem<ConstraintF>>(
52 cs: CS,
53 val: T,
54 ) -> Result<Self, SynthesisError>
55 where
56 T: Borrow<()>,
57 {
58 Self::alloc(cs, || Ok(val))
59 }
60
61 fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>(_: CS, _: F) -> Result<Self, SynthesisError>
62 where
63 F: FnOnce() -> Result<T, SynthesisError>,
64 T: Borrow<()>,
65 {
66 Ok(Blake2sParametersGadget)
67 }
68
69 fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>(
70 _: CS,
71 _: F,
72 ) -> Result<Self, SynthesisError>
73 where
74 F: FnOnce() -> Result<T, SynthesisError>,
75 T: Borrow<()>,
76 {
77 Ok(Blake2sParametersGadget)
78 }
79}
80
81impl<ConstraintF: PrimeField> AllocGadget<[u8; 32], ConstraintF> for Blake2sRandomnessGadget {
82 #[inline]
83 fn alloc_constant<T, CS: ConstraintSystem<ConstraintF>>(
84 mut cs: CS,
85 val: T,
86 ) -> Result<Self, SynthesisError>
87 where
88 T: Borrow<[u8; 32]>,
89 {
90 let mut bytes = vec![];
91 for (i, b) in val.borrow().iter().enumerate() {
92 bytes.push(UInt8::alloc_constant(cs.ns(|| format!("value {}", i)), b)?)
93 }
94
95 Ok(Blake2sRandomnessGadget(bytes))
96 }
97
98 #[inline]
99 fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>(
100 cs: CS,
101 value_gen: F,
102 ) -> Result<Self, SynthesisError>
103 where
104 F: FnOnce() -> Result<T, SynthesisError>,
105 T: Borrow<[u8; 32]>,
106 {
107 let zeros = [0u8; 32];
108 let value = match value_gen() {
109 Ok(val) => *(val.borrow()),
110 Err(_) => zeros,
111 };
112 let bytes = <UInt8>::alloc_vec(cs, &value)?;
113
114 Ok(Blake2sRandomnessGadget(bytes))
115 }
116
117 #[inline]
118 fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>(
119 cs: CS,
120 value_gen: F,
121 ) -> Result<Self, SynthesisError>
122 where
123 F: FnOnce() -> Result<T, SynthesisError>,
124 T: Borrow<[u8; 32]>,
125 {
126 let zeros = [0u8; 32];
127 let value = match value_gen() {
128 Ok(val) => *(val.borrow()),
129 Err(_) => zeros,
130 };
131 let bytes = <UInt8>::alloc_input_vec(cs, &value)?;
132
133 Ok(Blake2sRandomnessGadget(bytes))
134 }
135}
136
137#[cfg(test)]
138mod test {
139 use crate::{
140 commitment::blake2s::{
141 constraints::{Blake2sCommitmentGadget, Blake2sRandomnessGadget},
142 Blake2sCommitment,
143 },
144 *,
145 };
146 use algebra::{jubjub::Fq as Fr, test_rng};
147 use r1cs_core::ConstraintSystem;
148 use r1cs_std::{prelude::*, test_constraint_system::TestConstraintSystem};
149 use rand::Rng;
150
151 #[test]
152 fn commitment_gadget_test() {
153 let mut cs = TestConstraintSystem::<Fr>::new();
154
155 let input = [1u8; 32];
156
157 let rng = &mut test_rng();
158
159 type TestCOMM = Blake2sCommitment;
160 type TestCOMMGadget = Blake2sCommitmentGadget;
161
162 let mut randomness = [0u8; 32];
163 rng.fill(&mut randomness);
164
165 let parameters = ();
166 let primitive_result = Blake2sCommitment::commit(¶meters, &input, &randomness).unwrap();
167
168 let mut input_bytes = vec![];
169 for (byte_i, input_byte) in input.iter().enumerate() {
170 let cs = cs.ns(|| format!("input_byte_gadget_{}", byte_i));
171 input_bytes.push(UInt8::alloc(cs, || Ok(*input_byte)).unwrap());
172 }
173
174 let mut randomness_bytes = vec![];
175 for (byte_i, random_byte) in randomness.iter().enumerate() {
176 let cs = cs.ns(|| format!("randomness_byte_gadget_{}", byte_i));
177 randomness_bytes.push(UInt8::alloc(cs, || Ok(*random_byte)).unwrap());
178 }
179 let randomness_bytes = Blake2sRandomnessGadget(randomness_bytes);
180
181 let gadget_parameters =
182 <TestCOMMGadget as CommitmentGadget<TestCOMM, Fr>>::ParametersGadget::alloc(
183 &mut cs.ns(|| "gadget_parameters"),
184 || Ok(¶meters),
185 )
186 .unwrap();
187 let gadget_result =
188 <TestCOMMGadget as CommitmentGadget<TestCOMM, Fr>>::check_commitment_gadget(
189 &mut cs.ns(|| "gadget_evaluation"),
190 &gadget_parameters,
191 &input_bytes,
192 &randomness_bytes,
193 )
194 .unwrap();
195
196 for i in 0..32 {
197 assert_eq!(primitive_result[i], gadget_result.0[i].get_value().unwrap());
198 }
199 assert!(cs.is_satisfied());
200 }
201}