Skip to content

Commit

Permalink
Change unit tests as integration tests when possible (#599)
Browse files Browse the repository at this point in the history
Change unit tests to be integration tests

- Change test_full() to be an integration test
- Change CI to run all binaries generated by `cargo test --no-run`

Resolves: #500
  • Loading branch information
ureeves authored and vlopes11 committed Oct 18, 2021
1 parent 2e1a042 commit f856821
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 183 deletions.
6 changes: 5 additions & 1 deletion .github/workflows/dusk_ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,11 @@ jobs:

- name: Test with kcov
if: ${{ matrix.os == 'ubuntu-latest' && matrix.toolchain == 'nightly' }}
run: kcov --exclude-pattern=/.cargo,/usr/lib --verify target/cov target/release/deps/dusk_plonk-*[^.d][^.gcno]
# Find every executable resulting from building the tests and run each
# one of them with kcov. This ensures all the code we cover is measured.
run: >
find target/release/deps -type f -executable ! -name "*.*" -exec
kcov --exclude-pattern=/.cargo,/usr/lib --verify target/cov {} \;
- name: Upload coverage
if: ${{ matrix.os == 'ubuntu-latest' && matrix.toolchain == 'nightly' }}
Expand Down
184 changes: 2 additions & 182 deletions src/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ impl VerifierData {
/// &pp,
/// &vd,
/// &proof,
/// public_inputs.as_slice(),
/// &public_inputs,
/// b"Test",
/// )
/// }
Expand Down Expand Up @@ -346,7 +346,7 @@ where

let opening_key = pub_params.opening_key();

verifier.verify(proof, opening_key, dense_pi.as_slice())
verifier.verify(proof, opening_key, &dense_pi)
}

/// Return the list of public inputs generated by the gadget
Expand All @@ -355,183 +355,3 @@ where
/// Returns the Circuit size padded to the next power of two.
fn padded_gates(&self) -> usize;
}

#[cfg(feature = "std")]
#[cfg(test)]
mod tests {
use super::*;
use crate::constraint_system::{Constraint, TurboComposer};
use crate::proof_system::ProverKey;

type Result<T> = std::result::Result<T, TestError>;

#[derive(Debug)]
enum TestError {
Plonk(Error),
Io(std::io::Error),
}

impl From<Error> for TestError {
fn from(pe: Error) -> Self {
Self::Plonk(pe)
}
}

impl From<std::io::Error> for TestError {
fn from(ie: std::io::Error) -> Self {
Self::Io(ie)
}
}

// Implements a circuit that checks:
// 1) a + b = c where C is a PI
// 2) a <= 2^6
// 3) b <= 2^5
// 4) a * b = d where D is a PI
// 5) JubJub::GENERATOR * e(JubJubScalar) = f where F is a PI
#[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 TurboComposer,
) -> std::result::Result<(), Error> {
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);
composer.append_gate(
a,
b,
composer.constant_zero(),
composer.constant_zero(),
constraint,
);

// Check that a and b are in range
composer.component_range(a, 1 << 6);
composer.component_range(b, 1 << 5);

// Make second constraint a * b = d
let constraint = Constraint::new().mul(1).output(1).public(-self.d);
composer.append_gate(
a,
b,
composer.constant_zero(),
composer.constant_zero(),
constraint,
);

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

// Apply the constrain
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()]
}

fn padded_gates(&self) -> usize {
1 << 11
}
}

#[test]
fn test_full() -> Result<()> {
use rand_core::OsRng;
use std::fs::{self, File};
use std::io::Write;
use tempdir::TempDir;

let tmp = TempDir::new("plonk-keys-test-full")?.into_path();
let pp_path = tmp.join("pp_testcirc");
let pk_path = tmp.join("pk_testcirc");
let vd_path = tmp.join("vd_testcirc");

// Generate CRS
let pp_p = PublicParameters::setup(1 << 12, &mut OsRng)?;
File::create(&pp_path)
.and_then(|mut f| f.write(pp_p.to_raw_var_bytes().as_slice()))?;

// Read PublicParameters
let pp = fs::read(pp_path)?;
let pp =
unsafe { PublicParameters::from_slice_unchecked(pp.as_slice()) };

// Initialize the circuit
let mut circuit = TestCircuit::default();

// Compile the circuit
let (pk_p, vd_p) = circuit.compile(&pp)?;

// Write the keys
File::create(&pk_path)
.and_then(|mut f| f.write(pk_p.to_var_bytes().as_slice()))?;

// Read ProverKey
let pk = fs::read(pk_path)?;
let pk = ProverKey::from_slice(pk.as_slice())?;

assert_eq!(pk, pk_p);

// Store the VerifierData just for the verifier side:
// (You could also store public_inputs_indexes and VerifierKey
// sepparatedly).
File::create(&vd_path)
.and_then(|mut f| f.write(vd_p.to_var_bytes().as_slice()))?;
let vd = fs::read(vd_path)?;
let vd = VerifierData::from_slice(vd.as_slice())?;

assert_eq!(vd_p.key(), vd.key());
assert_eq!(vd_p.public_inputs_indexes(), vd.public_inputs_indexes());

// 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")
}?;

// 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(),
];

Ok(TestCircuit::verify(
&pp,
&vd,
&proof,
public_inputs.as_slice(),
b"Test",
)?)
}
}
156 changes: 156 additions & 0 deletions tests/circuit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Copyright (c) DUSK NETWORK. All rights reserved.

use dusk_plonk::prelude::*;
use rand_core::OsRng;
use std::fs;

type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;

// Implements a circuit that checks:
// 1) a + b = c where C is a PI
// 2) a <= 2^6
// 3) b <= 2^5
// 4) a * b = d where D is a PI
// 5) JubJub::GENERATOR * e(JubJubScalar) = f where F is a PI
#[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 TurboComposer,
) -> std::result::Result<(), Error> {
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);
composer.append_gate(
a,
b,
composer.constant_zero(),
composer.constant_zero(),
constraint,
);

// Check that a and b are in range
composer.component_range(a, 1 << 6);
composer.component_range(b, 1 << 5);

// Make second constraint a * b = d
let constraint = Constraint::new().mul(1).output(1).public(-self.d);
composer.append_gate(
a,
b,
composer.constant_zero(),
composer.constant_zero(),
constraint,
);

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

// Apply the constrain
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()]
}

fn padded_gates(&self) -> usize {
1 << 11
}
}

#[test]
fn test_full() -> Result<()> {
use tempdir::TempDir;

let tmp = TempDir::new("plonk-keys-test-full")?.into_path();
let pp_path = tmp.join("pp_testcirc");
let pk_path = tmp.join("pk_testcirc");
let vd_path = tmp.join("vd_testcirc");

// Generate CRS
let pp_p = PublicParameters::setup(1 << 12, &mut OsRng)?;
fs::write(&pp_path, &pp_p.to_raw_var_bytes())?;

// Read PublicParameters
let pp = fs::read(pp_path)?;
let pp = unsafe { PublicParameters::from_slice_unchecked(&pp) };

// Initialize the circuit
let mut circuit = TestCircuit::default();

// Compile the circuit
let (pk_p, vd_p) = circuit.compile(&pp)?;

// Write the keys
fs::write(&pk_path, &pk_p.to_var_bytes())?;

// Read ProverKey
let pk = fs::read(pk_path)?;
let pk = ProverKey::from_slice(&pk)?;

assert_eq!(pk, pk_p);

// Store the VerifierData just for the verifier side:
// (You could also store public_inputs_indexes and VerifierKey
// sepparatedly).
fs::write(&vd_path, &vd_p.to_var_bytes())?;
let vd = fs::read(vd_path)?;
let vd = VerifierData::from_slice(&vd)?;

assert_eq!(vd_p.key(), vd.key());
assert_eq!(vd_p.public_inputs_indexes(), vd.public_inputs_indexes());

// 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")
}?;

// 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(),
];

Ok(TestCircuit::verify(
&pp,
&vd,
&proof,
&public_inputs,
b"Test",
)?)
}

0 comments on commit f856821

Please sign in to comment.