hyperplonk/poly-iop/src/transcript.rs
poly-iop/src/transcript.rsRaw
1use std::marker::PhantomData;
2
3use ark_ff::PrimeField;
4use merlin::Transcript;
5
6use crate::{
7 errors::PolyIOPErrors,
8 structs::{DomainInfo, IOPProverMessage},
9 to_bytes,
10};
11
12pub struct IOPTranscript<F: PrimeField> {
13 transcript: Transcript,
14 is_empty: bool,
15 #[doc(hidden)]
16 phantom: PhantomData<F>,
17}
18
19impl<F: PrimeField> IOPTranscript<F> {
20 /// create a new IOP transcript
21 pub(crate) fn new(label: &'static [u8]) -> Self {
22 Self {
23 transcript: Transcript::new(label),
24 is_empty: true,
25 phantom: PhantomData::default(),
26 }
27 }
28
29 // append the message to the transcript
30 pub(crate) fn append_message(
31 &mut self,
32 label: &'static [u8],
33 msg: &[u8],
34 ) -> Result<(), PolyIOPErrors> {
35 self.transcript.append_message(label, msg);
36 self.is_empty = false;
37 Ok(())
38 }
39
40 pub(crate) fn append_domain_info(
41 &mut self,
42 domain_info: &DomainInfo<F>,
43 ) -> Result<(), PolyIOPErrors> {
44 let message = format!(
45 "max_mul {} num_var {}",
46 domain_info.max_degree, domain_info.num_variables
47 );
48 self.append_message(b"aux info", message.as_bytes())?;
49
50 Ok(())
51 }
52
53 // append the message to the transcript
54 pub(crate) fn append_field_element(
55 &mut self,
56 label: &'static [u8],
57 field_elem: &F,
58 ) -> Result<(), PolyIOPErrors> {
59 self.append_message(label, &to_bytes!(field_elem)?)
60 }
61
62 pub(crate) fn append_prover_message(
63 &mut self,
64 prover_message: &IOPProverMessage<F>,
65 ) -> Result<(), PolyIOPErrors> {
66 for e in prover_message.evaluations.iter() {
67 self.append_field_element(b"prover_message", e)?;
68 }
69 Ok(())
70 }
71
72 // generate the challenge for the current transcript
73 // and append it to the transcript
74 pub(crate) fn get_and_append_challenge(
75 &mut self,
76 label: &'static [u8],
77 ) -> Result<F, PolyIOPErrors> {
78 if self.is_empty {
79 return Err(PolyIOPErrors::InvalidTranscript(
80 "transcript is empty".to_string(),
81 ));
82 }
83
84 let mut buf = [0u8; 64];
85 self.transcript.challenge_bytes(label, &mut buf);
86 let challenge = F::from_le_bytes_mod_order(&buf);
87 self.transcript
88 .append_message(label, &to_bytes!(&challenge)?);
89 Ok(challenge)
90 }
91
92 // generate a list of challenges for the current transcript
93 // and append it to the transcript
94 pub(crate) fn get_and_append_challenge_vectors(
95 &mut self,
96 label: &'static [u8],
97 len: usize,
98 ) -> Result<Vec<F>, PolyIOPErrors> {
99 // we need to reject when transcript is empty
100 let mut res = vec![];
101 for _ in 0..len {
102 res.push(self.get_and_append_challenge(label)?)
103 }
104 Ok(res)
105 }
106}