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};
  5use algebra::{to_bytes, Group, ToBytes};
  6use r1cs_core::{ConstraintSystem, SynthesisError};
  7
  8use crate::commitment::CommitmentGadget;
  9use algebra::fields::{Field, PrimeField};
 10use r1cs_std::prelude::*;
 11use std::{borrow::Borrow, marker::PhantomData};
 12
 13#[derive(Derivative)]
 14#[derivative(Clone(bound = "G: Group, W: PedersenWindow, ConstraintF: Field"))]
 15pub struct PedersenCommitmentGadgetParameters<G: Group, W: PedersenWindow, ConstraintF: Field> {
 16    params:  PedersenParameters<G>,
 17    #[doc(hidden)]
 18    _group:  PhantomData<G>,
 19    #[doc(hidden)]
 20    _engine: PhantomData<ConstraintF>,
 21    #[doc(hidden)]
 22    _window: PhantomData<W>,
 23}
 24
 25#[derive(Clone, Debug)]
 26pub struct PedersenRandomnessGadget(Vec<UInt8>);
 27
 28pub struct PedersenCommitmentGadget<G: Group, ConstraintF: Field, GG: GroupGadget<G, ConstraintF>>(
 29    #[doc(hidden)] PhantomData<*const G>,
 30    #[doc(hidden)] PhantomData<*const GG>,
 31    PhantomData<ConstraintF>,
 32);
 33
 34impl<ConstraintF, G, GG, W> CommitmentGadget<PedersenCommitment<G, W>, ConstraintF>
 35    for PedersenCommitmentGadget<G, ConstraintF, GG>
 36where
 37    ConstraintF: PrimeField,
 38    G: Group,
 39    GG: GroupGadget<G, ConstraintF>,
 40    W: PedersenWindow,
 41{
 42    type OutputGadget = GG;
 43    type ParametersGadget = PedersenCommitmentGadgetParameters<G, W, ConstraintF>;
 44    type RandomnessGadget = PedersenRandomnessGadget;
 45
 46    fn check_commitment_gadget<CS: ConstraintSystem<ConstraintF>>(
 47        mut cs: CS,
 48        parameters: &Self::ParametersGadget,
 49        input: &[UInt8],
 50        r: &Self::RandomnessGadget,
 51    ) -> Result<Self::OutputGadget, SynthesisError> {
 52        assert!((input.len() * 8) <= (W::WINDOW_SIZE * W::NUM_WINDOWS));
 53
 54        let mut padded_input = input.to_vec();
 55        // Pad if input length is less than `W::WINDOW_SIZE * W::NUM_WINDOWS`.
 56        if (input.len() * 8) < W::WINDOW_SIZE * W::NUM_WINDOWS {
 57            let current_length = input.len();
 58            for _ in current_length..((W::WINDOW_SIZE * W::NUM_WINDOWS) / 8) {
 59                padded_input.push(UInt8::constant(0u8));
 60            }
 61        }
 62
 63        assert_eq!(padded_input.len() * 8, W::WINDOW_SIZE * W::NUM_WINDOWS);
 64        assert_eq!(parameters.params.generators.len(), W::NUM_WINDOWS);
 65
 66        // Allocate new variable for commitment output.
 67        let input_in_bits: Vec<_> = padded_input
 68            .iter()
 69            .flat_map(|byte| byte.into_bits_le())
 70            .collect();
 71        let input_in_bits = input_in_bits.chunks(W::WINDOW_SIZE);
 72        let mut result = GG::precomputed_base_multiscalar_mul(
 73            cs.ns(|| "multiexp"),
 74            &parameters.params.generators,
 75            input_in_bits,
 76        )?;
 77
 78        // Compute h^r
 79        let rand_bits: Vec<_> = r.0.iter().flat_map(|byte| byte.into_bits_le()).collect();
 80        result.precomputed_base_scalar_mul(
 81            cs.ns(|| "Randomizer"),
 82            rand_bits
 83                .iter()
 84                .zip(&parameters.params.randomness_generator),
 85        )?;
 86
 87        Ok(result)
 88    }
 89}
 90
 91impl<G, W, ConstraintF> AllocGadget<PedersenParameters<G>, ConstraintF>
 92    for PedersenCommitmentGadgetParameters<G, W, ConstraintF>
 93where
 94    G: Group,
 95    W: PedersenWindow,
 96    ConstraintF: PrimeField,
 97{
 98    fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>(
 99        _cs: CS,
100        value_gen: F,
101    ) -> Result<Self, SynthesisError>
102    where
103        F: FnOnce() -> Result<T, SynthesisError>,
104        T: Borrow<PedersenParameters<G>>,
105    {
106        let temp = value_gen()?;
107        let parameters = temp.borrow().clone();
108
109        Ok(PedersenCommitmentGadgetParameters {
110            params:  parameters,
111            _group:  PhantomData,
112            _engine: PhantomData,
113            _window: PhantomData,
114        })
115    }
116
117    fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>(
118        _cs: CS,
119        value_gen: F,
120    ) -> Result<Self, SynthesisError>
121    where
122        F: FnOnce() -> Result<T, SynthesisError>,
123        T: Borrow<PedersenParameters<G>>,
124    {
125        let temp = value_gen()?;
126        let parameters = temp.borrow().clone();
127
128        Ok(PedersenCommitmentGadgetParameters {
129            params:  parameters,
130            _group:  PhantomData,
131            _engine: PhantomData,
132            _window: PhantomData,
133        })
134    }
135}
136
137impl<G, ConstraintF> AllocGadget<PedersenRandomness<G>, ConstraintF> for PedersenRandomnessGadget
138where
139    G: Group,
140    ConstraintF: PrimeField,
141{
142    fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>(
143        cs: CS,
144        value_gen: F,
145    ) -> Result<Self, SynthesisError>
146    where
147        F: FnOnce() -> Result<T, SynthesisError>,
148        T: Borrow<PedersenRandomness<G>>,
149    {
150        let temp = value_gen()?;
151        let randomness = to_bytes![temp.borrow().0].unwrap();
152        Ok(PedersenRandomnessGadget(UInt8::alloc_vec(cs, &randomness)?))
153    }
154
155    fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>(
156        cs: CS,
157        value_gen: F,
158    ) -> Result<Self, SynthesisError>
159    where
160        F: FnOnce() -> Result<T, SynthesisError>,
161        T: Borrow<PedersenRandomness<G>>,
162    {
163        let temp = value_gen()?;
164        let randomness = to_bytes![temp.borrow().0].unwrap();
165        Ok(PedersenRandomnessGadget(UInt8::alloc_input_vec(
166            cs,
167            &randomness,
168        )?))
169    }
170}
171
172#[cfg(test)]
173mod test {
174    use algebra::{
175        fields::jubjub::{fq::Fq, fr::Fr},
176        UniformRand,
177    };
178    use rand::thread_rng;
179
180    use crate::{
181        commitment::{
182            pedersen::{
183                constraints::PedersenCommitmentGadget, PedersenCommitment, PedersenRandomness,
184            },
185            CommitmentGadget, CommitmentScheme,
186        },
187        crh::pedersen::PedersenWindow,
188    };
189    use algebra::curves::{jubjub::JubJubProjective as JubJub, ProjectiveCurve};
190    use r1cs_core::ConstraintSystem;
191    use r1cs_std::{
192        groups::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 thread_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(&parameters, &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(&parameters),
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}