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