sonobe_primitives/transcripts/absorbable.rs
1//! This module defines traits for converting values into a form absorbable by a
2//! sponge or transcript.
3//!
4//! Implementations are provided for some primitive types as well as composite
5//! types (references, tuples, slices, etc.).
6
7use ark_ff::PrimeField;
8use ark_r1cs_std::fields::fp::FpVar;
9use ark_relations::gr1cs::SynthesisError;
10
11// TODO (@winderica):
12//
13// Ideally this trait should be defined as follows, so that we can use it for
14// absorbing values into bits/bytes/etc., in addition to field elements.
15// (Although Arkworks' `Absorb` trait covers both bytes and field elements, it
16// requires downstream types to support absorbing into both as well, even if the
17// downstream type doesn't support/is unrelated to one absorbing target.)
18//
19// ```rs
20// pub trait Absorbable<F> {
21// fn absorb_into(&self, dest: &mut Vec<F>);
22
23// fn to_absorbable(&self) -> Vec<F> {
24// let mut result = Vec::new();
25// self.absorb_into(&mut result);
26// result
27// }
28// }
29// ```
30//
31// But my attempt was unsuccessful. In our use case, `SonobeField` needs to be
32// absorbed into prime fields that are unknown when making the definition. Due
33// to the `F` type parameter in `Absorbable<F>`, I have three options:
34// 1. Define `SonobeField` as `SonobeField<F>: Absorbable<F>`. This means that
35// I need to add `F` to everywhere `SonobeField` is used, making the codebase
36// much more verbose.
37// 2. Remove the `Absorbable` bound from `SonobeField`, but instead manually add
38// `Absorbable<F>` to `T: SonobeField`'s bounds whenever we need `T` to be
39// absorbable. This also increases the verbosity a lot.
40// 3. Wait for https://github.com/rust-lang/rust/issues/108185 to be resolved,
41// so I can define `SonobeField: for <F: PrimeField> Absorbable<F>`.
42// Personally I think the best option is 3. File an issue or submit a PR if you
43// have better solution :)
44/// [`Absorbable`] is a trait for objects that can be absorbed into a sponge or
45/// transcript.
46pub trait Absorbable {
47 /// [`Absorbable::absorb_into`] absorbs `self` into the given destination
48 /// vector of field elements.
49 ///
50 /// The implementation should append the field elements representing `self`
51 /// to `dest`.
52 fn absorb_into<F: PrimeField>(&self, dest: &mut Vec<F>);
53}
54
55impl Absorbable for usize {
56 fn absorb_into<F: PrimeField>(&self, dest: &mut Vec<F>) {
57 dest.push(F::from(*self as u64));
58 }
59}
60
61impl<T: Absorbable> Absorbable for &T {
62 fn absorb_into<F: PrimeField>(&self, dest: &mut Vec<F>) {
63 (*self).absorb_into(dest);
64 }
65}
66
67impl<T: Absorbable> Absorbable for (T, T) {
68 fn absorb_into<F: PrimeField>(&self, dest: &mut Vec<F>) {
69 self.0.absorb_into(dest);
70 self.1.absorb_into(dest);
71 }
72}
73
74impl<T: Absorbable> Absorbable for [T] {
75 fn absorb_into<F: PrimeField>(&self, dest: &mut Vec<F>) {
76 for t in self.iter() {
77 t.absorb_into(dest);
78 }
79 }
80}
81
82impl<T: Absorbable, const N: usize> Absorbable for [T; N] {
83 fn absorb_into<F: PrimeField>(&self, dest: &mut Vec<F>) {
84 self.as_ref().absorb_into(dest);
85 }
86}
87
88impl<T: Absorbable> Absorbable for Vec<T> {
89 fn absorb_into<F: PrimeField>(&self, dest: &mut Vec<F>) {
90 self.as_slice().absorb_into(dest);
91 }
92}
93
94/// [`AbsorbableVar`] is a trait for in-circuit variables that can be absorbed
95/// into a sponge or transcript defined over constraint field `F`.
96///
97/// Matches [`Absorbable`].
98pub trait AbsorbableVar<F: PrimeField> {
99 /// [`AbsorbableVar::absorb_into`] absorbs `self` into the given
100 /// destination vector of field element variables.
101 ///
102 /// The implementation should append the field element variables
103 /// representing `self` to `dest`.
104 fn absorb_into(&self, dest: &mut Vec<FpVar<F>>) -> Result<(), SynthesisError>;
105}
106
107impl<F: PrimeField, T: AbsorbableVar<F>> AbsorbableVar<F> for &T {
108 fn absorb_into(&self, dest: &mut Vec<FpVar<F>>) -> Result<(), SynthesisError> {
109 (*self).absorb_into(dest)
110 }
111}
112
113impl<F: PrimeField, T: AbsorbableVar<F>> AbsorbableVar<F> for (T, T) {
114 fn absorb_into(&self, dest: &mut Vec<FpVar<F>>) -> Result<(), SynthesisError> {
115 self.0.absorb_into(dest)?;
116 self.1.absorb_into(dest)
117 }
118}
119
120impl<F: PrimeField, T: AbsorbableVar<F>> AbsorbableVar<F> for [T] {
121 fn absorb_into(&self, dest: &mut Vec<FpVar<F>>) -> Result<(), SynthesisError> {
122 self.iter().try_for_each(|t| t.absorb_into(dest))
123 }
124}
125
126impl<F: PrimeField, T: AbsorbableVar<F>, const N: usize> AbsorbableVar<F> for [T; N] {
127 fn absorb_into(&self, dest: &mut Vec<FpVar<F>>) -> Result<(), SynthesisError> {
128 self.as_ref().absorb_into(dest)
129 }
130}
131
132impl<F: PrimeField, T: AbsorbableVar<F>> AbsorbableVar<F> for Vec<T> {
133 fn absorb_into(&self, dest: &mut Vec<FpVar<F>>) -> Result<(), SynthesisError> {
134 self.as_slice().absorb_into(dest)
135 }
136}