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