arnaucube
arnaucube/hyperplonkPublic Self-hosted repository
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}