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()
}
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);
}
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);
}
pub fn append(&mut self, v: &E) {
assert!(!self.is_sealed);
self.bytes.extend(v.as_le_bytes());
}
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());
}
}
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);
}
}