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::{Commitment, Parameters, Randomness},
  3    crh::pedersen::Window,
  4    Vec,
  5};
  6use algebra_core::{
  7    fields::{Field, PrimeField},
  8    to_bytes, ProjectiveCurve, Zero,
  9};
 10use r1cs_core::{Namespace, SynthesisError};
 11
 12use core::{borrow::Borrow, marker::PhantomData};
 13use r1cs_std::prelude::*;
 14
 15type ConstraintF<C> = <<C as ProjectiveCurve>::BaseField as Field>::BasePrimeField;
 16
 17#[derive(Derivative)]
 18#[derivative(Clone(bound = "C: ProjectiveCurve, GG: CurveVar<C, ConstraintF<C>>"))]
 19pub struct ParametersVar<C: ProjectiveCurve, GG: CurveVar<C, ConstraintF<C>>>
 20where
 21    for<'a> &'a GG: GroupOpsBounds<'a, C, GG>,
 22{
 23    params: Parameters<C>,
 24    #[doc(hidden)]
 25    _group_var: PhantomData<GG>,
 26}
 27
 28#[derive(Clone, Debug)]
 29pub struct RandomnessVar<F: Field>(Vec<UInt8<F>>);
 30
 31pub struct CommGadget<C: ProjectiveCurve, GG: CurveVar<C, ConstraintF<C>>, W: Window>
 32where
 33    for<'a> &'a GG: GroupOpsBounds<'a, C, GG>,
 34{
 35    #[doc(hidden)]
 36    _curve: PhantomData<*const C>,
 37    #[doc(hidden)]
 38    _group_var: PhantomData<*const GG>,
 39    #[doc(hidden)]
 40    _window: PhantomData<*const W>,
 41}
 42
 43impl<C, GG, W> crate::commitment::CommitmentGadget<Commitment<C, W>, ConstraintF<C>>
 44    for CommGadget<C, GG, W>
 45where
 46    C: ProjectiveCurve,
 47    GG: CurveVar<C, ConstraintF<C>>,
 48    W: Window,
 49    for<'a> &'a GG: GroupOpsBounds<'a, C, GG>,
 50    ConstraintF<C>: PrimeField,
 51{
 52    type OutputVar = GG;
 53    type ParametersVar = ParametersVar<C, GG>;
 54    type RandomnessVar = RandomnessVar<ConstraintF<C>>;
 55
 56    #[tracing::instrument(target = "r1cs", skip(parameters, r))]
 57    fn commit(
 58        parameters: &Self::ParametersVar,
 59        input: &[UInt8<ConstraintF<C>>],
 60        r: &Self::RandomnessVar,
 61    ) -> Result<Self::OutputVar, SynthesisError> {
 62        assert!((input.len() * 8) <= (W::WINDOW_SIZE * W::NUM_WINDOWS));
 63
 64        let mut padded_input = input.to_vec();
 65        // Pad if input length is less than `W::WINDOW_SIZE * W::NUM_WINDOWS`.
 66        if (input.len() * 8) < W::WINDOW_SIZE * W::NUM_WINDOWS {
 67            let current_length = input.len();
 68            for _ in current_length..((W::WINDOW_SIZE * W::NUM_WINDOWS) / 8) {
 69                padded_input.push(UInt8::constant(0u8));
 70            }
 71        }
 72
 73        assert_eq!(padded_input.len() * 8, W::WINDOW_SIZE * W::NUM_WINDOWS);
 74        assert_eq!(parameters.params.generators.len(), W::NUM_WINDOWS);
 75
 76        // Allocate new variable for commitment output.
 77        let input_in_bits: Vec<Boolean<_>> = padded_input
 78            .iter()
 79            .flat_map(|byte| byte.to_bits_le().unwrap())
 80            .collect();
 81        let input_in_bits = input_in_bits.chunks(W::WINDOW_SIZE);
 82        let mut result =
 83            GG::precomputed_base_multiscalar_mul_le(&parameters.params.generators, input_in_bits)?;
 84
 85        // Compute h^r
 86        let rand_bits: Vec<_> =
 87            r.0.iter()
 88                .flat_map(|byte| byte.to_bits_le().unwrap())
 89                .collect();
 90        result.precomputed_base_scalar_mul_le(
 91            rand_bits
 92                .iter()
 93                .zip(&parameters.params.randomness_generator),
 94        )?;
 95
 96        Ok(result)
 97    }
 98}
 99
100impl<C, GG> AllocVar<Parameters<C>, ConstraintF<C>> for ParametersVar<C, GG>
101where
102    C: ProjectiveCurve,
103    GG: CurveVar<C, ConstraintF<C>>,
104    for<'a> &'a GG: GroupOpsBounds<'a, C, GG>,
105{
106    fn new_variable<T: Borrow<Parameters<C>>>(
107        _cs: impl Into<Namespace<ConstraintF<C>>>,
108        f: impl FnOnce() -> Result<T, SynthesisError>,
109        _mode: AllocationMode,
110    ) -> Result<Self, SynthesisError> {
111        let params = f()?.borrow().clone();
112        Ok(ParametersVar {
113            params,
114            _group_var: PhantomData,
115        })
116    }
117}
118
119impl<C, F> AllocVar<Randomness<C>, F> for RandomnessVar<F>
120where
121    C: ProjectiveCurve,
122    F: PrimeField,
123{
124    fn new_variable<T: Borrow<Randomness<C>>>(
125        cs: impl Into<Namespace<F>>,
126        f: impl FnOnce() -> Result<T, SynthesisError>,
127        mode: AllocationMode,
128    ) -> Result<Self, SynthesisError> {
129        let r = to_bytes![&f().map(|b| b.borrow().0).unwrap_or(C::ScalarField::zero())].unwrap();
130        match mode {
131            AllocationMode::Constant => Ok(Self(UInt8::constant_vec(&r))),
132            AllocationMode::Input => UInt8::new_input_vec(cs, &r).map(Self),
133            AllocationMode::Witness => UInt8::new_witness_vec(cs, &r).map(Self),
134        }
135    }
136}
137
138#[cfg(test)]
139mod test {
140    use algebra::{
141        ed_on_bls12_381::{EdwardsProjective as JubJub, Fq, Fr},
142        test_rng, UniformRand,
143    };
144
145    use crate::{
146        commitment::{
147            pedersen::{constraints::CommGadget, Commitment, Randomness},
148            CommitmentGadget, CommitmentScheme,
149        },
150        crh::pedersen,
151    };
152    use r1cs_core::ConstraintSystem;
153    use r1cs_std::{ed_on_bls12_381::EdwardsVar, prelude::*};
154
155    #[test]
156    fn commitment_gadget_test() {
157        let cs = ConstraintSystem::<Fq>::new_ref();
158
159        #[derive(Clone, PartialEq, Eq, Hash)]
160        pub(super) struct Window;
161
162        impl pedersen::Window for Window {
163            const WINDOW_SIZE: usize = 4;
164            const NUM_WINDOWS: usize = 8;
165        }
166
167        let input = [1u8; 4];
168
169        let rng = &mut test_rng();
170
171        type TestCOMM = Commitment<JubJub, Window>;
172        type TestCOMMGadget = CommGadget<JubJub, EdwardsVar, Window>;
173
174        let randomness = Randomness(Fr::rand(rng));
175
176        let parameters = Commitment::<JubJub, Window>::setup(rng).unwrap();
177        let primitive_result =
178            Commitment::<JubJub, Window>::commit(&parameters, &input, &randomness).unwrap();
179
180        let mut input_var = vec![];
181        for input_byte in input.iter() {
182            input_var.push(UInt8::new_witness(cs.clone(), || Ok(*input_byte)).unwrap());
183        }
184
185        let randomness_var =
186            <TestCOMMGadget as CommitmentGadget<TestCOMM, Fq>>::RandomnessVar::new_witness(
187                r1cs_core::ns!(cs, "gadget_randomness"),
188                || Ok(&randomness),
189            )
190            .unwrap();
191        let parameters_var =
192            <TestCOMMGadget as CommitmentGadget<TestCOMM, Fq>>::ParametersVar::new_witness(
193                r1cs_core::ns!(cs, "gadget_parameters"),
194                || Ok(&parameters),
195            )
196            .unwrap();
197        let result_var =
198            TestCOMMGadget::commit(&parameters_var, &input_var, &randomness_var).unwrap();
199
200        let primitive_result = primitive_result;
201        assert_eq!(primitive_result, result_var.value().unwrap());
202        assert!(cs.is_satisfied().unwrap());
203    }
204}