Skip to main content

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}