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_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            &parameters.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(&parameters.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(&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}