use crate::commitment_scheme::kzg10::PublicParameters;
use crate::constraint_system::StandardComposer;
use crate::error::Error;
use crate::proof_system::{Proof, ProverKey, VerifierKey};
#[cfg(feature = "canon")]
use canonical::Canon;
#[cfg(feature = "canon")]
use canonical_derive::Canon;
use dusk_bls12_381::BlsScalar;
use dusk_jubjub::{JubJubAffine, JubJubScalar};
#[derive(Default, Debug, Clone)]
#[cfg_attr(feature = "canon", derive(Canon))]
pub struct PublicInputValue(pub(crate) Vec<BlsScalar>);
impl From<BlsScalar> for PublicInputValue {
fn from(scalar: BlsScalar) -> Self {
Self(vec![scalar])
}
}
impl From<JubJubScalar> for PublicInputValue {
fn from(scalar: JubJubScalar) -> Self {
Self(vec![scalar.into()])
}
}
impl From<JubJubAffine> for PublicInputValue {
fn from(point: JubJubAffine) -> Self {
Self(vec![point.get_x(), point.get_y()])
}
}
pub trait Circuit
where
Self: Sized,
{
const CIRCUIT_ID: [u8; 32];
fn gadget(&mut self, composer: &mut StandardComposer) -> Result<(), Error>;
fn compile(
&mut self,
pub_params: &PublicParameters,
) -> Result<(ProverKey, VerifierKey, Vec<usize>), Error> {
use crate::proof_system::{Prover, Verifier};
let (ck, _) = pub_params.trim(self.padded_circuit_size())?;
let mut prover = Prover::new(b"CircuitCompilation");
self.gadget(prover.mut_cs())?;
let pi_pos = prover.mut_cs().pi_positions();
prover.preprocess(&ck)?;
let mut verifier = Verifier::new(b"CircuitCompilation");
self.gadget(verifier.mut_cs())?;
verifier.preprocess(&ck)?;
Ok((
prover
.prover_key
.expect("Unexpected error. Missing ProverKey in compilation"),
verifier
.verifier_key
.expect("Unexpected error. Missing VerifierKey in compilation"),
pi_pos,
))
}
fn gen_proof(
&mut self,
pub_params: &PublicParameters,
prover_key: &ProverKey,
transcript_init: &'static [u8],
) -> Result<Proof, Error> {
use crate::proof_system::Prover;
let (ck, _) = pub_params.trim(self.padded_circuit_size())?;
let mut prover = Prover::new(transcript_init);
self.gadget(prover.mut_cs())?;
prover.prover_key = Some(prover_key.clone());
prover.prove(&ck)
}
fn padded_circuit_size(&self) -> usize;
}
pub fn verify_proof(
pub_params: &PublicParameters,
verifier_key: &VerifierKey,
proof: &Proof,
pub_inputs_values: &[PublicInputValue],
pub_inputs_positions: &[usize],
transcript_init: &'static [u8],
) -> Result<(), Error> {
use crate::proof_system::Verifier;
let trim_size = verifier_key.padded_circuit_size();
let (_, vk) = pub_params.trim(trim_size)?;
let mut verifier = Verifier::new(transcript_init);
verifier.verifier_key = Some(*verifier_key);
verifier.verify(
proof,
&vk,
build_pi(pub_inputs_values, pub_inputs_positions, trim_size).as_slice(),
)
}
fn build_pi(
pub_input_values: &[PublicInputValue],
pub_input_pos: &[usize],
trim_size: usize,
) -> Vec<BlsScalar> {
let mut pi = vec![BlsScalar::zero(); trim_size];
pub_input_values
.iter()
.map(|pub_input| pub_input.0.clone())
.flatten()
.zip(pub_input_pos.iter().copied())
.for_each(|(value, pos)| {
pi[pos] = -value;
});
pi
}
#[cfg(test)]
mod tests {
use super::*;
use crate::constraint_system::{ecc::*, StandardComposer};
use crate::proof_system::{ProverKey, VerifierKey};
use dusk_bytes::{DeserializableSlice, Serializable};
#[derive(Debug, Default)]
pub struct TestCircuit {
a: BlsScalar,
b: BlsScalar,
c: BlsScalar,
d: BlsScalar,
e: JubJubScalar,
f: JubJubAffine,
}
impl Circuit for TestCircuit {
const CIRCUIT_ID: [u8; 32] = [0xff; 32];
fn gadget(
&mut self,
composer: &mut StandardComposer,
) -> Result<(), Error> {
let a = composer.add_input(self.a);
let b = composer.add_input(self.b);
composer.poly_gate(
a,
b,
composer.zero_var,
BlsScalar::zero(),
BlsScalar::one(),
BlsScalar::one(),
BlsScalar::zero(),
BlsScalar::zero(),
Some(-self.c),
);
composer.range_gate(a, 1 << 6);
composer.range_gate(b, 1 << 5);
composer.poly_gate(
a,
b,
composer.zero_var,
BlsScalar::one(),
BlsScalar::zero(),
BlsScalar::zero(),
BlsScalar::one(),
BlsScalar::zero(),
Some(-self.d),
);
let generator =
Point::from_public_affine(composer, dusk_jubjub::GENERATOR);
let e = composer.add_input(self.e.into());
let scalar_mul_result =
scalar_mul::variable_base::variable_base_scalar_mul(
composer, e, generator,
);
composer
.assert_equal_public_point(scalar_mul_result.into(), self.f);
Ok(())
}
fn padded_circuit_size(&self) -> usize {
1 << 11
}
}
#[test]
fn test_full() -> Result<(), Error> {
use std::fs::{self, File};
use std::io::Write;
use tempdir::TempDir;
let tmp = TempDir::new("plonk-keys-test-full").unwrap().into_path();
let pp_path = tmp.clone().join("pp_testcirc");
let pk_path = tmp.clone().join("pk_testcirc");
let vk_path = tmp.clone().join("vk_testcirc");
let pp_p = PublicParameters::setup(1 << 12, &mut rand::thread_rng())?;
File::create(&pp_path)
.and_then(|mut f| f.write(pp_p.to_raw_var_bytes().as_slice()))
.unwrap();
let pp = fs::read(pp_path).unwrap();
let pp =
unsafe { PublicParameters::from_slice_unchecked(pp.as_slice()) };
let mut circuit = TestCircuit::default();
let (pk_p, vk_p, pi_pos) = circuit.compile(&pp)?;
File::create(&pk_path)
.and_then(|mut f| f.write(pk_p.to_var_bytes().as_slice()))
.unwrap();
File::create(&vk_path)
.and_then(|mut f| f.write(&vk_p.to_bytes()))
.unwrap();
let pk = fs::read(pk_path).unwrap();
let pk = ProverKey::from_slice(pk.as_slice())?;
let vk = fs::read(vk_path).unwrap();
let vk = VerifierKey::from_slice(vk.as_slice())?;
assert_eq!(pk, pk_p);
assert_eq!(vk, vk_p);
let proof = {
let mut circuit = TestCircuit {
a: BlsScalar::from(20u64),
b: BlsScalar::from(5u64),
c: BlsScalar::from(25u64),
d: BlsScalar::from(100u64),
e: JubJubScalar::from(2u64),
f: JubJubAffine::from(
dusk_jubjub::GENERATOR_EXTENDED * JubJubScalar::from(2u64),
),
};
circuit.gen_proof(&pp, &pk, b"Test")
}?;
let public_inputs2: Vec<PublicInputValue> = vec![
BlsScalar::from(25u64).into(),
BlsScalar::from(100u64).into(),
dusk_jubjub::GENERATOR.into(),
JubJubAffine::from(
dusk_jubjub::GENERATOR_EXTENDED * JubJubScalar::from(2u64),
)
.into(),
];
verify_proof(&pp, &vk, &proof, &public_inputs2, &pi_pos, b"Test")
}
}