lettuce 0.1.3

Healthy lattice consructions in pure Rust.
Documentation
use std::marker::PhantomData;

use rand::RngCore;
use rand::SeedableRng;
use rand_chacha::ChaChaRng;

use crate::*;

#[derive(Clone)]
pub struct Transcript<E: RingElement> {
    bytes: Vec<u8>,
    rng_maybe: Option<ChaChaRng>,
    is_sealed: bool,
    _phantom: PhantomData<E>,
}

impl<E: RingElement> From<&[u8; 32]> for Transcript<E> {
    fn from(value: &[u8; 32]) -> Self {
        let mut out = Self::new();
        out.append_bytes(value);
        out.is_sealed = true;
        out
    }
}

impl<E: RingElement> Transcript<E> {
    pub fn new() -> Self {
        Self {
            bytes: Vec::default(),
            rng_maybe: None,
            is_sealed: false,
            _phantom: PhantomData::default(),
        }
    }

    fn ensure_rng<'a>(&'a mut self) -> &'a mut ChaChaRng {
        if self.rng_maybe.is_some() {
            return self.rng_maybe.as_mut().unwrap();
        }
        if self.bytes.len() < 32 {
            panic!(
                "lettuce::Transcript refusing to sample entropy from transcript with less than 32 bytes"
            );
        }
        let hash = blake3::hash(&self.bytes);
        let csprng = rand_chacha::ChaCha20Rng::from_seed(hash.into());
        self.rng_maybe = Some(csprng);
        self.rng_maybe.as_mut().unwrap()
    }

    /// Pull entropy from another transcript.
    pub fn pull(&mut self, other: &mut Self) {
        assert!(!self.is_sealed);
        self.domain_separator("sync");
        let rhs = other.random::<[u8; 32]>();
        self.append_bytes(&rhs);
    }

    /// Append a string domain separator between distinct components of a transcript.
    pub fn domain_separator(&mut self, sep: &str) {
        assert!(!self.is_sealed);
        let hash = blake3::hash(sep.as_bytes());
        self.bytes.extend(hash.as_bytes());
    }

    pub fn append_bytes(&mut self, v: &[u8]) {
        assert!(!self.is_sealed);
        self.bytes.extend(v);
    }

    /// Append a field element to the transcript.
    pub fn append(&mut self, v: &E) {
        assert!(!self.is_sealed);
        self.bytes.extend(v.as_le_bytes());
    }

    /// Append a vector of field elements to the transcript.
    pub fn append_vector(&mut self, vec: &Vector<E>) {
        assert!(!self.is_sealed);
        for v in vec.iter() {
            self.bytes.extend(v.as_le_bytes());
        }
    }

    /// Append a matrix of field elements to the transcript.
    pub fn append_matrix(&mut self, mat: &Matrix<E>) {
        assert!(!self.is_sealed);
        for row in mat.iter() {
            for v in row.iter() {
                self.bytes.extend(v.as_le_bytes());
            }
        }
    }
}

impl<E: RingElement> RngCore for Transcript<E> {
    fn next_u32(&mut self) -> u32 {
        let rng = self.ensure_rng();
        rng.next_u32()
    }

    fn next_u64(&mut self) -> u64 {
        let rng = self.ensure_rng();
        rng.next_u64()
    }

    fn fill_bytes(&mut self, dst: &mut [u8]) {
        let rng = self.ensure_rng();
        rng.fill_bytes(dst);
    }
}