1use core::marker::PhantomData;
2
3use crate::{
4 Sigma, Writable,
5 rand_core::{CryptoRng, RngCore, SeedableRng},
6 typenum::{
7 PartialDiv, U32, U64, Unsigned, marker_traits::NonZero, type_operators::IsLessOrEqual,
8 },
9};
10use digest::{FixedOutput, Update, crypto_common::BlockSizeUser};
11use generic_array::GenericArray;
12
13pub trait Transcript<S: Sigma>: Clone {
19 fn add_name<N: Writable + ?Sized>(&mut self, name: &N);
22
23 fn add_statement(&mut self, sigma: &S, statement: &S::Statement);
27
28 fn get_challenge(
30 self,
31 sigma: &S,
32 announcement: &S::Announcement,
33 ) -> GenericArray<u8, S::ChallengeLength>;
34}
35
36pub trait ProverTranscript<S: Sigma> {
42 type Rng: CryptoRng + RngCore;
44 fn gen_rng<R: CryptoRng + RngCore>(
47 &self,
48 sigma: &S,
49 witness: &S::Witness,
50 in_rng: Option<&mut R>,
51 ) -> Self::Rng;
52}
53
54#[derive(Clone, Debug)]
55pub struct HashTranscript<H, R = ()> {
62 hash: H,
63 rng: PhantomData<R>,
64}
65
66impl<H: Default, R> Default for HashTranscript<H, R> {
67 fn default() -> Self {
68 HashTranscript {
69 hash: H::default(),
70 rng: PhantomData,
71 }
72 }
73}
74
75#[derive(Clone)]
76struct WriteHash<H>(H);
77
78impl<H: Update> core::fmt::Write for WriteHash<H> {
79 fn write_str(&mut self, s: &str) -> core::fmt::Result {
80 self.0.update(s.as_bytes());
81 Ok(())
82 }
83}
84
85impl<H, S: Sigma, R: Clone> Transcript<S> for HashTranscript<H, R>
91where
92 S::ChallengeLength: IsLessOrEqual<U32>,
93 <S::ChallengeLength as IsLessOrEqual<U32>>::Output: NonZero,
94 H: BlockSizeUser<BlockSize = U64> + FixedOutput<OutputSize = U32> + Update + Default + Clone,
95{
96 fn add_name<N: Writable + ?Sized>(&mut self, name: &N) {
97 let hashed_tag = {
98 let mut hash = WriteHash(H::default());
99 name.write_to(&mut hash)
100 .expect("writing to hash won't fail");
101 hash.0.finalize_fixed()
102 };
103 let fill_block =
106 <<H::BlockSize as PartialDiv<H::OutputSize>>::Output as Unsigned>::to_usize();
107 for _ in 0..fill_block {
108 self.hash.update(&hashed_tag[..]);
109 }
110 }
111
112 fn add_statement(&mut self, sigma: &S, statement: &S::Statement) {
113 sigma.hash_statement(&mut self.hash, statement);
114 }
115
116 fn get_challenge(
117 mut self,
118 sigma: &S,
119 announce: &S::Announcement,
120 ) -> GenericArray<u8, S::ChallengeLength> {
121 sigma.hash_announcement(&mut self.hash, announce);
122 let challenge_bytes = self.hash.finalize_fixed();
123 GenericArray::clone_from_slice(&challenge_bytes[..S::ChallengeLength::to_usize()])
125 }
126}
127
128impl<S, H, R> ProverTranscript<S> for HashTranscript<H, R>
130where
131 S: Sigma,
132 H: Update + FixedOutput<OutputSize = U32> + Clone,
133 R: SeedableRng + CryptoRng + RngCore + Clone,
134 R::Seed: From<GenericArray<u8, U32>>,
135{
136 type Rng = R;
137
138 fn gen_rng<SysRng: CryptoRng + RngCore>(
139 &self,
140 sigma: &S,
141 witness: &S::Witness,
142 in_rng: Option<&mut SysRng>,
143 ) -> Self::Rng {
144 let mut rng_hash = self.hash.clone();
145 sigma.hash_witness(&mut rng_hash, witness);
146 if let Some(rng) = in_rng {
147 let mut randomness = [0u8; 32];
148 rng.fill_bytes(&mut randomness);
149 rng_hash.update(&randomness);
150 }
151 let secret_seed = rng_hash.finalize_fixed();
152 R::from_seed(secret_seed.into())
153 }
154}