ark-r1cs-std/crypto-primitives/src/crh/pedersen/constraints.rs
crypto-primitives/src/crh/pedersen/constraints.rsRaw
1use crate::{
2 crh::{
3 pedersen::{Parameters, Window, CRH},
4 FixedLengthCRHGadget,
5 },
6 Vec,
7};
8use algebra_core::{Field, ProjectiveCurve};
9use r1cs_core::{Namespace, SynthesisError};
10use r1cs_std::prelude::*;
11
12use core::{borrow::Borrow, marker::PhantomData};
13
14#[derive(Derivative)]
15#[derivative(Clone(bound = "C: ProjectiveCurve, GG: CurveVar<C, ConstraintF<C>>"))]
16pub struct CRHParametersVar<C: ProjectiveCurve, GG: CurveVar<C, ConstraintF<C>>>
17where
18 for<'a> &'a GG: GroupOpsBounds<'a, C, GG>,
19{
20 params: Parameters<C>,
21 #[doc(hidden)]
22 _group_g: PhantomData<GG>,
23}
24
25type ConstraintF<C> = <<C as ProjectiveCurve>::BaseField as Field>::BasePrimeField;
26pub struct CRHGadget<C: ProjectiveCurve, GG: CurveVar<C, ConstraintF<C>>, W: Window>
27where
28 for<'a> &'a GG: GroupOpsBounds<'a, C, GG>,
29{
30 #[doc(hidden)]
31 _group: PhantomData<*const C>,
32 #[doc(hidden)]
33 _group_var: PhantomData<*const GG>,
34 #[doc(hidden)]
35 _window: PhantomData<*const W>,
36}
37
38impl<C, GG, W> FixedLengthCRHGadget<CRH<C, W>, ConstraintF<C>> for CRHGadget<C, GG, W>
39where
40 C: ProjectiveCurve,
41 GG: CurveVar<C, ConstraintF<C>>,
42 W: Window,
43 for<'a> &'a GG: GroupOpsBounds<'a, C, GG>,
44{
45 type OutputVar = GG;
46 type ParametersVar = CRHParametersVar<C, GG>;
47
48 fn evaluate(
49 parameters: &Self::ParametersVar,
50 input: &[UInt8<ConstraintF<C>>],
51 ) -> Result<Self::OutputVar, SynthesisError> {
52 let mut padded_input = input.to_vec();
53 // Pad the input if it is not the current length.
54 if input.len() * 8 < W::WINDOW_SIZE * W::NUM_WINDOWS {
55 let current_length = input.len();
56 for _ in current_length..(W::WINDOW_SIZE * W::NUM_WINDOWS / 8) {
57 padded_input.push(UInt8::constant(0u8));
58 }
59 }
60 assert_eq!(padded_input.len() * 8, W::WINDOW_SIZE * W::NUM_WINDOWS);
61 assert_eq!(parameters.params.generators.len(), W::NUM_WINDOWS);
62
63 // Allocate new variable for the result.
64 let input_in_bits: Vec<_> = padded_input.iter().flat_map(|b| b.into_bits_le()).collect();
65 let input_in_bits = input_in_bits.chunks(W::WINDOW_SIZE);
66 let result =
67 GG::precomputed_base_multiscalar_mul(¶meters.params.generators, input_in_bits)?;
68
69 Ok(result)
70 }
71}
72
73impl<C, GG> AllocVar<Parameters<C>, ConstraintF<C>> for CRHParametersVar<C, GG>
74where
75 C: ProjectiveCurve,
76 GG: CurveVar<C, ConstraintF<C>>,
77 for<'a> &'a GG: GroupOpsBounds<'a, C, GG>,
78{
79 fn new_variable<T: Borrow<Parameters<C>>>(
80 _cs: impl Into<Namespace<ConstraintF<C>>>,
81 f: impl FnOnce() -> Result<T, SynthesisError>,
82 _mode: AllocationMode,
83 ) -> Result<Self, SynthesisError> {
84 let params = f()?.borrow().clone();
85 Ok(CRHParametersVar {
86 params,
87 _group_g: PhantomData,
88 })
89 }
90}
91
92#[cfg(test)]
93mod test {
94 use crate::crh::{pedersen, pedersen::constraints::*, FixedLengthCRH, FixedLengthCRHGadget};
95 use algebra::{
96 ed_on_bls12_381::{EdwardsProjective as JubJub, Fq as Fr},
97 test_rng,
98 };
99 use r1cs_core::{ConstraintSystem, ConstraintSystemRef};
100 use r1cs_std::ed_on_bls12_381::EdwardsVar;
101 use rand::Rng;
102
103 type TestCRH = pedersen::CRH<JubJub, Window>;
104 type TestCRHGadget = CRHGadget<JubJub, EdwardsVar, Window>;
105
106 #[derive(Clone, PartialEq, Eq, Hash)]
107 pub(super) struct Window;
108
109 impl pedersen::Window for Window {
110 const WINDOW_SIZE: usize = 128;
111 const NUM_WINDOWS: usize = 8;
112 }
113
114 fn generate_input<R: Rng>(
115 cs: ConstraintSystemRef<Fr>,
116 rng: &mut R,
117 ) -> ([u8; 128], Vec<UInt8<Fr>>) {
118 let mut input = [1u8; 128];
119 rng.fill_bytes(&mut input);
120
121 let mut input_bytes = vec![];
122 for byte in input.iter() {
123 input_bytes.push(UInt8::new_witness(cs.clone(), || Ok(byte)).unwrap());
124 }
125 (input, input_bytes)
126 }
127
128 #[test]
129 fn test_native_equality() {
130 let rng = &mut test_rng();
131 let cs = ConstraintSystem::<Fr>::new_ref();
132
133 let (input, input_var) = generate_input(cs.clone(), rng);
134
135 let parameters = TestCRH::setup(rng).unwrap();
136 let primitive_result = TestCRH::evaluate(¶meters, &input).unwrap();
137
138 let parameters_var =
139 CRHParametersVar::new_constant(cs.ns("CRH Parameters"), ¶meters).unwrap();
140
141 let result_var = TestCRHGadget::evaluate(¶meters_var, &input_var).unwrap();
142
143 let primitive_result = primitive_result;
144 assert_eq!(primitive_result, result_var.value().unwrap());
145 assert!(cs.is_satisfied().unwrap());
146 }
147}