jf_plonk/transcript/
mod.rs

1// Copyright (c) 2022 Espresso Systems (espressosys.com)
2// This file is part of the Jellyfish library.
3
4// You should have received a copy of the MIT License
5// along with the Jellyfish library. If not, see <https://mit-license.org/>.
6
7//! This module implements three different types of transcripts that are
8//! supported.
9
10pub(crate) mod rescue;
11pub(crate) mod solidity;
12pub(crate) mod standard;
13
14pub use rescue::RescueTranscript;
15pub use solidity::SolidityTranscript;
16pub use standard::StandardTranscript;
17
18use crate::{
19    errors::PlonkError,
20    proof_system::structs::{PlookupEvaluations, ProofEvaluations, VerifyingKey},
21};
22use ark_ec::{
23    pairing::Pairing,
24    short_weierstrass::{Affine, SWCurveConfig as SWParam},
25};
26use ark_ff::PrimeField;
27use ark_std::vec::Vec;
28use jf_pcs::prelude::Commitment;
29use jf_utils::to_bytes;
30
31/// Defines transcript APIs.
32///
33/// It has an associated type `F` which defines the native
34/// field for the snark circuit.
35///
36/// The transcript can be either a Merlin transcript
37/// (instantiated with Sha-3/keccak), or a Rescue transcript
38/// (instantiated with Rescue hash), or a Solidity-friendly transcript
39/// (instantiated with Keccak256 hash).
40/// The second is only used for recursive snarks.
41pub trait PlonkTranscript<F> {
42    /// Create a new plonk transcript.
43    fn new(label: &'static [u8]) -> Self;
44
45    /// Append the verification key and the public input to the transcript.
46    fn append_vk_and_pub_input<E, P>(
47        &mut self,
48        vk: &VerifyingKey<E>,
49        pub_input: &[E::ScalarField],
50    ) -> Result<(), PlonkError>
51    where
52        E: Pairing<BaseField = F, G1Affine = Affine<P>>,
53        P: SWParam<BaseField = F>,
54    {
55        self.append_message(
56            b"field size in bits",
57            E::ScalarField::MODULUS_BIT_SIZE.to_le_bytes().as_ref(),
58        )?;
59        <Self as PlonkTranscript<F>>::append_message(
60            self,
61            b"domain size",
62            vk.domain_size.to_le_bytes().as_ref(),
63        )?;
64        <Self as PlonkTranscript<F>>::append_message(
65            self,
66            b"input size",
67            vk.num_inputs.to_le_bytes().as_ref(),
68        )?;
69
70        // include [x]_2 G2 point from SRS
71        // all G1 points from SRS are implicit reflected in committed polys
72        <Self as PlonkTranscript<F>>::append_message(
73            self,
74            b"SRS G2 element",
75            &to_bytes!(&vk.open_key.powers_of_h[1])?,
76        )?;
77
78        self.append_field_elems::<E>(b"wire subsets separators", &vk.k)?;
79        self.append_commitments(b"selector commitments", &vk.selector_comms)?;
80        self.append_commitments(b"sigma commitments", &vk.sigma_comms)?;
81        self.append_field_elems::<E>(b"public input", pub_input)?;
82
83        Ok(())
84    }
85
86    /// Append the message to the transcript.
87    fn append_message(&mut self, label: &'static [u8], msg: &[u8]) -> Result<(), PlonkError>;
88
89    /// Append a slice of commitments to the transcript.
90    fn append_commitments<E, P>(
91        &mut self,
92        label: &'static [u8],
93        comms: &[Commitment<E>],
94    ) -> Result<(), PlonkError>
95    where
96        E: Pairing<BaseField = F, G1Affine = Affine<P>>,
97        P: SWParam<BaseField = F>,
98    {
99        for comm in comms.iter() {
100            self.append_commitment(label, comm)?;
101        }
102        Ok(())
103    }
104
105    /// Append a single commitment to the transcript.
106    fn append_commitment<E, P>(
107        &mut self,
108        label: &'static [u8],
109        comm: &Commitment<E>,
110    ) -> Result<(), PlonkError>
111    where
112        E: Pairing<BaseField = F, G1Affine = Affine<P>>,
113        P: SWParam<BaseField = F>,
114    {
115        <Self as PlonkTranscript<F>>::append_message(self, label, &to_bytes!(comm)?)
116    }
117
118    /// Append a field element to the transcript.
119    fn append_field_elem<E>(
120        &mut self,
121        label: &'static [u8],
122        field: &E::ScalarField,
123    ) -> Result<(), PlonkError>
124    where
125        E: Pairing<BaseField = F>,
126    {
127        <Self as PlonkTranscript<F>>::append_message(self, label, &to_bytes!(field)?)
128    }
129
130    /// Append a list of field elements to the transcript
131    fn append_field_elems<E>(
132        &mut self,
133        label: &'static [u8],
134        fields: &[E::ScalarField],
135    ) -> Result<(), PlonkError>
136    where
137        E: Pairing<BaseField = F>,
138    {
139        for f in fields {
140            self.append_field_elem::<E>(label, f)?;
141        }
142        Ok(())
143    }
144
145    /// Append a proof evaluation to the transcript.
146    fn append_proof_evaluations<E: Pairing<BaseField = F>>(
147        &mut self,
148        evals: &ProofEvaluations<E::ScalarField>,
149    ) -> Result<(), PlonkError> {
150        self.append_field_elems::<E>(b"wire_evals", &evals.wires_evals)?;
151        self.append_field_elems::<E>(b"wire_sigma_evals", &evals.wire_sigma_evals)?;
152        self.append_field_elem::<E>(b"perm_next_eval", &evals.perm_next_eval)
153    }
154
155    /// Append the plookup evaluation to the transcript.
156    fn append_plookup_evaluations<E: Pairing<BaseField = F>>(
157        &mut self,
158        evals: &PlookupEvaluations<E::ScalarField>,
159    ) -> Result<(), PlonkError> {
160        self.append_field_elem::<E>(b"lookup_table_eval", &evals.range_table_eval)?;
161        self.append_field_elem::<E>(b"h_1_eval", &evals.h_1_eval)?;
162        self.append_field_elem::<E>(b"prod_next_eval", &evals.prod_next_eval)?;
163        self.append_field_elem::<E>(b"lookup_table_next_eval", &evals.range_table_next_eval)?;
164        self.append_field_elem::<E>(b"h_1_next_eval", &evals.h_1_next_eval)?;
165        self.append_field_elem::<E>(b"h_2_next_eval", &evals.h_2_next_eval)
166    }
167
168    /// Generate a single challenge for the current round
169    fn get_challenge<E>(&mut self, label: &'static [u8]) -> Result<E::ScalarField, PlonkError>
170    where
171        E: Pairing<BaseField = F>;
172
173    /// Generate multiple challenges for the current round
174    /// Implementers should be careful about domain separation for each
175    /// challenge The default implementation assume `self.get_challenge()`
176    /// already implements proper domain separation for each challenge
177    /// generation, thus simply call it multiple times.
178    fn get_n_challenges<E>(
179        &mut self,
180        labels: &[&'static [u8]],
181    ) -> Result<Vec<E::ScalarField>, PlonkError>
182    where
183        E: Pairing<BaseField = F>,
184    {
185        let mut challenges = Vec::new();
186        for label in labels {
187            challenges.push(self.get_challenge::<E>(label)?);
188        }
189        Ok(challenges)
190    }
191}