Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor Composer into trait #700

Merged
merged 2 commits into from
Aug 17, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,13 @@ canonical = {version = "0.7", optional = true}
canonical_derive = {version = "0.7", optional = true}
rkyv = {version = "0.7", optional = true}
bytecheck = {version = "0.6", optional = true}
backtrace = {version = "0.3", optional = true}
dusk-cdf = {version = "0.2", optional = true}

[dev-dependencies]
criterion = "0.3"
tempdir = "0.3"
rand = "0.8"

[[bench]]
name = "plonk"
Expand All @@ -52,8 +55,7 @@ std = [
"rayon"
]
alloc = ["dusk-bls12_381/alloc"]
trace = []
trace-print = ["trace"]
debug = ["dusk-cdf", "backtrace"]
canon = ["dusk-bls12_381/canon", "dusk-jubjub/canon", "canonical", "canonical_derive"]
rkyv-impl = ["dusk-bls12_381/rkyv-impl", "dusk-jubjub/rkyv-impl", "rkyv", "bytecheck"]

Expand Down
95 changes: 26 additions & 69 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,21 +36,16 @@ pub struct TestCircuit {
}

impl Circuit for TestCircuit {
const CIRCUIT_ID: [u8; 32] = [0xff; 32];
fn gadget(
&mut self,
composer: &mut TurboComposer,
) -> Result<(), Error> {
fn circuit<C>(&self, composer: &mut C) -> Result<(), Error>
where
C: Composer,
{
let a = composer.append_witness(self.a);
let b = composer.append_witness(self.b);

// Make first constraint a + b = c
let constraint = Constraint::new()
.left(1)
.right(1)
.public(-self.c)
.a(a)
.b(b);
let constraint =
Constraint::new().left(1).right(1).public(-self.c).a(a).b(b);

composer.append_gate(constraint);

Expand All @@ -59,71 +54,38 @@ impl Circuit for TestCircuit {
composer.component_range(b, 1 << 5);

// Make second constraint a * b = d
let constraint = Constraint::new()
.mult(1)
.public(-self.d)
.a(a)
.b(b);
let constraint =
Constraint::new().mult(1).public(-self.d).a(a).b(b);

composer.append_gate(constraint);

let e = composer.append_witness(self.e);
let scalar_mul_result = composer
.component_mul_generator(e, dusk_jubjub::GENERATOR_EXTENDED);
.component_mul_generator(e, dusk_jubjub::GENERATOR_EXTENDED)?;

// Apply the constraint
composer.assert_equal_public_point(scalar_mul_result, self.f);

Ok(())
}
}

fn public_inputs(&self) -> Vec<PublicInputValue> {
vec![self.c.into(), self.d.into(), self.f.into()]
}
let label = b"transcript-arguments";
let pp = PublicParameters::setup(1 << 12, &mut OsRng)
.expect("failed to setup");

fn padded_gates(&self) -> usize {
1 << 11
}
}
let (prover, verifier) = Compiler::compile::<TestCircuit>(&pp, label)
.expect("failed to compile circuit");

// Generate the proof and its public inputs
let (proof, public_inputs) = prover
.prove(&mut OsRng, &TestCircuit::default())
.expect("failed to prove");

// Now let's use the Circuit we've just implemented!

let pp = PublicParameters::setup(1 << 12, &mut OsRng).unwrap();
// Initialize the circuit
let mut circuit = TestCircuit::default();
// Compile/preproces the circuit
let (pk, vd) = circuit.compile(&pp).unwrap();

// Prover POV
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.prove(&pp, &pk, b"Test", &mut OsRng).unwrap()
};

// Verifier POV
let public_inputs: Vec<PublicInputValue> = vec![
BlsScalar::from(25u64).into(),
BlsScalar::from(100u64).into(),
JubJubAffine::from(
dusk_jubjub::GENERATOR_EXTENDED * JubJubScalar::from(2u64),
)
.into(),
];
TestCircuit::verify(
&pp,
&vd,
&proof,
&public_inputs,
b"Test",
).unwrap();
// Verify the generated proof
verifier
.verify(&proof, &public_inputs)
.expect("failed to verify proof");
```

### Features
Expand All @@ -135,12 +97,7 @@ This crate includes a variety of features which will briefly be explained below:
- `std`: Enables `std` usage as well as `rayon` parallelization in some proving and verifying ops.
It also uses the `std` versions of the elliptic curve deps, which utilizes the `parallel` feature
from `dusk-bls12-381`. By default, this is the feature that comes enabled with the crate.
- `trace`: Enables the Circuit debugger tooling. This is essentially the capability of using the
`TurboComposer::check_circuit_satisfied` function. The function will output information about each circuit gate until
one of the gates does not satisfy the equation, or there are no more gates. If there is an unsatisfied gate
equation, the function will panic and return the gate number.
- `trace-print`: Goes a step further than `trace` and prints each `gate` component data, giving a clear overview of all the
values which make up the circuit that we're constructing.
- `debug`: Enables the runtime debugger backend. Will output [CDF](https://crates.io/crates/dusk-cdf) files to the path defined in the `CDF_OUTPUT` environment variable. If used, the binary must be compiled with `debug = true`. For more info, check the [cargo book](https://doc.rust-lang.org/cargo/reference/profiles.html#debug).
__The recommended method is to derive the std output, and the std error, and then place them in text file
which can be used to efficiently analyse the gates.__
- `canon`: Enables `canonical` serialization for particular data structures, which is very useful in integrating this library within the rest of the Dusk stack - especially for storage purposes.
Expand Down
204 changes: 105 additions & 99 deletions benches/plonk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,127 +8,133 @@

use criterion::{black_box, criterion_group, criterion_main, Criterion};
use dusk_plonk::prelude::*;
use rand_core::OsRng;

#[derive(Debug, Clone, Copy)]
struct BenchCircuit {
degree: usize,
struct BenchCircuit<const DEGREE: usize> {
a: BlsScalar,
b: BlsScalar,
x: BlsScalar,
y: JubJubScalar,
z: JubJubExtended,
}

impl<T> From<T> for BenchCircuit
where
T: Into<usize>,
{
fn from(degree: T) -> Self {
impl<const DEGREE: usize> Default for BenchCircuit<DEGREE> {
fn default() -> Self {
Self {
degree: 1 << degree.into(),
a: BlsScalar::from(2u64),
b: BlsScalar::from(3u64),
x: BlsScalar::from(6u64),
y: JubJubScalar::from(7u64),
z: dusk_jubjub::GENERATOR_EXTENDED * &JubJubScalar::from(7u64),
}
}
}

impl Circuit for BenchCircuit {
const CIRCUIT_ID: [u8; 32] = [0xff; 32];

fn gadget(&mut self, composer: &mut TurboComposer) -> Result<(), Error> {
let mut a = BlsScalar::from(2u64);
let mut b = BlsScalar::from(3u64);
let mut c;

while composer.gates() < self.padded_gates() {
a += BlsScalar::one();
b += BlsScalar::one();
c = a * b + a + b + BlsScalar::one();

let x = composer.append_witness(a);
let y = composer.append_witness(b);
let z = composer.append_witness(c);

let constraint = Constraint::new()
.mult(1)
.left(1)
.right(1)
.output(-BlsScalar::one())
.constant(1)
.a(x)
.b(y)
.o(z);

composer.append_gate(constraint);
impl<const DEGREE: usize> Circuit for BenchCircuit<DEGREE> {
fn circuit<C>(&self, composer: &mut C) -> Result<(), Error>
where
C: Composer,
{
let w_a = composer.append_witness(self.a);
let w_b = composer.append_witness(self.b);
let w_x = composer.append_witness(self.x);
let w_y = composer.append_witness(self.y);
let w_z = composer.append_point(self.z);

let mut diff = 0;
let mut prev = composer.constraints();

while prev + diff < DEGREE {
let r_w =
composer.gate_mul(Constraint::new().mult(1).a(w_a).b(w_b));

composer.append_constant(15);
composer.append_constant_point(self.z);

composer.assert_equal(w_x, r_w);
composer.assert_equal_point(w_z, w_z);

composer.gate_add(Constraint::new().left(1).right(1).a(w_a).b(w_b));

composer.component_add_point(w_z, w_z);
composer.append_logic_and(w_a, w_b, 254);
composer.append_logic_xor(w_a, w_b, 254);
composer.component_boolean(C::ONE);
composer.component_decomposition::<254>(w_a);
composer.component_mul_generator(
w_y,
dusk_jubjub::GENERATOR_EXTENDED,
)?;
composer.component_mul_point(w_y, w_z);
composer.component_range(w_a, 254);
composer.component_select(C::ONE, w_a, w_b);
composer.component_select_identity(C::ONE, w_z);
composer.component_select_one(C::ONE, w_a);
composer.component_select_point(C::ONE, w_z, w_z);
composer.component_select_zero(C::ONE, w_a);

diff = composer.constraints() - prev;
prev = composer.constraints();
}

Ok(())
}

fn public_inputs(&self) -> Vec<PublicInputValue> {
vec![]
}

fn padded_gates(&self) -> usize {
self.degree
}
}

fn constraint_system_prove(
circuit: &mut BenchCircuit,
fn run<const DEGREE: usize>(
c: &mut Criterion,
pp: &PublicParameters,
pk: &ProverKey,
label: &'static [u8],
) -> Proof {
circuit
.prove(pp, pk, label, &mut OsRng)
.expect("Failed to prove bench circuit!")
) {
let (prover, verifier) =
Compiler::compile::<BenchCircuit<DEGREE>>(&pp, label)
.expect("failed to compile circuit");

// sanity run
let (proof, public_inputs) = prover
.prove(&mut rand_core::OsRng, &Default::default())
.expect("failed to prove");

verifier
.verify(&proof, &public_inputs)
.expect("failed to verify proof");

let power = (DEGREE as f64).log2() as usize;
let description = format!("Prove 2^{} = {} gates", power, DEGREE);

c.bench_function(description.as_str(), |b| {
b.iter(|| {
black_box(prover.prove(&mut rand_core::OsRng, &Default::default()))
})
});

let description = format!("Verify 2^{} = {} gates", power, DEGREE);

c.bench_function(description.as_str(), |b| {
b.iter(|| verifier.verify(black_box(&proof), black_box(&public_inputs)))
});
}

fn constraint_system_benchmark(c: &mut Criterion) {
let initial_degree = 5;
let final_degree = 17;
const MAX_DEGREE: usize = 17;

let rng = &mut rand_core::OsRng;
let label = b"dusk-network";
let pp = PublicParameters::setup(1 << final_degree, rng)
.expect("Failed to create PP");

let data: Vec<(BenchCircuit, ProverKey, VerifierData, Proof)> =
(initial_degree..=final_degree)
.map(|degree| {
let mut circuit = BenchCircuit::from(degree as usize);
let (pk, vd) =
circuit.compile(&pp).expect("Failed to compile circuit!");

let proof =
constraint_system_prove(&mut circuit, &pp, &pk, label);

BenchCircuit::verify(&pp, &vd, &proof, &[], label)
.expect("Failed to verify bench circuit");

(circuit, pk, vd, proof)
})
.collect();

data.iter().for_each(|(mut circuit, pk, _, _)| {
let size = circuit.padded_gates();
let power = (size as f64).log2() as usize;
let description = format!("Prove 2^{} = {} gates", power, size);

c.bench_function(description.as_str(), |b| {
b.iter(|| {
constraint_system_prove(black_box(&mut circuit), &pp, pk, label)
})
});
});

data.iter().for_each(|(circuit, _, vd, proof)| {
let size = circuit.padded_gates();
let power = (size as f64).log2() as usize;
let description = format!("Verify 2^{} = {} gates", power, size);

c.bench_function(description.as_str(), |b| {
b.iter(|| {
BenchCircuit::verify(&pp, vd, black_box(proof), &[], label)
.expect("Failed to verify bench circuit!");
})
});
});
let pp = PublicParameters::setup(1 << MAX_DEGREE, &mut rand_core::OsRng)
.expect("failed to generate pp");

run::<{ 1 << 5 }>(c, &pp, label);
run::<{ 1 << 6 }>(c, &pp, label);
run::<{ 1 << 7 }>(c, &pp, label);
run::<{ 1 << 8 }>(c, &pp, label);
run::<{ 1 << 9 }>(c, &pp, label);
run::<{ 1 << 10 }>(c, &pp, label);
run::<{ 1 << 11 }>(c, &pp, label);
run::<{ 1 << 12 }>(c, &pp, label);
run::<{ 1 << 13 }>(c, &pp, label);
run::<{ 1 << 14 }>(c, &pp, label);
run::<{ 1 << 15 }>(c, &pp, label);
run::<{ 1 << 16 }>(c, &pp, label);
run::<{ 1 << 17 }>(c, &pp, label);
moCello marked this conversation as resolved.
Show resolved Hide resolved
}

criterion_group! {
Expand Down
Loading