mirror of
https://github.com/arnaucube/hyperplonk.git
synced 2026-01-10 16:11:29 +01:00
move transcript to trait (#46)
This commit is contained in:
17
transcript/Cargo.toml
Normal file
17
transcript/Cargo.toml
Normal file
@@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "transcript"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
|
||||
merlin = { version = "3.0.0", default-features = false }
|
||||
|
||||
|
||||
ark-ff = { version = "^0.3.0", default-features = false }
|
||||
ark-serialize = { version = "^0.3.0", default-features = false }
|
||||
ark-std = { version = "^0.3.0", default-features = false }
|
||||
|
||||
displaydoc = { version = "0.2.3", default-features = false }
|
||||
19
transcript/src/errors.rs
Normal file
19
transcript/src/errors.rs
Normal file
@@ -0,0 +1,19 @@
|
||||
//! Error module.
|
||||
|
||||
use ark_std::string::String;
|
||||
use displaydoc::Display;
|
||||
|
||||
/// A `enum` specifying the possible failure modes of the Transcript.
|
||||
#[derive(Display, Debug)]
|
||||
pub enum TranscriptErrors {
|
||||
/// Invalid Transcript: {0}
|
||||
InvalidTranscript(String),
|
||||
/// An error during (de)serialization: {0}
|
||||
SerializationError(ark_serialize::SerializationError),
|
||||
}
|
||||
|
||||
impl From<ark_serialize::SerializationError> for TranscriptErrors {
|
||||
fn from(e: ark_serialize::SerializationError) -> Self {
|
||||
Self::SerializationError(e)
|
||||
}
|
||||
}
|
||||
129
transcript/src/lib.rs
Normal file
129
transcript/src/lib.rs
Normal file
@@ -0,0 +1,129 @@
|
||||
//! Module for PolyIOP transcript.
|
||||
//! TODO(ZZ): move this module to HyperPlonk where the transcript will also be
|
||||
//! useful.
|
||||
//! TODO(ZZ): decide which APIs need to be public.
|
||||
|
||||
mod errors;
|
||||
pub use errors::TranscriptErrors;
|
||||
|
||||
use ark_ff::PrimeField;
|
||||
use ark_serialize::CanonicalSerialize;
|
||||
use merlin::Transcript;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
/// An IOP transcript consists of a Merlin transcript and a flag `is_empty` to
|
||||
/// indicate that if the transcript is empty.
|
||||
///
|
||||
/// It is associated with a prime field `F` for which challenges are generated
|
||||
/// over.
|
||||
///
|
||||
/// The `is_empty` flag is useful in the case where a protocol is initiated by
|
||||
/// the verifier, in which case the prover should start its phase by receiving a
|
||||
/// `non-empty` transcript.
|
||||
#[derive(Clone)]
|
||||
pub struct IOPTranscript<F: PrimeField> {
|
||||
transcript: Transcript,
|
||||
is_empty: bool,
|
||||
#[doc(hidden)]
|
||||
phantom: PhantomData<F>,
|
||||
}
|
||||
|
||||
// TODO: Make this into a Trait
|
||||
impl<F: PrimeField> IOPTranscript<F> {
|
||||
/// Create a new IOP transcript.
|
||||
pub fn new(label: &'static [u8]) -> Self {
|
||||
Self {
|
||||
transcript: Transcript::new(label),
|
||||
is_empty: true,
|
||||
phantom: PhantomData::default(),
|
||||
}
|
||||
}
|
||||
|
||||
// Append the message to the transcript.
|
||||
pub fn append_message(
|
||||
&mut self,
|
||||
label: &'static [u8],
|
||||
msg: &[u8],
|
||||
) -> Result<(), TranscriptErrors> {
|
||||
self.transcript.append_message(label, msg);
|
||||
self.is_empty = false;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Append the message to the transcript.
|
||||
pub fn append_field_element(
|
||||
&mut self,
|
||||
label: &'static [u8],
|
||||
field_elem: &F,
|
||||
) -> Result<(), TranscriptErrors> {
|
||||
self.append_message(label, &to_bytes!(field_elem)?)
|
||||
}
|
||||
|
||||
// Append the message to the transcript.
|
||||
pub fn append_serializable_element<S: CanonicalSerialize>(
|
||||
&mut self,
|
||||
label: &'static [u8],
|
||||
group_elem: &S,
|
||||
) -> Result<(), TranscriptErrors> {
|
||||
self.append_message(label, &to_bytes!(group_elem)?)
|
||||
}
|
||||
|
||||
// Generate the challenge from the current transcript
|
||||
// and append it to the transcript.
|
||||
//
|
||||
// The output field element is statistical uniform as long
|
||||
// as the field has a size less than 2^384.
|
||||
pub fn get_and_append_challenge(
|
||||
&mut self,
|
||||
label: &'static [u8],
|
||||
) -> Result<F, TranscriptErrors> {
|
||||
// we need to reject when transcript is empty
|
||||
if self.is_empty {
|
||||
return Err(TranscriptErrors::InvalidTranscript(
|
||||
"transcript is empty".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
let mut buf = [0u8; 64];
|
||||
self.transcript.challenge_bytes(label, &mut buf);
|
||||
let challenge = F::from_le_bytes_mod_order(&buf);
|
||||
self.transcript
|
||||
.append_message(label, &to_bytes!(&challenge)?);
|
||||
Ok(challenge)
|
||||
}
|
||||
|
||||
// Generate a list of challenges from the current transcript
|
||||
// and append them to the transcript.
|
||||
//
|
||||
// The output field element are statistical uniform as long
|
||||
// as the field has a size less than 2^384.
|
||||
pub fn get_and_append_challenge_vectors(
|
||||
&mut self,
|
||||
label: &'static [u8],
|
||||
len: usize,
|
||||
) -> Result<Vec<F>, TranscriptErrors> {
|
||||
// we need to reject when transcript is empty
|
||||
if self.is_empty {
|
||||
return Err(TranscriptErrors::InvalidTranscript(
|
||||
"transcript is empty".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
let mut res = vec![];
|
||||
for _ in 0..len {
|
||||
res.push(self.get_and_append_challenge(label)?)
|
||||
}
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
/// Takes as input a struct, and converts them to a series of bytes. All traits
|
||||
/// that implement `CanonicalSerialize` can be automatically converted to bytes
|
||||
/// in this manner.
|
||||
#[macro_export]
|
||||
macro_rules! to_bytes {
|
||||
($x:expr) => {{
|
||||
let mut buf = ark_std::vec![];
|
||||
ark_serialize::CanonicalSerialize::serialize($x, &mut buf).map(|_| buf)
|
||||
}};
|
||||
}
|
||||
Reference in New Issue
Block a user