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