arnaucube
arnaucube/hyperplonkPublic Self-hosted repository
hyperplonk/transcript/src/lib.rs
transcript/src/lib.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
  6mod errors;
  7pub use errors::TranscriptErrors;
  8
  9use ark_ff::PrimeField;
 10use ark_serialize::CanonicalSerialize;
 11use merlin::Transcript;
 12use std::marker::PhantomData;
 13
 14/// An IOP transcript consists of a Merlin transcript and a flag `is_empty` to
 15/// indicate that if the transcript is empty.
 16///
 17/// It is associated with a prime field `F` for which challenges are generated
 18/// over.
 19///
 20/// The `is_empty` flag is useful in the case where a protocol is initiated by
 21/// the verifier, in which case the prover should start its phase by receiving a
 22/// `non-empty` transcript.
 23#[derive(Clone)]
 24pub struct IOPTranscript<F: PrimeField> {
 25    transcript: Transcript,
 26    is_empty: bool,
 27    #[doc(hidden)]
 28    phantom: PhantomData<F>,
 29}
 30
 31// TODO: Make this into a Trait
 32impl<F: PrimeField> IOPTranscript<F> {
 33    /// Create a new IOP transcript.
 34    pub fn new(label: &'static [u8]) -> Self {
 35        Self {
 36            transcript: Transcript::new(label),
 37            is_empty: true,
 38            phantom: PhantomData::default(),
 39        }
 40    }
 41
 42    // Append the message to the transcript.
 43    pub fn append_message(
 44        &mut self,
 45        label: &'static [u8],
 46        msg: &[u8],
 47    ) -> Result<(), TranscriptErrors> {
 48        self.transcript.append_message(label, msg);
 49        self.is_empty = false;
 50        Ok(())
 51    }
 52
 53    // Append the message to the transcript.
 54    pub fn append_field_element(
 55        &mut self,
 56        label: &'static [u8],
 57        field_elem: &F,
 58    ) -> Result<(), TranscriptErrors> {
 59        self.append_message(label, &to_bytes!(field_elem)?)
 60    }
 61
 62    // Append the message to the transcript.
 63    pub fn append_serializable_element<S: CanonicalSerialize>(
 64        &mut self,
 65        label: &'static [u8],
 66        group_elem: &S,
 67    ) -> Result<(), TranscriptErrors> {
 68        self.append_message(label, &to_bytes!(group_elem)?)
 69    }
 70
 71    // Generate the challenge from the current transcript
 72    // and append it to the transcript.
 73    //
 74    // The output field element is statistical uniform as long
 75    // as the field has a size less than 2^384.
 76    pub fn get_and_append_challenge(
 77        &mut self,
 78        label: &'static [u8],
 79    ) -> Result<F, TranscriptErrors> {
 80        //  we need to reject when transcript is empty
 81        if self.is_empty {
 82            return Err(TranscriptErrors::InvalidTranscript(
 83                "transcript is empty".to_string(),
 84            ));
 85        }
 86
 87        let mut buf = [0u8; 64];
 88        self.transcript.challenge_bytes(label, &mut buf);
 89        let challenge = F::from_le_bytes_mod_order(&buf);
 90        self.transcript
 91            .append_message(label, &to_bytes!(&challenge)?);
 92        Ok(challenge)
 93    }
 94
 95    // Generate a list of challenges from the current transcript
 96    // and append them to the transcript.
 97    //
 98    // The output field element are statistical uniform as long
 99    // as the field has a size less than 2^384.
100    pub fn get_and_append_challenge_vectors(
101        &mut self,
102        label: &'static [u8],
103        len: usize,
104    ) -> Result<Vec<F>, TranscriptErrors> {
105        //  we need to reject when transcript is empty
106        if self.is_empty {
107            return Err(TranscriptErrors::InvalidTranscript(
108                "transcript is empty".to_string(),
109            ));
110        }
111
112        let mut res = vec![];
113        for _ in 0..len {
114            res.push(self.get_and_append_challenge(label)?)
115        }
116        Ok(res)
117    }
118}
119
120/// Takes as input a struct, and converts them to a series of bytes. All traits
121/// that implement `CanonicalSerialize` can be automatically converted to bytes
122/// in this manner.
123#[macro_export]
124macro_rules! to_bytes {
125    ($x:expr) => {{
126        let mut buf = ark_std::vec![];
127        ark_serialize::CanonicalSerialize::serialize($x, &mut buf).map(|_| buf)
128    }};
129}