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