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<F, T, CS: ConstraintSystem<ConstraintF>>(
102        _cs: CS,
103        value_gen: F,
104    ) -> Result<Self, SynthesisError>
105    where
106        F: FnOnce() -> Result<T, SynthesisError>,
107        T: Borrow<PedersenParameters<G>>,
108    {
109        let temp = value_gen()?;
110        let parameters = temp.borrow().clone();
111
112        Ok(PedersenCommitmentGadgetParameters {
113            params: parameters,
114            _group: PhantomData,
115            _engine: PhantomData,
116            _window: PhantomData,
117        })
118    }
119
120    fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>(
121        _cs: CS,
122        value_gen: F,
123    ) -> Result<Self, SynthesisError>
124    where
125        F: FnOnce() -> Result<T, SynthesisError>,
126        T: Borrow<PedersenParameters<G>>,
127    {
128        let temp = value_gen()?;
129        let parameters = temp.borrow().clone();
130
131        Ok(PedersenCommitmentGadgetParameters {
132            params: parameters,
133            _group: PhantomData,
134            _engine: PhantomData,
135            _window: PhantomData,
136        })
137    }
138}
139
140impl<G, ConstraintF> AllocGadget<PedersenRandomness<G>, ConstraintF> for PedersenRandomnessGadget
141where
142    G: Group,
143    ConstraintF: PrimeField,
144{
145    fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>(
146        cs: CS,
147        value_gen: F,
148    ) -> Result<Self, SynthesisError>
149    where
150        F: FnOnce() -> Result<T, SynthesisError>,
151        T: Borrow<PedersenRandomness<G>>,
152    {
153        let temp = value_gen()?;
154        let randomness = to_bytes![temp.borrow().0].unwrap();
155        Ok(PedersenRandomnessGadget(UInt8::alloc_vec(cs, &randomness)?))
156    }
157
158    fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>(
159        cs: CS,
160        value_gen: F,
161    ) -> Result<Self, SynthesisError>
162    where
163        F: FnOnce() -> Result<T, SynthesisError>,
164        T: Borrow<PedersenRandomness<G>>,
165    {
166        let temp = value_gen()?;
167        let randomness = to_bytes![temp.borrow().0].unwrap();
168        Ok(PedersenRandomnessGadget(UInt8::alloc_input_vec(
169            cs,
170            &randomness,
171        )?))
172    }
173}
174
175#[cfg(test)]
176mod test {
177    use algebra::{
178        jubjub::{Fq, Fr, JubJubProjective as JubJub},
179        test_rng, ProjectiveCurve, UniformRand,
180    };
181
182    use crate::{
183        commitment::{
184            pedersen::{
185                constraints::PedersenCommitmentGadget, PedersenCommitment, PedersenRandomness,
186            },
187            CommitmentGadget, CommitmentScheme,
188        },
189        crh::pedersen::PedersenWindow,
190    };
191    use r1cs_core::ConstraintSystem;
192    use r1cs_std::{
193        jubjub::JubJubGadget, prelude::*, test_constraint_system::TestConstraintSystem,
194    };
195
196    #[test]
197    fn commitment_gadget_test() {
198        let mut cs = TestConstraintSystem::<Fq>::new();
199
200        #[derive(Clone, PartialEq, Eq, Hash)]
201        pub(super) struct Window;
202
203        impl PedersenWindow for Window {
204            const WINDOW_SIZE: usize = 4;
205            const NUM_WINDOWS: usize = 8;
206        }
207
208        let input = [1u8; 4];
209
210        let rng = &mut test_rng();
211
212        type TestCOMM = PedersenCommitment<JubJub, Window>;
213        type TestCOMMGadget = PedersenCommitmentGadget<JubJub, Fq, JubJubGadget>;
214
215        let randomness = PedersenRandomness(Fr::rand(rng));
216
217        let parameters = PedersenCommitment::<JubJub, Window>::setup(rng).unwrap();
218        let primitive_result =
219            PedersenCommitment::<JubJub, Window>::commit(&parameters, &input, &randomness).unwrap();
220
221        let mut input_bytes = vec![];
222        for (byte_i, input_byte) in input.iter().enumerate() {
223            let cs = cs.ns(|| format!("input_byte_gadget_{}", byte_i));
224            input_bytes.push(UInt8::alloc(cs, || Ok(*input_byte)).unwrap());
225        }
226
227        let randomness =
228            <TestCOMMGadget as CommitmentGadget<TestCOMM, Fq>>::RandomnessGadget::alloc(
229                &mut cs.ns(|| "gadget_randomness"),
230                || Ok(&randomness),
231            )
232            .unwrap();
233        let gadget_parameters =
234            <TestCOMMGadget as CommitmentGadget<TestCOMM, Fq>>::ParametersGadget::alloc(
235                &mut cs.ns(|| "gadget_parameters"),
236                || Ok(&parameters),
237            )
238            .unwrap();
239        let gadget_result =
240            <TestCOMMGadget as CommitmentGadget<TestCOMM, Fq>>::check_commitment_gadget(
241                &mut cs.ns(|| "gadget_evaluation"),
242                &gadget_parameters,
243                &input_bytes,
244                &randomness,
245            )
246            .unwrap();
247
248        let primitive_result = primitive_result.into_affine();
249        assert_eq!(primitive_result.x, gadget_result.x.value.unwrap());
250        assert_eq!(primitive_result.y, gadget_result.y.value.unwrap());
251        assert!(cs.is_satisfied());
252    }
253}