diff --git a/plonky2/Cargo.toml b/plonky2/Cargo.toml index 6df46060..39b95f21 100644 --- a/plonky2/Cargo.toml +++ b/plonky2/Cargo.toml @@ -31,6 +31,7 @@ plonky2_util = { version = "0.1.0", default-features = false } rand = { version = "0.8.4", default-features = false } rand_chacha = { version = "0.3.1", optional = true, default-features = false } serde = { version = "1.0", default-features = false, features = ["derive"] } +serde_json = "1.0" static_assertions = { version = "1.1.0", default-features = false } unroll = { version = "0.1.5", default-features = false } diff --git a/plonky2/examples/fibonacci_serialization.rs b/plonky2/examples/fibonacci_serialization.rs new file mode 100644 index 00000000..68943457 --- /dev/null +++ b/plonky2/examples/fibonacci_serialization.rs @@ -0,0 +1,79 @@ +#![allow(clippy::upper_case_acronyms)] + +use std::fs; + +use anyhow::Result; +use plonky2::field::types::Field; +use plonky2::iop::witness::{PartialWitness, WitnessWrite}; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2::plonk::circuit_data::CircuitConfig; +use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + +/// An example of using Plonky2 to prove a statement of the form +/// "I know the 100th element of the Fibonacci sequence, starting with constants a and b." +/// When a == 0 and b == 1, this is proving knowledge of the 100th (standard) Fibonacci number. +/// This example also serializes the circuit data and proof to JSON files. +fn main() -> Result<()> { + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + + let config = CircuitConfig::standard_recursion_config(); + let mut builder = CircuitBuilder::::new(config); + + // The arithmetic circuit. + let initial_a = builder.add_virtual_target(); + let initial_b = builder.add_virtual_target(); + let mut prev_target = initial_a; + let mut cur_target = initial_b; + for _ in 0..99 { + let temp = builder.add(prev_target, cur_target); + prev_target = cur_target; + cur_target = temp; + } + + // Public inputs are the two initial values (provided below) and the result (which is generated). + builder.register_public_input(initial_a); + builder.register_public_input(initial_b); + builder.register_public_input(cur_target); + + // Provide initial values. + let mut pw = PartialWitness::new(); + pw.set_target(initial_a, F::ZERO); + pw.set_target(initial_b, F::ONE); + + let data = builder.build::(); + + let common_circuit_data_serialized = serde_json::to_string(&data.common).unwrap(); + fs::write("common_circuit_data.json", common_circuit_data_serialized) + .expect("Unable to write file"); + + let verifier_only_circuit_data_serialized = serde_json::to_string(&data.verifier_only).unwrap(); + fs::write( + "verifier_only_circuit_data.json", + verifier_only_circuit_data_serialized, + ) + .expect("Unable to write file"); + + let proof = data.prove(pw)?; + + let proof_serialized = serde_json::to_string(&proof).unwrap(); + fs::write("proof_with_public_inputs.json", proof_serialized).expect("Unable to write file"); + + let proof_challenges = proof + .get_challenges( + proof.get_public_inputs_hash(), + &data.verifier_only.circuit_digest, + &data.common, + ) + .unwrap(); + let proof_challenges_serialized = serde_json::to_string(&proof_challenges).unwrap(); + fs::write("proof_challenges.json", proof_challenges_serialized).expect("Unable to write file"); + + println!( + "100th Fibonacci number mod |F| (starting with {}, {}) is: {}", + proof.public_inputs[0], proof.public_inputs[1], proof.public_inputs[2] + ); + + data.verify(proof) +} diff --git a/plonky2/src/fri/mod.rs b/plonky2/src/fri/mod.rs index ca800b98..5121d755 100644 --- a/plonky2/src/fri/mod.rs +++ b/plonky2/src/fri/mod.rs @@ -1,5 +1,7 @@ use alloc::vec::Vec; +use serde::Serialize; + use crate::fri::reduction_strategies::FriReductionStrategy; mod challenges; @@ -13,7 +15,7 @@ mod validate_shape; pub mod verifier; pub mod witness_util; -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq, Serialize)] pub struct FriConfig { /// `rate = 2^{-rate_bits}`. pub rate_bits: usize, @@ -56,7 +58,7 @@ impl FriConfig { /// FRI parameters, including generated parameters which are specific to an instance size, in /// contrast to `FriConfig` which is user-specified and independent of instance size. -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq, Serialize)] pub struct FriParams { /// User-specified FRI configuration. pub config: FriConfig, diff --git a/plonky2/src/fri/proof.rs b/plonky2/src/fri/proof.rs index 326001fd..d00feb4c 100644 --- a/plonky2/src/fri/proof.rs +++ b/plonky2/src/fri/proof.rs @@ -393,6 +393,7 @@ impl, HCO: HashConfig, H: Hasher, const D: } } +#[derive(Serialize)] pub struct FriChallenges, const D: usize> { // Scaling factor to combine polynomials. pub fri_alpha: F::Extension, diff --git a/plonky2/src/fri/reduction_strategies.rs b/plonky2/src/fri/reduction_strategies.rs index 409a0224..df273eea 100644 --- a/plonky2/src/fri/reduction_strategies.rs +++ b/plonky2/src/fri/reduction_strategies.rs @@ -4,9 +4,10 @@ use alloc::vec::Vec; use std::time::Instant; use log::debug; +use serde::Serialize; /// A method for deciding what arity to use at each reduction layer. -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq, Serialize)] pub enum FriReductionStrategy { /// Specifies the exact sequence of arities (expressed in bits) to use. Fixed(Vec), diff --git a/plonky2/src/gates/constant.rs b/plonky2/src/gates/constant.rs index f794c904..5fac1f00 100644 --- a/plonky2/src/gates/constant.rs +++ b/plonky2/src/gates/constant.rs @@ -2,6 +2,8 @@ use alloc::string::String; use alloc::vec::Vec; use alloc::{format, vec}; +use serde::{Deserialize, Serialize}; + use crate::field::extension::Extendable; use crate::field::packed::PackedField; use crate::gates::gate::Gate; @@ -18,7 +20,7 @@ use crate::plonk::vars::{ use crate::util::serialization::{Buffer, IoResult, Read, Write}; /// A gate which takes a single constant parameter and outputs that value. -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Serialize, Deserialize)] pub struct ConstantGate { pub(crate) num_consts: usize, } diff --git a/plonky2/src/gates/gate.rs b/plonky2/src/gates/gate.rs index 43c1179a..1dbc4f57 100644 --- a/plonky2/src/gates/gate.rs +++ b/plonky2/src/gates/gate.rs @@ -8,6 +8,7 @@ use core::hash::{Hash, Hasher}; use core::ops::Range; use hashbrown::HashMap; +use serde::{Serialize, Serializer}; use crate::field::batch_util::batch_multiply_inplace; use crate::field::extension::{Extendable, FieldExtension}; @@ -239,6 +240,12 @@ impl, const D: usize> Debug for GateRef { } } +impl, const D: usize> Serialize for GateRef { + fn serialize(&self, serializer: S) -> Result { + serializer.serialize_str(&self.0.id()) + } +} + /// Map between gate parameters and available slots. /// An available slot is of the form `(row, op)`, meaning the current available slot /// is at gate index `row` in the `op`-th operation. diff --git a/plonky2/src/gates/selectors.rs b/plonky2/src/gates/selectors.rs index 7217de2f..0e690c6d 100644 --- a/plonky2/src/gates/selectors.rs +++ b/plonky2/src/gates/selectors.rs @@ -2,6 +2,8 @@ use alloc::vec; use alloc::vec::Vec; use core::ops::Range; +use serde::Serialize; + use crate::field::extension::Extendable; use crate::field::polynomial::PolynomialValues; use crate::gates::gate::{GateInstance, GateRef}; @@ -10,7 +12,7 @@ use crate::hash::hash_types::RichField; /// Placeholder value to indicate that a gate doesn't use a selector polynomial. pub(crate) const UNUSED_SELECTOR: usize = u32::MAX as usize; -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq, Serialize)] pub struct SelectorsInfo { pub(crate) selector_indices: Vec, pub(crate) groups: Vec>, diff --git a/plonky2/src/plonk/circuit_data.rs b/plonky2/src/plonk/circuit_data.rs index fa9af818..8ecf646e 100644 --- a/plonky2/src/plonk/circuit_data.rs +++ b/plonky2/src/plonk/circuit_data.rs @@ -4,6 +4,7 @@ use alloc::vec::Vec; use core::ops::{Range, RangeFrom}; use anyhow::Result; +use serde::Serialize; use crate::field::extension::Extendable; use crate::field::fft::FftRootTable; @@ -35,7 +36,7 @@ use crate::util::serialization::{ }; use crate::util::timing::TimingTree; -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct CircuitConfig { pub num_wires: usize, pub num_routed_wires: usize, @@ -347,7 +348,7 @@ pub struct ProverOnlyCircuitData< } /// Circuit data required by the verifier, but not the prover. -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq, Serialize)] pub struct VerifierOnlyCircuitData, const D: usize> { /// A commitment to each constant polynomial and each permutation polynomial. pub constants_sigmas_cap: MerkleCap, @@ -370,7 +371,7 @@ impl, const D: usize> VerifierOnlyCircuitData { } /// Circuit data required by both the prover and the verifier. -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq, Serialize)] pub struct CommonCircuitData, const D: usize> { pub config: CircuitConfig, diff --git a/plonky2/src/plonk/config.rs b/plonky2/src/plonk/config.rs index 60f9a7b8..a5fe5bdc 100644 --- a/plonky2/src/plonk/config.rs +++ b/plonky2/src/plonk/config.rs @@ -117,7 +117,7 @@ impl HashConfig for PoseidonHashConfig { const WIDTH: usize = 12; } /// Configuration using Poseidon over the Goldilocks field. -#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize)] pub struct PoseidonGoldilocksConfig; impl GenericConfig<2> for PoseidonGoldilocksConfig { type F = GoldilocksField; diff --git a/plonky2/src/plonk/get_challenges.rs b/plonky2/src/plonk/get_challenges.rs index d0682572..0e90b398 100644 --- a/plonky2/src/plonk/get_challenges.rs +++ b/plonky2/src/plonk/get_challenges.rs @@ -94,7 +94,7 @@ impl, C: GenericConfig, const D: usize> } /// Computes all Fiat-Shamir challenges used in the Plonk proof. - pub(crate) fn get_challenges( + pub fn get_challenges( &self, public_inputs_hash: <>::InnerHasher as Hasher>::Hash, circuit_digest: &<>::Hasher as Hasher>::Hash, diff --git a/plonky2/src/plonk/proof.rs b/plonky2/src/plonk/proof.rs index 90a7ea86..fe4a0511 100644 --- a/plonky2/src/plonk/proof.rs +++ b/plonky2/src/plonk/proof.rs @@ -102,7 +102,7 @@ impl, C: GenericConfig, const D: usize> }) } - pub(crate) fn get_public_inputs_hash( + pub fn get_public_inputs_hash( &self, ) -> <>::InnerHasher as Hasher>::Hash where @@ -276,7 +276,8 @@ impl, C: GenericConfig, const D: usize> } } -pub(crate) struct ProofChallenges, const D: usize> { +#[derive(Serialize)] +pub struct ProofChallenges, const D: usize> { /// Random values used in Plonk's permutation argument. pub plonk_betas: Vec,