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        edwards_on_bls12_381::{EdwardsProjective as JubJub, Fq, Fr},
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        edwards_on_bls12_381::JubJubGadget, prelude::*,
219        test_constraint_system::TestConstraintSystem,
220    };
221
222    #[test]
223    fn commitment_gadget_test() {
224        let mut cs = TestConstraintSystem::<Fq>::new();
225
226        #[derive(Clone, PartialEq, Eq, Hash)]
227        pub(super) struct Window;
228
229        impl PedersenWindow for Window {
230            const WINDOW_SIZE: usize = 4;
231            const NUM_WINDOWS: usize = 8;
232        }
233
234        let input = [1u8; 4];
235
236        let rng = &mut test_rng();
237
238        type TestCOMM = PedersenCommitment<JubJub, Window>;
239        type TestCOMMGadget = PedersenCommitmentGadget<JubJub, Fq, JubJubGadget>;
240
241        let randomness = PedersenRandomness(Fr::rand(rng));
242
243        let parameters = PedersenCommitment::<JubJub, Window>::setup(rng).unwrap();
244        let primitive_result =
245            PedersenCommitment::<JubJub, Window>::commit(&parameters, &input, &randomness).unwrap();
246
247        let mut input_bytes = vec![];
248        for (byte_i, input_byte) in input.iter().enumerate() {
249            let cs = cs.ns(|| format!("input_byte_gadget_{}", byte_i));
250            input_bytes.push(UInt8::alloc(cs, || Ok(*input_byte)).unwrap());
251        }
252
253        let randomness =
254            <TestCOMMGadget as CommitmentGadget<TestCOMM, Fq>>::RandomnessGadget::alloc(
255                &mut cs.ns(|| "gadget_randomness"),
256                || Ok(&randomness),
257            )
258            .unwrap();
259        let gadget_parameters =
260            <TestCOMMGadget as CommitmentGadget<TestCOMM, Fq>>::ParametersGadget::alloc(
261                &mut cs.ns(|| "gadget_parameters"),
262                || Ok(&parameters),
263            )
264            .unwrap();
265        let gadget_result =
266            <TestCOMMGadget as CommitmentGadget<TestCOMM, Fq>>::check_commitment_gadget(
267                &mut cs.ns(|| "gadget_evaluation"),
268                &gadget_parameters,
269                &input_bytes,
270                &randomness,
271            )
272            .unwrap();
273
274        let primitive_result = primitive_result.into_affine();
275        assert_eq!(primitive_result.x, gadget_result.x.value.unwrap());
276        assert_eq!(primitive_result.y, gadget_result.y.value.unwrap());
277        assert!(cs.is_satisfied());
278    }
279}