Skip to main content

spongefish_circuit/
baby_bear.rs

1//! [`spongefish::Unit`] support for `p3_baby_bear::BabyBear`.
2//!
3//! A direct `impl Unit for BabyBear` would violate the orphan rule, so the
4//! field is carried through the transparent [`BabyBearUnit`] wrapper.
5
6use alloc::vec::Vec;
7
8use p3_baby_bear::BabyBear;
9use p3_field::{integers::QuotientMap, PrimeCharacteristicRing};
10use spongefish::{EncodedSessionId, Unit};
11
12use crate::expr::Ring;
13
14/// Transparent [`Unit`] wrapper around [`BabyBear`].
15#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
16#[repr(transparent)]
17pub struct BabyBearUnit(pub BabyBear);
18
19impl Unit for BabyBearUnit {
20    const ZERO: Self = Self(BabyBear::ZERO);
21}
22
23impl Ring for BabyBearUnit {
24    const ONE: Self = Self(BabyBear::ONE);
25
26    fn add(self, other: Self) -> Self {
27        self + other
28    }
29
30    fn mul(self, other: Self) -> Self {
31        self * other
32    }
33}
34
35impl core::ops::Add for BabyBearUnit {
36    type Output = Self;
37
38    fn add(self, rhs: Self) -> Self {
39        Self(self.0 + rhs.0)
40    }
41}
42
43impl core::ops::Mul for BabyBearUnit {
44    type Output = Self;
45
46    fn mul(self, rhs: Self) -> Self {
47        Self(self.0 * rhs.0)
48    }
49}
50
51impl From<BabyBear> for BabyBearUnit {
52    fn from(value: BabyBear) -> Self {
53        Self(value)
54    }
55}
56
57impl From<BabyBearUnit> for BabyBear {
58    fn from(value: BabyBearUnit) -> Self {
59        value.0
60    }
61}
62
63/// Reads a byte string as BabyBear units, one element per byte.
64///
65/// This is what lets a sponge over [`BabyBearUnit`] be seeded from a session
66/// identifier: [`DuplexSponge`][spongefish::DuplexSponge] implements
67/// [`DuplexSpongeInit`][spongefish::DuplexSpongeInit] over any alphabet that
68/// byte strings embed into. With it,
69/// [`ProverState::new`][spongefish::ProverState::new] works over BabyBear
70/// exactly as it does over bytes.
71///
72/// One element per byte rather than a denser packing: every element is then in
73/// `[0, 256)`, so the map is injective by inspection and there is no remainder
74/// case to get wrong. A 32-byte session identifier costs 32 units, absorbed
75/// once per proof.
76///
77/// # Security
78///
79/// Like the identity embedding on bytes, this map is injective but **not**
80/// prefix-free across lengths: `b"ab"` maps to a prefix of `b"abc"`. It is
81/// admissible where the byte length is fixed by the protocol — a session
82/// identifier is always 32 bytes — and a variable-length byte string must be
83/// length-prefixed by the caller.
84impl EncodedSessionId for BabyBearUnit {
85    fn encode_bytes(bytes: &[u8]) -> impl AsRef<[Self]> {
86        bytes
87            .iter()
88            .map(|&byte| Self(BabyBear::from_int(byte)))
89            .collect::<Vec<_>>()
90    }
91}
92
93impl core::ops::Deref for BabyBearUnit {
94    type Target = BabyBear;
95
96    fn deref(&self) -> &Self::Target {
97        &self.0
98    }
99}