1pub mod traits;
2
3use crate::traits::{ConstTranscribable, GenTranscribable, Transcript};
4use crypto_primitives::{BaseFieldConfig, ConstIntSemiring};
5use std::io::ErrorKind;
6use thiserror::Error;
7use zinc_primality::PrimalityTest;
8
9#[derive(Debug, Clone)]
13pub struct Blake3Transcript {
14 hasher: blake3::Hasher,
16}
17
18impl Default for Blake3Transcript {
19 fn default() -> Self {
20 Self::new()
21 }
22}
23
24const DOMAIN_SEPARATOR: &[u8] = b"zinc-plus/transcript/v1";
35
36impl Blake3Transcript {
37 pub fn new() -> Self {
38 let mut hasher = blake3::Hasher::new();
39 hasher.update(DOMAIN_SEPARATOR);
40 Self { hasher }
41 }
42
43 #[allow(clippy::arithmetic_side_effects)]
49 fn fill_with_random_bytes(&mut self, buf: &mut [u8]) {
50 self.hasher.finalize_xof().fill(buf);
51 }
52
53 fn gen_random<R: ConstTranscribable>(&mut self, buf: &mut [u8]) -> R {
54 self.fill_with_random_bytes(buf);
55 self.absorb_bytes(buf);
56 R::read_transcription_bytes_exact(buf)
57 }
58}
59
60impl Transcript for Blake3Transcript {
61 fn get_challenge<T: ConstTranscribable>(&mut self) -> T {
62 let mut buf = vec![0u8; T::NUM_BYTES];
63 self.fill_with_random_bytes(&mut buf);
64 self.hasher.update(&[0x12]);
65 self.hasher.update(&buf);
66 self.hasher.update(&[0x34]);
67 T::read_transcription_bytes_exact(&buf)
68 }
69
70 #[allow(clippy::arithmetic_side_effects)]
71 fn get_prime<R: ConstIntSemiring + ConstTranscribable, T: PrimalityTest<R>>(&mut self) -> R {
72 let buf = &mut vec![0u8; R::NUM_BYTES];
73 loop {
74 let mut prime_candidate: R = self.gen_random(buf);
75 if prime_candidate.is_zero() {
76 continue;
77 }
78 if prime_candidate.is_even() {
79 prime_candidate -= R::ONE;
80 }
81 if T::is_probably_prime(&prime_candidate) {
82 return prime_candidate;
83 }
84 }
85 }
86
87 fn absorb_inner(&mut self, v: &[u8]) {
88 self.hasher.update(v);
89 }
90}
91
92pub fn read_field_cfg<C>(bytes: &[u8]) -> C
93where
94 C: BaseFieldConfig,
95 C::Integer: ConstTranscribable,
96{
97 let mod_size = C::Integer::NUM_BYTES;
98 let modulus = C::Integer::read_transcription_bytes_exact(&bytes[..mod_size]);
99 C::new(&modulus).expect("valid field modulus in proof transcription")
100}
101
102pub fn append_field_cfg<'a, C>(buf: &'a mut [u8], modulus: &C::Integer) -> &'a mut [u8]
103where
104 C: BaseFieldConfig,
105 C::Integer: ConstTranscribable,
106{
107 let mod_size = C::Integer::NUM_BYTES;
108 let (buf, rest) = buf.split_at_mut(mod_size);
109 modulus.write_transcription_bytes_exact(buf);
110 rest
111}
112
113#[derive(Clone, Debug, PartialEq, Error)]
114#[error("{1}")]
115pub struct TranscriptError(pub ErrorKind, pub String);