arnaucube
arnaucube/sigmabus-pocPublic Self-hosted repository
sigmabus-poc/src/transcript.rs
src/transcript.rsRaw
 1use ark_crypto_primitives::sponge::{
 2    poseidon::{PoseidonConfig, PoseidonSponge},
 3    Absorb, CryptographicSponge,
 4};
 5use ark_ec::{AffineRepr, CurveGroup, Group};
 6use ark_ff::{BigInteger, Field, PrimeField};
 7
 8pub struct PoseidonTranscript<C: CurveGroup>
 9where
10    <C as Group>::ScalarField: Absorb,
11{
12    sponge: PoseidonSponge<C::ScalarField>,
13}
14
15impl<C: CurveGroup> PoseidonTranscript<C>
16where
17    <C as Group>::ScalarField: Absorb,
18{
19    pub fn new(poseidon_config: &PoseidonConfig<C::ScalarField>) -> Self {
20        let sponge = PoseidonSponge::<C::ScalarField>::new(poseidon_config);
21        Self { sponge }
22    }
23    pub fn absorb(&mut self, v: &C::ScalarField) {
24        self.sponge.absorb(&v);
25    }
26    pub fn absorb_point(&mut self, p: &C) {
27        self.sponge.absorb(&prepare_point(p));
28    }
29    pub fn get_challenge(&mut self) -> C::ScalarField {
30        let c = self.sponge.squeeze_field_elements(1);
31        self.sponge.absorb(&c[0]);
32        c[0]
33    }
34}
35
36// Returns the point coordinates in Fr, so it can be absrobed by the transcript. It does not work
37// over bytes in order to have a logic that can be reproduced in-circuit.
38fn prepare_point<C: CurveGroup>(p: &C) -> Vec<C::ScalarField> {
39    let binding = p.into_affine();
40    let p_coords = &binding.xy().unwrap();
41    let x_bi = p_coords
42        .0
43        .to_base_prime_field_elements()
44        .next()
45        .expect("a")
46        .into_bigint();
47    let y_bi = p_coords
48        .1
49        .to_base_prime_field_elements()
50        .next()
51        .expect("a")
52        .into_bigint();
53    vec![
54        C::ScalarField::from_le_bytes_mod_order(x_bi.to_bytes_le().as_ref()),
55        C::ScalarField::from_le_bytes_mod_order(y_bi.to_bytes_le().as_ref()),
56    ]
57}
58
59#[cfg(test)]
60pub mod tests {
61    use super::*;
62    use ark_crypto_primitives::sponge::poseidon::find_poseidon_ark_and_mds;
63
64    /// WARNING the method poseidon_test_config is for tests only
65    #[cfg(test)]
66    pub fn poseidon_test_config<F: PrimeField>() -> PoseidonConfig<F> {
67        let full_rounds = 8;
68        let partial_rounds = 31;
69        let alpha = 5;
70        let rate = 2;
71
72        let (ark, mds) = find_poseidon_ark_and_mds::<F>(
73            F::MODULUS_BIT_SIZE as u64,
74            rate,
75            full_rounds,
76            partial_rounds,
77            0,
78        );
79
80        PoseidonConfig::new(
81            full_rounds as usize,
82            partial_rounds as usize,
83            alpha,
84            mds,
85            ark,
86            rate,
87            1,
88        )
89    }
90}