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<Boolean<_>> = padded_input
65 .iter()
66 .flat_map(|b| b.to_bits_le().unwrap())
67 .collect();
68 let input_in_bits = input_in_bits.chunks(W::WINDOW_SIZE);
69 let result =
70 GG::precomputed_base_multiscalar_mul_le(¶meters.params.generators, input_in_bits)?;
71 Ok(result)
72 }
73}
74
75impl<C, GG> AllocVar<Parameters<C>, ConstraintF<C>> for CRHParametersVar<C, GG>
76where
77 C: ProjectiveCurve,
78 GG: CurveVar<C, ConstraintF<C>>,
79 for<'a> &'a GG: GroupOpsBounds<'a, C, GG>,
80{
81 fn new_variable<T: Borrow<Parameters<C>>>(
82 _cs: impl Into<Namespace<ConstraintF<C>>>,
83 f: impl FnOnce() -> Result<T, SynthesisError>,
84 _mode: AllocationMode,
85 ) -> Result<Self, SynthesisError> {
86 let params = f()?.borrow().clone();
87 Ok(CRHParametersVar {
88 params,
89 _group_g: PhantomData,
90 })
91 }
92}
93
94#[cfg(test)]
95mod test {
96 use crate::crh::{pedersen, pedersen::constraints::*, FixedLengthCRH, FixedLengthCRHGadget};
97 use algebra::{
98 ed_on_bls12_381::{EdwardsProjective as JubJub, Fq as Fr},
99 test_rng,
100 };
101 use r1cs_core::{ConstraintSystem, ConstraintSystemRef};
102 use r1cs_std::ed_on_bls12_381::EdwardsVar;
103 use rand::Rng;
104
105 type TestCRH = pedersen::CRH<JubJub, Window>;
106 type TestCRHGadget = CRHGadget<JubJub, EdwardsVar, Window>;
107
108 #[derive(Clone, PartialEq, Eq, Hash)]
109 pub(super) struct Window;
110
111 impl pedersen::Window for Window {
112 const WINDOW_SIZE: usize = 128;
113 const NUM_WINDOWS: usize = 8;
114 }
115
116 fn generate_input<R: Rng>(
117 cs: ConstraintSystemRef<Fr>,
118 rng: &mut R,
119 ) -> ([u8; 128], Vec<UInt8<Fr>>) {
120 let mut input = [1u8; 128];
121 rng.fill_bytes(&mut input);
122
123 let mut input_bytes = vec![];
124 for byte in input.iter() {
125 input_bytes.push(UInt8::new_witness(cs.clone(), || Ok(byte)).unwrap());
126 }
127 (input, input_bytes)
128 }
129
130 #[test]
131 fn test_native_equality() {
132 let rng = &mut test_rng();
133 let cs = ConstraintSystem::<Fr>::new_ref();
134
135 let (input, input_var) = generate_input(cs.clone(), rng);
136
137 let parameters = TestCRH::setup(rng).unwrap();
138 let primitive_result = TestCRH::evaluate(¶meters, &input).unwrap();
139
140 let parameters_var =
141 CRHParametersVar::new_constant(cs.ns("CRH Parameters"), ¶meters).unwrap();
142
143 let result_var = TestCRHGadget::evaluate(¶meters_var, &input_var).unwrap();
144
145 let primitive_result = primitive_result;
146 assert_eq!(primitive_result, result_var.value().unwrap());
147 assert!(cs.is_satisfied().unwrap());
148 }
149}