Skip to main content

liminal_ark_pnbr_sponge/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2//! A crate for the cryptographic sponge trait.
3#![deny(
4    const_err,
5    future_incompatible,
6    missing_docs,
7    non_shorthand_field_patterns,
8    renamed_and_removed_lints,
9    rust_2018_idioms,
10    stable_features,
11    trivial_casts,
12    trivial_numeric_casts,
13    unused,
14    variant_size_differences
15)]
16#![forbid(unsafe_code)]
17
18use ark_ff::{FpParameters, PrimeField};
19use ark_std::vec;
20use ark_std::vec::Vec;
21
22/// Infrastructure for the constraints counterparts.
23#[cfg(feature = "r1cs")]
24pub mod constraints;
25
26mod absorb;
27pub use absorb::*;
28
29/// The sponge for Poseidon
30///
31/// This implementation of Poseidon is entirely from Fractal's implementation in [COS20][cos]
32/// with small syntax changes.
33///
34/// [cos]: https://eprint.iacr.org/2019/1076
35pub mod poseidon;
36
37/// An enum for specifying the output field element size.
38#[derive(Clone, Copy, Eq, PartialEq)]
39pub enum FieldElementSize {
40    /// Sample field elements from the entire field.
41    Full,
42
43    /// Sample field elements from a subset of the field, specified by the maximum number of bits.
44    Truncated(usize),
45}
46
47impl FieldElementSize {
48    pub(crate) fn num_bits<F: PrimeField>(&self) -> usize {
49        if let FieldElementSize::Truncated(num_bits) = self {
50            if *num_bits > (F::Params::MODULUS_BITS as usize) {
51                panic!("num_bits is greater than the capacity of the field.")
52            }
53        };
54        F::Params::CAPACITY as usize
55    }
56
57    /// Calculate the sum of field element sizes in `elements`.
58    pub fn sum<F: PrimeField>(elements: &[Self]) -> usize {
59        elements.iter().map(|item| item.num_bits::<F>()).sum()
60    }
61}
62
63/// Default implementation of `CryptographicSponge::squeeze_field_elements_with_sizes`
64pub(crate) fn squeeze_field_elements_with_sizes_default_impl<F: PrimeField>(
65    sponge: &mut impl CryptographicSponge,
66    sizes: &[FieldElementSize],
67) -> Vec<F> {
68    if sizes.len() == 0 {
69        return Vec::new();
70    }
71
72    let mut total_bits = 0usize;
73    for size in sizes {
74        total_bits += size.num_bits::<F>();
75    }
76
77    let bits = sponge.squeeze_bits(total_bits);
78    let mut bits_window = bits.as_slice();
79
80    let mut output = Vec::with_capacity(sizes.len());
81    for size in sizes {
82        let num_bits = size.num_bits::<F>();
83        let nonnative_bits_le: Vec<bool> = bits_window[..num_bits].to_vec();
84        bits_window = &bits_window[num_bits..];
85
86        let nonnative_bytes = nonnative_bits_le
87            .chunks(8)
88            .map(|bits| {
89                let mut byte = 0u8;
90                for (i, &bit) in bits.into_iter().enumerate() {
91                    if bit {
92                        byte += 1 << i;
93                    }
94                }
95                byte
96            })
97            .collect::<Vec<_>>();
98
99        output.push(F::from_le_bytes_mod_order(nonnative_bytes.as_slice()));
100    }
101
102    output
103}
104
105/// The interface for a cryptographic sponge.
106/// A sponge can `absorb` or take in inputs and later `squeeze` or output bytes or field elements.
107/// The outputs are dependent on previous `absorb` and `squeeze` calls.
108pub trait CryptographicSponge: Clone {
109    /// Parameters used by the sponge.
110    type Parameters;
111
112    /// Initialize a new instance of the sponge.
113    fn new(params: &Self::Parameters) -> Self;
114
115    /// Absorb an input into the sponge.
116    fn absorb(&mut self, input: &impl Absorb);
117
118    /// Squeeze `num_bytes` bytes from the sponge.
119    fn squeeze_bytes(&mut self, num_bytes: usize) -> Vec<u8>;
120
121    /// Squeeze `num_bits` bits from the sponge.
122    fn squeeze_bits(&mut self, num_bits: usize) -> Vec<bool>;
123
124    /// Squeeze `sizes.len()` field elements from the sponge, where the `i`-th element of
125    /// the output has size `sizes[i]`.
126    ///
127    /// If the implementation is field-based, to squeeze native field elements,
128    /// call `self.squeeze_native_field_elements` instead.
129    ///
130    /// TODO: Support general Field.
131    ///
132    /// Note that when `FieldElementSize` is `FULL`, the output is not strictly uniform. Output
133    /// space is uniform in \[0, 2^{F::MODULUS_BITS - 1}\]
134    fn squeeze_field_elements_with_sizes<F: PrimeField>(
135        &mut self,
136        sizes: &[FieldElementSize],
137    ) -> Vec<F> {
138        squeeze_field_elements_with_sizes_default_impl(self, sizes)
139    }
140
141    /// Squeeze `num_elements` nonnative field elements from the sponge.
142    ///
143    /// Because of rust limitation, for field-based implementation, using this method to squeeze
144    /// native field elements will have runtime casting cost. For better efficiency, use `squeeze_native_field_elements`.
145    fn squeeze_field_elements<F: PrimeField>(&mut self, num_elements: usize) -> Vec<F> {
146        self.squeeze_field_elements_with_sizes::<F>(
147            vec![FieldElementSize::Full; num_elements].as_slice(),
148        )
149    }
150
151    /// Creates a new sponge with applied domain separation.
152    fn fork(&self, domain: &[u8]) -> Self {
153        let mut new_sponge = self.clone();
154
155        let mut input = Absorb::to_sponge_bytes_as_vec(&domain.len());
156        input.extend_from_slice(domain);
157        new_sponge.absorb(&input);
158
159        new_sponge
160    }
161}
162
163/// The interface for field-based cryptographic sponge.
164/// `CF` is the native field used by the cryptographic sponge implementation.
165pub trait FieldBasedCryptographicSponge<CF: PrimeField>: CryptographicSponge {
166    /// Squeeze `num_elements` field elements from the sponge.
167    fn squeeze_native_field_elements(&mut self, num_elements: usize) -> Vec<CF>;
168
169    /// Squeeze `sizes.len()` field elements from the sponge, where the `i`-th element of
170    /// the output has size `sizes[i]`.
171    fn squeeze_native_field_elements_with_sizes(&mut self, sizes: &[FieldElementSize]) -> Vec<CF> {
172        let mut all_full_sizes = true;
173        for size in sizes {
174            if *size != FieldElementSize::Full {
175                all_full_sizes = false;
176                break;
177            }
178        }
179
180        if all_full_sizes {
181            self.squeeze_native_field_elements(sizes.len())
182        } else {
183            squeeze_field_elements_with_sizes_default_impl(self, sizes)
184        }
185    }
186}
187
188/// An extension for the interface of a cryptographic sponge.
189/// In addition to operations defined in `CryptographicSponge`, `SpongeExt` can convert itself to
190/// a state, and instantiate itself from state.
191pub trait SpongeExt: CryptographicSponge {
192    /// The full state of the cryptographic sponge.
193    type State: Clone;
194    /// Returns a sponge that uses `state`.
195    fn from_state(state: Self::State, params: &Self::Parameters) -> Self;
196    /// Consumes `self` and returns the state.
197    fn into_state(self) -> Self::State;
198}
199
200/// The mode structure for duplex sponges
201#[derive(Clone, Debug)]
202pub enum DuplexSpongeMode {
203    /// The sponge is currently absorbing data.
204    Absorbing {
205        /// next position of the state to be XOR-ed when absorbing.
206        next_absorb_index: usize,
207    },
208    /// The sponge is currently squeezing data out.
209    Squeezing {
210        /// next position of the state to be outputted when squeezing.
211        next_squeeze_index: usize,
212    },
213}