ark-r1cs-std/crypto-primitives/src/commitment/pedersen/constraints.rs
crypto-primitives/src/commitment/pedersen/constraints.rsRaw
1use crate::{
2 commitment::pedersen::{PedersenCommitment, PedersenParameters, PedersenRandomness},
3 crh::pedersen::PedersenWindow,
4};
5use algebra_core::{
6 fields::{Field, PrimeField},
7 to_bytes, Group, ToBytes,
8};
9use r1cs_core::{ConstraintSystem, SynthesisError};
10
11use crate::commitment::CommitmentGadget;
12use core::{borrow::Borrow, marker::PhantomData};
13use r1cs_std::prelude::*;
14
15#[derive(Derivative)]
16#[derivative(Clone(bound = "G: Group, W: PedersenWindow, ConstraintF: Field"))]
17pub struct PedersenCommitmentGadgetParameters<G: Group, W: PedersenWindow, ConstraintF: Field> {
18 params: PedersenParameters<G>,
19 #[doc(hidden)]
20 _group: PhantomData<G>,
21 #[doc(hidden)]
22 _engine: PhantomData<ConstraintF>,
23 #[doc(hidden)]
24 _window: PhantomData<W>,
25}
26
27#[derive(Clone, Debug)]
28pub struct PedersenRandomnessGadget(Vec<UInt8>);
29
30pub struct PedersenCommitmentGadget<G: Group, ConstraintF: Field, GG: GroupGadget<G, ConstraintF>>(
31 #[doc(hidden)] PhantomData<*const G>,
32 #[doc(hidden)] PhantomData<*const GG>,
33 PhantomData<ConstraintF>,
34);
35
36impl<ConstraintF, G, GG, W> CommitmentGadget<PedersenCommitment<G, W>, ConstraintF>
37 for PedersenCommitmentGadget<G, ConstraintF, GG>
38where
39 ConstraintF: PrimeField,
40 G: Group,
41 GG: GroupGadget<G, ConstraintF>,
42 W: PedersenWindow,
43{
44 type OutputGadget = GG;
45 type ParametersGadget = PedersenCommitmentGadgetParameters<G, W, ConstraintF>;
46 type RandomnessGadget = PedersenRandomnessGadget;
47
48 fn check_commitment_gadget<CS: ConstraintSystem<ConstraintF>>(
49 mut cs: CS,
50 parameters: &Self::ParametersGadget,
51 input: &[UInt8],
52 r: &Self::RandomnessGadget,
53 ) -> Result<Self::OutputGadget, SynthesisError> {
54 assert!((input.len() * 8) <= (W::WINDOW_SIZE * W::NUM_WINDOWS));
55
56 let mut padded_input = input.to_vec();
57 // Pad if input length is less than `W::WINDOW_SIZE * W::NUM_WINDOWS`.
58 if (input.len() * 8) < W::WINDOW_SIZE * W::NUM_WINDOWS {
59 let current_length = input.len();
60 for _ in current_length..((W::WINDOW_SIZE * W::NUM_WINDOWS) / 8) {
61 padded_input.push(UInt8::constant(0u8));
62 }
63 }
64
65 assert_eq!(padded_input.len() * 8, W::WINDOW_SIZE * W::NUM_WINDOWS);
66 assert_eq!(parameters.params.generators.len(), W::NUM_WINDOWS);
67
68 // Allocate new variable for commitment output.
69 let input_in_bits: Vec<_> = padded_input
70 .iter()
71 .flat_map(|byte| byte.into_bits_le())
72 .collect();
73 let input_in_bits = input_in_bits.chunks(W::WINDOW_SIZE);
74 let mut result = GG::precomputed_base_multiscalar_mul(
75 cs.ns(|| "multiexp"),
76 ¶meters.params.generators,
77 input_in_bits,
78 )?;
79
80 // Compute h^r
81 let rand_bits: Vec<_> = r.0.iter().flat_map(|byte| byte.into_bits_le()).collect();
82 result.precomputed_base_scalar_mul(
83 cs.ns(|| "Randomizer"),
84 rand_bits
85 .iter()
86 .zip(¶meters.params.randomness_generator),
87 )?;
88
89 Ok(result)
90 }
91}
92
93impl<G, W, ConstraintF> AllocGadget<PedersenParameters<G>, ConstraintF>
94 for PedersenCommitmentGadgetParameters<G, W, ConstraintF>
95where
96 G: Group,
97 W: PedersenWindow,
98 ConstraintF: PrimeField,
99{
100 fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>(
101 _cs: CS,
102 value_gen: F,
103 ) -> Result<Self, SynthesisError>
104 where
105 F: FnOnce() -> Result<T, SynthesisError>,
106 T: Borrow<PedersenParameters<G>>,
107 {
108 let temp = value_gen()?;
109 let parameters = temp.borrow().clone();
110
111 Ok(PedersenCommitmentGadgetParameters {
112 params: parameters,
113 _group: PhantomData,
114 _engine: PhantomData,
115 _window: PhantomData,
116 })
117 }
118
119 fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>(
120 _cs: CS,
121 value_gen: F,
122 ) -> Result<Self, SynthesisError>
123 where
124 F: FnOnce() -> Result<T, SynthesisError>,
125 T: Borrow<PedersenParameters<G>>,
126 {
127 let temp = value_gen()?;
128 let parameters = temp.borrow().clone();
129
130 Ok(PedersenCommitmentGadgetParameters {
131 params: parameters,
132 _group: PhantomData,
133 _engine: PhantomData,
134 _window: PhantomData,
135 })
136 }
137}
138
139impl<G, ConstraintF> AllocGadget<PedersenRandomness<G>, ConstraintF> for PedersenRandomnessGadget
140where
141 G: Group,
142 ConstraintF: PrimeField,
143{
144 fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>(
145 cs: CS,
146 value_gen: F,
147 ) -> Result<Self, SynthesisError>
148 where
149 F: FnOnce() -> Result<T, SynthesisError>,
150 T: Borrow<PedersenRandomness<G>>,
151 {
152 let temp = value_gen()?;
153 let randomness = to_bytes![temp.borrow().0].unwrap();
154 Ok(PedersenRandomnessGadget(UInt8::alloc_vec(cs, &randomness)?))
155 }
156
157 fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>(
158 cs: CS,
159 value_gen: F,
160 ) -> Result<Self, SynthesisError>
161 where
162 F: FnOnce() -> Result<T, SynthesisError>,
163 T: Borrow<PedersenRandomness<G>>,
164 {
165 let temp = value_gen()?;
166 let randomness = to_bytes![temp.borrow().0].unwrap();
167 Ok(PedersenRandomnessGadget(UInt8::alloc_input_vec(
168 cs,
169 &randomness,
170 )?))
171 }
172}
173
174#[cfg(test)]
175mod test {
176 use algebra::{
177 jubjub::{Fq, Fr, JubJubProjective as JubJub},
178 test_rng, ProjectiveCurve, UniformRand,
179 };
180
181 use crate::{
182 commitment::{
183 pedersen::{
184 constraints::PedersenCommitmentGadget, PedersenCommitment, PedersenRandomness,
185 },
186 CommitmentGadget, CommitmentScheme,
187 },
188 crh::pedersen::PedersenWindow,
189 };
190 use r1cs_core::ConstraintSystem;
191 use r1cs_std::{
192 jubjub::JubJubGadget, prelude::*, test_constraint_system::TestConstraintSystem,
193 };
194
195 #[test]
196 fn commitment_gadget_test() {
197 let mut cs = TestConstraintSystem::<Fq>::new();
198
199 #[derive(Clone, PartialEq, Eq, Hash)]
200 pub(super) struct Window;
201
202 impl PedersenWindow for Window {
203 const WINDOW_SIZE: usize = 4;
204 const NUM_WINDOWS: usize = 8;
205 }
206
207 let input = [1u8; 4];
208
209 let rng = &mut test_rng();
210
211 type TestCOMM = PedersenCommitment<JubJub, Window>;
212 type TestCOMMGadget = PedersenCommitmentGadget<JubJub, Fq, JubJubGadget>;
213
214 let randomness = PedersenRandomness(Fr::rand(rng));
215
216 let parameters = PedersenCommitment::<JubJub, Window>::setup(rng).unwrap();
217 let primitive_result =
218 PedersenCommitment::<JubJub, Window>::commit(¶meters, &input, &randomness).unwrap();
219
220 let mut input_bytes = vec![];
221 for (byte_i, input_byte) in input.iter().enumerate() {
222 let cs = cs.ns(|| format!("input_byte_gadget_{}", byte_i));
223 input_bytes.push(UInt8::alloc(cs, || Ok(*input_byte)).unwrap());
224 }
225
226 let randomness =
227 <TestCOMMGadget as CommitmentGadget<TestCOMM, Fq>>::RandomnessGadget::alloc(
228 &mut cs.ns(|| "gadget_randomness"),
229 || Ok(&randomness),
230 )
231 .unwrap();
232 let gadget_parameters =
233 <TestCOMMGadget as CommitmentGadget<TestCOMM, Fq>>::ParametersGadget::alloc(
234 &mut cs.ns(|| "gadget_parameters"),
235 || Ok(¶meters),
236 )
237 .unwrap();
238 let gadget_result =
239 <TestCOMMGadget as CommitmentGadget<TestCOMM, Fq>>::check_commitment_gadget(
240 &mut cs.ns(|| "gadget_evaluation"),
241 &gadget_parameters,
242 &input_bytes,
243 &randomness,
244 )
245 .unwrap();
246
247 let primitive_result = primitive_result.into_affine();
248 assert_eq!(primitive_result.x, gadget_result.x.value.unwrap());
249 assert_eq!(primitive_result.y, gadget_result.y.value.unwrap());
250 assert!(cs.is_satisfied());
251 }
252}