ark_sponge/constraints/
absorb.rs1use ark_ec::{ModelParameters, SWModelParameters, TEModelParameters};
2use ark_ff::{Field, PrimeField};
3use ark_r1cs_std::bits::boolean::Boolean;
4use ark_r1cs_std::bits::uint8::UInt8;
5use ark_r1cs_std::fields::fp::FpVar;
6use ark_r1cs_std::fields::{FieldOpsBounds, FieldVar};
7use ark_r1cs_std::groups::curves::short_weierstrass::{
8 AffineVar as SWAffineVar, ProjectiveVar as SWProjectiveVar,
9};
10use ark_r1cs_std::groups::curves::twisted_edwards::AffineVar as TEAffineVar;
11use ark_r1cs_std::{ToBytesGadget, ToConstraintFieldGadget};
12use ark_relations::r1cs::SynthesisError;
13use ark_std::vec;
14use ark_std::vec::Vec;
15pub trait AbsorbGadget<F: PrimeField> {
18 fn to_sponge_bytes(&self) -> Result<Vec<UInt8<F>>, SynthesisError>;
21
22 fn batch_to_sponge_bytes(batch: &[Self]) -> Result<Vec<UInt8<F>>, SynthesisError>
24 where
25 Self: Sized,
26 {
27 let mut result = Vec::new();
28 for item in batch {
29 result.append(&mut (item.to_sponge_bytes()?))
30 }
31 Ok(result)
32 }
33
34 fn to_sponge_field_elements(&self) -> Result<Vec<FpVar<F>>, SynthesisError>;
36
37 fn batch_to_sponge_field_elements(batch: &[Self]) -> Result<Vec<FpVar<F>>, SynthesisError>
39 where
40 Self: Sized,
41 {
42 let mut output = Vec::new();
43 for absorbable in batch {
44 output.append(&mut absorbable.to_sponge_field_elements()?);
45 }
46
47 Ok(output)
48 }
49}
50
51impl<F: PrimeField> AbsorbGadget<F> for UInt8<F> {
52 fn to_sponge_bytes(&self) -> Result<Vec<UInt8<F>>, SynthesisError> {
53 Ok(vec![self.clone()])
54 }
55
56 fn to_sponge_field_elements(&self) -> Result<Vec<FpVar<F>>, SynthesisError> {
57 vec![self.clone()].to_constraint_field()
58 }
59
60 fn batch_to_sponge_field_elements(batch: &[Self]) -> Result<Vec<FpVar<F>>, SynthesisError> {
61 let mut bytes = UInt8::constant_vec((batch.len() as u64).to_le_bytes().as_ref());
64 bytes.extend_from_slice(batch);
65 bytes.to_constraint_field()
66 }
67}
68
69impl<F: PrimeField> AbsorbGadget<F> for Boolean<F> {
70 fn to_sponge_bytes(&self) -> Result<Vec<UInt8<F>>, SynthesisError> {
71 self.to_bytes()
72 }
73
74 fn to_sponge_field_elements(&self) -> Result<Vec<FpVar<F>>, SynthesisError> {
75 Ok(vec![FpVar::from(self.clone())])
76 }
77}
78
79impl<F: PrimeField> AbsorbGadget<F> for FpVar<F> {
80 fn to_sponge_bytes(&self) -> Result<Vec<UInt8<F>>, SynthesisError> {
81 self.to_bytes()
82 }
83
84 fn to_sponge_field_elements(&self) -> Result<Vec<FpVar<F>>, SynthesisError> {
85 Ok(vec![self.clone()])
86 }
87
88 fn batch_to_sponge_field_elements(batch: &[Self]) -> Result<Vec<FpVar<F>>, SynthesisError> {
89 Ok(batch.to_vec())
90 }
91}
92
93macro_rules! impl_absorbable_group {
94 ($group:ident, $params:ident) => {
95 impl<P, F> AbsorbGadget<<P::BaseField as Field>::BasePrimeField> for $group<P, F>
96 where
97 P: $params,
98 F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
99 for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
100 F: ToConstraintFieldGadget<<P::BaseField as Field>::BasePrimeField>,
101 {
102 fn to_sponge_bytes(
103 &self,
104 ) -> Result<Vec<UInt8<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> {
105 self.to_constraint_field()?.to_sponge_bytes()
106 }
107
108 fn to_sponge_field_elements(
109 &self,
110 ) -> Result<Vec<FpVar<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> {
111 self.to_constraint_field()
112 }
113 }
114 };
115}
116
117impl_absorbable_group!(TEAffineVar, TEModelParameters);
118impl_absorbable_group!(SWAffineVar, SWModelParameters);
119
120impl<P, F> AbsorbGadget<<P::BaseField as Field>::BasePrimeField> for SWProjectiveVar<P, F>
121where
122 P: SWModelParameters,
123 F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
124 for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
125 F: ToConstraintFieldGadget<<P::BaseField as Field>::BasePrimeField>,
126{
127 fn to_sponge_bytes(
128 &self,
129 ) -> Result<
130 Vec<UInt8<<<P as ModelParameters>::BaseField as Field>::BasePrimeField>>,
131 SynthesisError,
132 > {
133 self.to_bytes()
134 }
135
136 fn to_sponge_field_elements(
137 &self,
138 ) -> Result<
139 Vec<FpVar<<<P as ModelParameters>::BaseField as Field>::BasePrimeField>>,
140 SynthesisError,
141 > {
142 self.to_affine()?.to_sponge_field_elements()
143 }
144}
145
146impl<F: PrimeField, A: AbsorbGadget<F>> AbsorbGadget<F> for &[A] {
147 fn to_sponge_bytes(&self) -> Result<Vec<UInt8<F>>, SynthesisError> {
148 A::batch_to_sponge_bytes(self)
149 }
150
151 fn to_sponge_field_elements(&self) -> Result<Vec<FpVar<F>>, SynthesisError> {
152 A::batch_to_sponge_field_elements(self)
153 }
154}
155
156impl<F: PrimeField, A: AbsorbGadget<F>> AbsorbGadget<F> for Vec<A> {
157 fn to_sponge_bytes(&self) -> Result<Vec<UInt8<F>>, SynthesisError> {
158 self.as_slice().to_sponge_bytes()
159 }
160
161 fn to_sponge_field_elements(&self) -> Result<Vec<FpVar<F>>, SynthesisError> {
162 self.as_slice().to_sponge_field_elements()
163 }
164}
165
166impl<F: PrimeField, A: AbsorbGadget<F>> AbsorbGadget<F> for Option<A> {
167 fn to_sponge_bytes(&self) -> Result<Vec<UInt8<F>>, SynthesisError> {
168 let mut output = Vec::new();
169 output.append(&mut (Boolean::Constant(self.is_some()).to_sponge_bytes()?));
170 if let Some(item) = self {
171 output.append(&mut (item.to_sponge_bytes()?))
172 }
173 Ok(output)
174 }
175
176 fn to_sponge_field_elements(&self) -> Result<Vec<FpVar<F>>, SynthesisError> {
177 let mut output = vec![FpVar::from(Boolean::constant(self.is_some()))];
178 if let Some(absorbable) = self.as_ref() {
179 output.append(&mut absorbable.to_sponge_field_elements()?);
180 }
181 Ok(output)
182 }
183}
184
185impl<F: PrimeField, A: AbsorbGadget<F>> AbsorbGadget<F> for &A {
186 fn to_sponge_bytes(&self) -> Result<Vec<UInt8<F>>, SynthesisError> {
187 (*self).to_sponge_bytes()
188 }
189
190 fn to_sponge_field_elements(&self) -> Result<Vec<FpVar<F>>, SynthesisError> {
191 (*self).to_sponge_field_elements()
192 }
193}
194
195#[macro_export]
199macro_rules! absorb_gadget {
200 ($sponge:expr, $($absorbable:expr),+ ) => {
201 $(
202 CryptographicSpongeVar::absorb($sponge, &$absorbable)?;
203 )+
204 };
205}
206
207#[macro_export]
209macro_rules! collect_sponge_field_elements_gadget {
210 ($head:expr $(, $tail:expr)* ) => {
211 {
212 let mut output = AbsorbGadget::to_sponge_field_elements(&$head)?;
213 $(
214 output.append(&mut AbsorbGadget::to_sponge_field_elements(&$tail)?);
215 )*
216
217 Ok(output)
218 }
219 };
220}
221
222#[cfg(test)]
223mod tests {
224 use crate::constraints::AbsorbGadget;
225 use crate::Absorb;
226 use ark_r1cs_std::alloc::AllocVar;
227 use ark_r1cs_std::fields::fp::FpVar;
228 use ark_r1cs_std::uint8::UInt8;
229 use ark_r1cs_std::R1CSVar;
230 use ark_relations::r1cs::ConstraintSystem;
231 use ark_relations::*;
232 use ark_std::{test_rng, UniformRand};
233 use ark_test_curves::bls12_381::Fr;
234
235 #[test]
236 fn consistency_check() {
237 let cs = ConstraintSystem::<Fr>::new_ref();
239 let mut rng = test_rng();
240 let data = vec![0u8, 1u8, 2u8, 3u8, 4u8, 5u8];
242 let data_var = UInt8::new_input_vec(ns!(cs, "u8data"), &data).unwrap();
243
244 let native_bytes = data.to_sponge_bytes_as_vec();
245 let constraint_bytes = data_var.to_sponge_bytes().unwrap();
246
247 assert_eq!(constraint_bytes.value().unwrap(), native_bytes);
248
249 let data: Vec<_> = (0..10).map(|_| Fr::rand(&mut rng)).collect();
252 let data_var: Vec<_> = data
253 .iter()
254 .map(|item| FpVar::new_input(ns!(cs, "fpdata"), || Ok(*item)).unwrap())
255 .collect();
256
257 let native_bytes = data.to_sponge_bytes_as_vec();
258 let constraint_bytes = data_var.to_sponge_bytes().unwrap();
259 assert_eq!(constraint_bytes.value().unwrap(), native_bytes);
260
261 assert!(cs.is_satisfied().unwrap())
262 }
263}