lambdaworks_crypto/fiat_shamir/
default_transcript.rs1use super::is_transcript::IsTranscript;
2use core::marker::PhantomData;
3use lambdaworks_math::{
4 field::{element::FieldElement, traits::HasDefaultTranscript},
5 traits::ByteConversion,
6};
7use rand_chacha::{rand_core::SeedableRng, ChaCha20Rng};
8use sha3::{Digest, Keccak256};
9
10pub struct DefaultTranscript<F: HasDefaultTranscript> {
11 hasher: Keccak256,
12 phantom: PhantomData<F>,
13}
14
15impl<F> DefaultTranscript<F>
16where
17 F: HasDefaultTranscript,
18 FieldElement<F>: ByteConversion,
19{
20 pub fn new(data: &[u8]) -> Self {
21 let mut res = Self {
22 hasher: Keccak256::new(),
23 phantom: PhantomData,
24 };
25 res.append_bytes(data);
26 res
27 }
28
29 pub fn sample(&mut self) -> [u8; 32] {
30 let mut result_hash = [0_u8; 32];
31 result_hash.copy_from_slice(&self.hasher.finalize_reset());
32 result_hash.reverse();
33 self.hasher.update(result_hash);
34 result_hash
35 }
36}
37
38impl<F> Default for DefaultTranscript<F>
39where
40 F: HasDefaultTranscript,
41 FieldElement<F>: ByteConversion,
42{
43 fn default() -> Self {
44 Self::new(&[])
45 }
46}
47
48impl<F> IsTranscript<F> for DefaultTranscript<F>
49where
50 F: HasDefaultTranscript,
51 FieldElement<F>: ByteConversion,
52{
53 fn append_bytes(&mut self, new_bytes: &[u8]) {
54 self.hasher.update(new_bytes);
55 }
56
57 fn append_field_element(&mut self, element: &FieldElement<F>) {
58 self.append_bytes(&element.to_bytes_be());
59 }
60
61 fn state(&self) -> [u8; 32] {
62 self.hasher.clone().finalize().into()
63 }
64
65 fn sample_field_element(&mut self) -> FieldElement<F> {
66 let mut rng = <ChaCha20Rng as SeedableRng>::from_seed(self.sample());
67 F::get_random_field_element_from_rng(&mut rng)
68 }
69
70 fn sample_u64(&mut self, upper_bound: u64) -> u64 {
71 u64::from_be_bytes(self.state()[..8].try_into().unwrap()) % upper_bound
72 }
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78
79 use alloc::vec::Vec;
80 use lambdaworks_math::elliptic_curve::short_weierstrass::curves::bls12_381::default_types::FrField;
81
82 #[test]
83 fn basic_challenge() {
84 let mut transcript = DefaultTranscript::<FrField>::default();
85
86 let point_a: Vec<u8> = vec![0xFF, 0xAB];
87 let point_b: Vec<u8> = vec![0xDD, 0x8C, 0x9D];
88
89 transcript.append_bytes(&point_a); transcript.append_bytes(&point_b); let challenge1 = transcript.sample(); assert_eq!(
95 challenge1,
96 [
97 0x0c, 0x2b, 0xd8, 0xcf, 0x2d, 0x71, 0xe0, 0x0a, 0xce, 0xa3, 0xbd, 0x5d, 0xc7, 0x9f,
98 0x4f, 0x93, 0xed, 0x57, 0x42, 0xd0, 0x23, 0xbd, 0x47, 0xc9, 0x04, 0xc2, 0x67, 0x9d,
99 0xbc, 0xfa, 0x7c, 0xa7
100 ]
101 );
102
103 let point_c: Vec<u8> = vec![0xFF, 0xAB];
104 let point_d: Vec<u8> = vec![0xDD, 0x8C, 0x9D];
105
106 transcript.append_bytes(&point_c); transcript.append_bytes(&point_d); let challenge2 = transcript.sample(); assert_eq!(
111 challenge2,
112 [
113 0x81, 0x61, 0x51, 0xc5, 0x7e, 0xcb, 0x45, 0xd5, 0x17, 0x1a, 0x3c, 0x2e, 0x38, 0x04,
114 0x5d, 0xfb, 0x3a, 0x3d, 0x33, 0x8a, 0x22, 0xaf, 0xf8, 0x60, 0x85, 0xb9, 0x54, 0x3f,
115 0xf8, 0x32, 0x32, 0xbc
116 ]
117 );
118 }
119}