fullcodec_plonk/circuit.rs
1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4//
5// Copyright (c) DUSK NETWORK. All rights reserved.
6
7//! Tools & traits for PLONK circuits
8
9use crate::commitment_scheme::PublicParameters;
10use crate::constraint_system::TurboComposer;
11use crate::error::Error;
12use crate::proof_system::{Proof, Prover, ProverKey, Verifier, VerifierKey};
13#[cfg(feature = "canon")]
14use canonical_derive::Canon;
15use dusk_bls12_381::BlsScalar;
16use dusk_bytes::{DeserializableSlice, Serializable, Write};
17use dusk_jubjub::{JubJubAffine, JubJubExtended, JubJubScalar};
18use parity_scale_codec::{Decode, Encode};
19use sp_std::vec;
20use sp_std::vec::Vec;
21
22#[derive(Default, Debug, Clone, PartialEq, Decode, Encode)]
23#[cfg_attr(feature = "canon", derive(Canon))]
24/// Structure that represents a PLONK Circuit Public Input converted into it's
25/// &\[[`BlsScalar`]\] repr.
26pub struct PublicInputValue(pub(crate) Vec<BlsScalar>);
27
28impl From<BlsScalar> for PublicInputValue {
29 fn from(scalar: BlsScalar) -> Self {
30 Self(vec![scalar])
31 }
32}
33
34impl From<JubJubScalar> for PublicInputValue {
35 fn from(scalar: JubJubScalar) -> Self {
36 Self(vec![scalar.into()])
37 }
38}
39
40impl From<JubJubAffine> for PublicInputValue {
41 fn from(point: JubJubAffine) -> Self {
42 Self(vec![point.get_x(), point.get_y()])
43 }
44}
45
46impl From<JubJubExtended> for PublicInputValue {
47 fn from(point: JubJubExtended) -> Self {
48 JubJubAffine::from(point).into()
49 }
50}
51
52#[derive(Debug, Clone, PartialEq, Decode, Encode)]
53/// Collection of structs/objects that the Verifier will use in order to
54/// de/serialize data needed for Circuit proof verification.
55/// This structure can be seen as a link between the [`Circuit`] public input
56/// positions and the [`VerifierKey`] that the Verifier needs to use.
57pub struct VerifierData {
58 key: VerifierKey,
59 public_inputs_indexes: Vec<u32>,
60}
61
62impl VerifierData {
63 /// Creates a new `VerifierData` from a [`VerifierKey`] and the public
64 /// input positions of the circuit that it represents.
65 pub const fn new(
66 key: VerifierKey,
67 public_inputs_indexes: Vec<u32>,
68 ) -> Self {
69 Self {
70 key,
71 public_inputs_indexes,
72 }
73 }
74
75 /// Returns a reference to the contained [`VerifierKey`].
76 pub const fn key(&self) -> &VerifierKey {
77 &self.key
78 }
79
80 /// Returns a reference to the contained Public Input positions.
81 pub fn public_inputs_indexes(&self) -> &[u32] {
82 &self.public_inputs_indexes
83 }
84
85 /// Deserializes the `VerifierData` into a vector of bytes.
86 #[allow(unused_must_use)]
87 pub fn to_var_bytes(&self) -> Vec<u8> {
88 let mut buff = vec![
89 0u8;
90 VerifierKey::SIZE
91 + u32::SIZE
92 + self.public_inputs_indexes.len() * u32::SIZE
93 ];
94 let mut writer = &mut buff[..];
95
96 writer.write(&self.key.to_bytes());
97 writer.write(&(self.public_inputs_indexes.len() as u32).to_bytes());
98 self.public_inputs_indexes.iter().copied().for_each(|pos| {
99 // Omit the result since disk_bytes write can't fail here
100 // due to the fact that we're writing into a vector basically.
101 let _ = writer.write(&(pos as u32).to_bytes());
102 });
103
104 buff
105 }
106
107 /// Serializes `VerifierData` from a slice of bytes.
108 pub fn from_slice(mut buf: &[u8]) -> Result<Self, Error> {
109 let key = VerifierKey::from_reader(&mut buf)?;
110 let pos_num = u32::from_reader(&mut buf)? as usize;
111
112 let mut public_inputs_indexes = vec![];
113 for _ in 0..pos_num {
114 public_inputs_indexes.push(u32::from_reader(&mut buf)?);
115 }
116
117 Ok(Self {
118 key,
119 public_inputs_indexes,
120 })
121 }
122}
123
124/// Trait that should be implemented for any circuit function to provide to it
125/// the capabilities of automatically being able to generate, and verify proofs
126/// as well as compile the circuit.
127/// # Example
128///
129/// ```
130/// use fullcodec_plonk::prelude::*;
131/// use rand::SeedableRng;
132/// use rand_xorshift::XorShiftRng;
133///
134/// fn main() -> Result<(), Error> {
135/// // Implements a circuit that checks:
136/// // 1) a + b = c where C is a PI
137/// // 2) a <= 2^6
138/// // 3) b <= 2^5
139/// // 4) a * b = d where D is a PI
140/// // 5) JubJub::GENERATOR * e(JubJubScalar) = f where F is a PI
141/// #[derive(Debug, Default)]
142/// pub struct TestCircuit {
143/// a: BlsScalar,
144/// b: BlsScalar,
145/// c: BlsScalar,
146/// d: BlsScalar,
147/// e: JubJubScalar,
148/// f: JubJubAffine,
149/// }
150///
151/// impl Circuit for TestCircuit {
152/// const CIRCUIT_ID: [u8; 32] = [0xff; 32];
153/// fn gadget(
154/// &mut self,
155/// composer: &mut TurboComposer,
156/// ) -> Result<(), Error> {
157/// // Add fixed witness zero
158/// let zero = TurboComposer::constant_zero();
159/// let a = composer.append_witness(self.a);
160/// let b = composer.append_witness(self.b);
161///
162/// // Make first constraint a + b = c
163/// let constraint = Constraint::new()
164/// .left(1)
165/// .right(1)
166/// .public(-self.c)
167/// .a(a)
168/// .b(b);
169///
170/// composer.append_gate(constraint);
171///
172/// // Check that a and b are in range
173/// composer.component_range(a, 1 << 6);
174/// composer.component_range(b, 1 << 5);
175///
176/// // Make second constraint a * b = d
177/// let constraint = Constraint::new()
178/// .mult(1)
179/// .output(1)
180/// .public(-self.d)
181/// .a(a)
182/// .b(b);
183///
184/// composer.append_gate(constraint);
185///
186/// let e = composer.append_witness(self.e);
187/// let scalar_mul_result =
188/// composer.component_mul_generator(
189/// e, dusk_jubjub::GENERATOR_EXTENDED,
190/// );
191/// // Apply the constrain
192/// composer
193/// .assert_equal_public_point(scalar_mul_result, self.f);
194/// Ok(())
195/// }
196///
197/// fn public_inputs(&self) -> Vec<PublicInputValue> {
198/// vec![self.c.into(), self.d.into(), self.f.into()]
199/// }
200///
201/// fn padded_gates(&self) -> usize {
202/// 1 << 11
203/// }
204/// }
205///
206/// let rng = XorShiftRng::from_seed([
207/// 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37,
208/// 0x32, 0x54, 0x06, 0xbc, 0xe5,
209/// ]);
210///
211/// let pp = PublicParameters::setup(1 << 12, rng)?;
212/// // Initialize the circuit
213/// let mut circuit = TestCircuit::default();
214/// // Compile the circuit
215/// let (pk, vd) = circuit.compile(&pp)?;
216///
217/// // Prover POV
218/// let proof = {
219/// let mut circuit = TestCircuit {
220/// a: BlsScalar::from(20u64),
221/// b: BlsScalar::from(5u64),
222/// c: BlsScalar::from(25u64),
223/// d: BlsScalar::from(100u64),
224/// e: JubJubScalar::from(2u64),
225/// f: JubJubAffine::from(
226/// dusk_jubjub::GENERATOR_EXTENDED * JubJubScalar::from(2u64),
227/// ),
228/// };
229///
230/// circuit.prove(&pp, &pk, b"Test")
231/// }?;
232///
233/// // Verifier POV
234/// let public_inputs: Vec<PublicInputValue> = vec![
235/// BlsScalar::from(25u64).into(),
236/// BlsScalar::from(100u64).into(),
237/// JubJubAffine::from(
238/// dusk_jubjub::GENERATOR_EXTENDED * JubJubScalar::from(2u64),
239/// )
240/// .into(),
241/// ];
242///
243/// TestCircuit::verify(
244/// &pp,
245/// &vd,
246/// &proof,
247/// &public_inputs,
248/// b"Test",
249/// )
250/// }
251pub trait Circuit
252where
253 Self: Sized,
254{
255 /// Circuit identifier associated constant.
256 const CIRCUIT_ID: [u8; 32];
257
258 /// Gadget implementation used to fill the composer.
259 fn gadget(&mut self, composer: &mut TurboComposer) -> Result<(), Error>;
260
261 /// Compiles the circuit by using a function that returns a `Result`
262 /// with the `ProverKey`, `VerifierKey` and the circuit size.
263 fn compile(
264 &mut self,
265 pub_params: &PublicParameters,
266 ) -> Result<(ProverKey, VerifierData), Error> {
267 // Setup PublicParams
268 let (ck, _) = pub_params.trim(self.padded_gates())?;
269
270 // Generate & save `ProverKey` with some random values.
271 let mut prover = Prover::new(b"CircuitCompilation");
272
273 self.gadget(prover.composer_mut())?;
274
275 let public_inputs_indexes =
276 prover.composer_mut().public_input_indexes();
277
278 prover.preprocess(&ck)?;
279
280 // Generate & save `VerifierKey` with some random values.
281 let mut verifier = Verifier::new(b"CircuitCompilation");
282
283 self.gadget(verifier.composer_mut())?;
284
285 verifier.preprocess(&ck)?;
286
287 Ok((
288 prover
289 .prover_key
290 .expect("Unexpected error. Missing ProverKey in compilation"),
291 VerifierData::new(
292 verifier.verifier_key.expect(
293 "Unexpected error. Missing VerifierKey in compilation",
294 ),
295 public_inputs_indexes,
296 ),
297 ))
298 }
299
300 /// Generates a proof using the provided `CircuitInputs` & `ProverKey`
301 /// instances.
302 fn prove(
303 &mut self,
304 pub_params: &PublicParameters,
305 prover_key: &ProverKey,
306 transcript_init: &'static [u8],
307 ) -> Result<Proof, Error> {
308 let (ck, _) = pub_params.trim(self.padded_gates())?;
309
310 // New Prover instance
311 let mut prover = Prover::new(transcript_init);
312
313 // Fill witnesses for Prover
314 self.gadget(prover.composer_mut())?;
315
316 // Add ProverKey to Prover
317 prover.prover_key = Some(prover_key.clone());
318 prover.prove(&ck)
319 }
320
321 /// Verify the provided proof for the compiled verifier data
322 fn verify(
323 pub_params: &PublicParameters,
324 verifier_data: &VerifierData,
325 proof: &Proof,
326 public_inputs: &[PublicInputValue],
327 transcript_init: &'static [u8],
328 ) -> Result<(), Error> {
329 let gates = verifier_data.key().padded_gates();
330 let pi_indexes = verifier_data.public_inputs_indexes();
331
332 let mut dense_pi = vec![BlsScalar::zero(); gates as usize];
333
334 public_inputs
335 .iter()
336 .map(|pi| pi.0.clone())
337 .flatten()
338 .zip(pi_indexes.iter().cloned())
339 .for_each(|(value, pos)| {
340 dense_pi[pos as usize] = -value;
341 });
342
343 let mut verifier = Verifier::new(transcript_init);
344
345 verifier.verifier_key.replace(*verifier_data.key());
346
347 let opening_key = pub_params.opening_key();
348
349 verifier.verify(proof, opening_key, &dense_pi)
350 }
351
352 /// Return the list of public inputs generated by the gadget
353 fn public_inputs(&self) -> Vec<PublicInputValue>;
354
355 /// Returns the Circuit size padded to the next power of two.
356 fn padded_gates(&self) -> usize;
357}