proof_cat_core/
transcript.rs1use field_cat::FieldBytes;
9use sha2::{Digest, Sha256};
10
11use crate::error::Error;
12
13#[derive(Debug, Clone)]
35pub struct Transcript {
36 state: Vec<u8>,
37}
38
39impl Transcript {
40 #[must_use]
42 pub fn new(label: &[u8]) -> Self {
43 Self {
44 state: label.to_vec(),
45 }
46 }
47
48 #[must_use]
50 pub fn absorb_bytes(self, data: &[u8]) -> Self {
51 Self {
52 state: self.state.into_iter().chain(data.iter().copied()).collect(),
53 }
54 }
55
56 #[must_use]
58 pub fn absorb_field<F: FieldBytes>(self, elem: &F) -> Self {
59 self.absorb_bytes(&elem.to_le_bytes())
60 }
61
62 pub fn squeeze_challenge<F: FieldBytes>(self) -> Result<(F, Self), Error> {
73 let digest = Sha256::digest(&self.state);
74 let challenge = F::from_le_bytes(digest.as_slice())?;
75 let new_state = self
76 .state
77 .into_iter()
78 .chain(digest.iter().copied())
79 .collect();
80 Ok((challenge, Self { state: new_state }))
81 }
82}
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87 use field_cat::{BabyBear, F101};
88
89 #[test]
90 fn deterministic_challenges() -> Result<(), Error> {
91 let t1 = Transcript::new(b"test").absorb_field(&BabyBear::new(42));
92 let t2 = Transcript::new(b"test").absorb_field(&BabyBear::new(42));
93 let (c1, _) = t1.squeeze_challenge::<BabyBear>()?;
94 let (c2, _) = t2.squeeze_challenge::<BabyBear>()?;
95 assert_eq!(c1, c2);
96 Ok(())
97 }
98
99 #[test]
100 fn different_inputs_different_challenges() -> Result<(), Error> {
101 let t1 = Transcript::new(b"test").absorb_field(&BabyBear::new(1));
102 let t2 = Transcript::new(b"test").absorb_field(&BabyBear::new(2));
103 let (c1, _) = t1.squeeze_challenge::<BabyBear>()?;
104 let (c2, _) = t2.squeeze_challenge::<BabyBear>()?;
105 assert_ne!(c1, c2);
106 Ok(())
107 }
108
109 #[test]
110 fn absorb_order_matters() -> Result<(), Error> {
111 let t1 = Transcript::new(b"test")
112 .absorb_field(&F101::new(1))
113 .absorb_field(&F101::new(2));
114 let t2 = Transcript::new(b"test")
115 .absorb_field(&F101::new(2))
116 .absorb_field(&F101::new(1));
117 let (c1, _) = t1.squeeze_challenge::<F101>()?;
118 let (c2, _) = t2.squeeze_challenge::<F101>()?;
119 assert_ne!(c1, c2);
120 Ok(())
121 }
122
123 #[test]
124 fn label_matters() -> Result<(), Error> {
125 let t1 = Transcript::new(b"label_a").absorb_field(&BabyBear::new(42));
126 let t2 = Transcript::new(b"label_b").absorb_field(&BabyBear::new(42));
127 let (c1, _) = t1.squeeze_challenge::<BabyBear>()?;
128 let (c2, _) = t2.squeeze_challenge::<BabyBear>()?;
129 assert_ne!(c1, c2);
130 Ok(())
131 }
132}