hyperplonk/poly-iop/src/transcript.rs
poly-iop/src/transcript.rsRaw
1//! Module for PolyIOP transcript.
2//! TODO(ZZ): move this module to HyperPlonk where the transcript will also be
3//! useful.
4//! TODO(ZZ): decide which APIs need to be public.
5
6use ark_ff::PrimeField;
7use ark_serialize::CanonicalSerialize;
8use merlin::Transcript;
9use std::marker::PhantomData;
10
11use crate::{errors::PolyIOPErrors, structs::IOPProverMessage, to_bytes, virtual_poly::VPAuxInfo};
12
13/// An IOP transcript consists of a Merlin transcript and a flag `is_empty` to
14/// indicate that if the transcript is empty.
15///
16/// It is associated with a prime field `F` for which challenges are generated
17/// over.
18///
19/// The `is_empty` flag is useful in the case where a protocol is initiated by
20/// the verifier, in which case the prover should start its phase by receiving a
21/// `non-empty` transcript.
22#[derive(Clone)]
23pub struct IOPTranscript<F: PrimeField> {
24 transcript: Transcript,
25 is_empty: bool,
26 #[doc(hidden)]
27 phantom: PhantomData<F>,
28}
29
30impl<F: PrimeField> IOPTranscript<F> {
31 /// Create a new IOP transcript.
32 pub fn new(label: &'static [u8]) -> Self {
33 Self {
34 transcript: Transcript::new(label),
35 is_empty: true,
36 phantom: PhantomData::default(),
37 }
38 }
39
40 // Append the message to the transcript.
41 pub fn append_message(
42 &mut self,
43 label: &'static [u8],
44 msg: &[u8],
45 ) -> Result<(), PolyIOPErrors> {
46 self.transcript.append_message(label, msg);
47 self.is_empty = false;
48 Ok(())
49 }
50
51 // Append the aux information for a virtual polynomial.
52 pub(crate) fn append_aux_info(&mut self, aux_info: &VPAuxInfo<F>) -> Result<(), PolyIOPErrors> {
53 let message = format!(
54 "max_mul {} num_var {}",
55 aux_info.max_degree, aux_info.num_variables
56 );
57 self.append_message(b"aux info", message.as_bytes())?;
58
59 Ok(())
60 }
61
62 // Append the message to the transcript.
63 pub fn append_field_element(
64 &mut self,
65 label: &'static [u8],
66 field_elem: &F,
67 ) -> Result<(), PolyIOPErrors> {
68 self.append_message(label, &to_bytes!(field_elem)?)
69 }
70
71 // Append the message to the transcript.
72 pub fn append_serializable_element<S: CanonicalSerialize>(
73 &mut self,
74 label: &'static [u8],
75 group_elem: &S,
76 ) -> Result<(), PolyIOPErrors> {
77 self.append_message(label, &to_bytes!(group_elem)?)
78 }
79
80 // Append a prover message to the transcript.
81 pub(crate) fn append_prover_message(
82 &mut self,
83 prover_message: &IOPProverMessage<F>,
84 ) -> Result<(), PolyIOPErrors> {
85 for e in prover_message.evaluations.iter() {
86 self.append_field_element(b"prover_message", e)?;
87 }
88 Ok(())
89 }
90
91 // Generate the challenge from the current transcript
92 // and append it to the transcript.
93 //
94 // The output field element is statistical uniform as long
95 // as the field has a size less than 2^384.
96 pub fn get_and_append_challenge(&mut self, label: &'static [u8]) -> Result<F, PolyIOPErrors> {
97 // we need to reject when transcript is empty
98 if self.is_empty {
99 return Err(PolyIOPErrors::InvalidTranscript(
100 "transcript is empty".to_string(),
101 ));
102 }
103
104 let mut buf = [0u8; 64];
105 self.transcript.challenge_bytes(label, &mut buf);
106 let challenge = F::from_le_bytes_mod_order(&buf);
107 self.transcript
108 .append_message(label, &to_bytes!(&challenge)?);
109 Ok(challenge)
110 }
111
112 // Generate a list of challenges from the current transcript
113 // and append them to the transcript.
114 //
115 // The output field element are statistical uniform as long
116 // as the field has a size less than 2^384.
117 pub(crate) fn get_and_append_challenge_vectors(
118 &mut self,
119 label: &'static [u8],
120 len: usize,
121 ) -> Result<Vec<F>, PolyIOPErrors> {
122 // we need to reject when transcript is empty
123 if self.is_empty {
124 return Err(PolyIOPErrors::InvalidTranscript(
125 "transcript is empty".to_string(),
126 ));
127 }
128
129 let mut res = vec![];
130 for _ in 0..len {
131 res.push(self.get_and_append_challenge(label)?)
132 }
133 Ok(res)
134 }
135}