-
Notifications
You must be signed in to change notification settings - Fork 39
/
lib.rs
131 lines (117 loc) · 4.09 KB
/
lib.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright (c) 2023 Espresso Systems (espressosys.com)
// This file is part of the HyperPlonk library.
// You should have received a copy of the MIT License
// along with the HyperPlonk library. If not, see <https://mit-license.org/>.
//! 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::TranscriptError;
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,
}
}
// Append the message to the transcript.
pub fn append_message(
&mut self,
label: &'static [u8],
msg: &[u8],
) -> Result<(), TranscriptError> {
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<(), TranscriptError> {
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<(), TranscriptError> {
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, TranscriptError> {
// we need to reject when transcript is empty
if self.is_empty {
return Err(TranscriptError::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.append_serializable_element(label, &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>, TranscriptError> {
// we need to reject when transcript is empty
if self.is_empty {
return Err(TranscriptError::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_compressed($x, &mut buf).map(|_| buf)
}};
}