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

Fix tests panic in debug #764

Merged
merged 3 commits into from
Aug 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
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
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed

- Fix panic when creating proof for circuit with different circuit size [#760]
- Fix panic when testing in debug mode [#763]

### Removed

- Remove 'setup' funcion from common test module [#763]

### Changed

- Change range and logic component to be generic over the const `BIT_PAIRS` [#763]

## [0.14.1] - 2022-06-28

Expand Down Expand Up @@ -482,6 +491,7 @@ is necessary since `rkyv/validation` was required as a bound.
- Proof system module.

<!-- ISSUES -->
[#763]: https://github.com/dusk-network/plonk/issues/763
[#760]: https://github.com/dusk-network/plonk/issues/760
[#752]: https://github.com/dusk-network/plonk/pull/752
[#738]: https://github.com/dusk-network/plonk/issues/738
Expand Down
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use rand_core::OsRng;
// Implement a circuit that checks:
// 1) a + b = c where C is a PI
// 2) a < 2^6
// 3) b < 2^5
// 3) b < 2^4
// 4) a * b = d where D is a PI
// 5) JubJub::GENERATOR * e(JubJubScalar) = f where F is a Public Input
#[derive(Debug, Default)]
Expand Down Expand Up @@ -50,8 +50,10 @@ impl Circuit for TestCircuit {
composer.append_gate(constraint);

// Check that a and b are in range
composer.component_range(a, 6);
composer.component_range(b, 5);
const HALF_SIX: usize = 3;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's the reason for that?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The range (and logic) component is now generic over a constant BIT_PAIRS. This was done so that the user has no way to construct an invalid circuit (internally we group the bits in pairs which made circuits over an uneven number of bits invalid).

In the case of the above example, we chose 3 for the generic BIT_PAIRS, which will result in a circuit that checks whether the witness is encoded in 6 bits or less.
To make that connection between 3 and 6 clear I chose the name HALF_SIX.

composer.component_range::<HALF_SIX>(a);
const HALF_FOUR: usize = 2;
composer.component_range::<HALF_FOUR>(b);

// Make second constraint a * b = d
let constraint =
Expand Down
6 changes: 3 additions & 3 deletions benches/plonk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,16 @@ impl<const DEGREE: usize> Circuit for BenchCircuit<DEGREE> {
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.append_logic_and::<128>(w_a, w_b);
composer.append_logic_xor::<128>(w_a, w_b);
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_range::<128>(w_a);
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);
Expand Down
71 changes: 30 additions & 41 deletions src/composer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,33 +105,26 @@ pub trait Composer: Sized + Index<Witness, Output = BlsScalar> {
self.append_custom_gate_internal(constraint)
}

/// Performs a logical AND or XOR op between the inputs provided for the
/// specified number of bits (counting from the least significant bit).
/// Performs a logical AND or XOR op between the inputs provided for
/// `num_bits = BIT_PAIRS * 2` bits (counting from the least significant).
///
/// Each logic gate adds `(num_bits / 2) + 1` gates to the circuit to
/// Each logic gate adds `BIT_PAIRS + 1` gates to the circuit to
/// perform the whole operation.
///
/// ## Constraint
/// - is_component_xor = 1 -> Performs XOR between the first `num_bits` for
/// `a` and `b`.
/// - is_component_xor = 0 -> Performs AND between the first `num_bits` for
/// `a` and `b`.
///
/// # Panics
/// This function will panic if the num_bits specified is not even, ie.
/// `num_bits % 2 != 0`.
fn append_logic_component(
fn append_logic_component<const BIT_PAIRS: usize>(
&mut self,
a: Witness,
b: Witness,
num_bits: usize,
is_component_xor: bool,
) -> Witness {
// the bits are iterated as chunks of two; hence, we require an even
// number
debug_assert_eq!(num_bits & 1, 0);

let num_bits = cmp::min(num_bits, 256);
let num_bits = cmp::min(BIT_PAIRS * 2, 256);
let num_quads = num_bits >> 1;

let bls_four = BlsScalar::from(4u64);
Expand Down Expand Up @@ -272,7 +265,13 @@ pub trait Composer: Sized + Index<Witness, Output = BlsScalar> {
let width = 2;
let wnaf_entries = scalar.compute_windowed_naf(width);

debug_assert_eq!(wnaf_entries.len(), bits);
// this will pass as long as `compute_windowed_naf` returns an array
// with 256 elements
debug_assert_eq!(
wnaf_entries.len(),
bits,
"the wnaf_entries array is expected to be 256 elements long"
);

// initialize the accumulators
let mut scalar_acc = vec![BlsScalar::zero()];
Expand Down Expand Up @@ -581,35 +580,25 @@ pub trait Composer: Sized + Index<Witness, Output = BlsScalar> {
}

/// Adds a logical AND gate that performs the bitwise AND between two values
/// for the specified first `num_bits` returning a [`Witness`]
/// specified first `num_bits = BIT_PAIRS * 2` bits returning a [`Witness`]
/// holding the result.
///
/// # Panics
///
/// If the `num_bits` specified in the fn params is odd.
fn append_logic_and(
fn append_logic_and<const BIT_PAIRS: usize>(
&mut self,
a: Witness,
b: Witness,
num_bits: usize,
) -> Witness {
self.append_logic_component(a, b, num_bits, false)
self.append_logic_component::<BIT_PAIRS>(a, b, false)
}

/// Adds a logical XOR gate that performs the XOR between two values for the
/// specified first `num_bits` returning a [`Witness`] holding the
/// result.
///
/// # Panics
///
/// If the `num_bits` specified in the fn params is odd.
fn append_logic_xor(
/// specified first `num_bits = BIT_PAIRS * 2` bits returning a [`Witness`]
/// holding the result.
fn append_logic_xor<const BIT_PAIRS: usize>(
&mut self,
a: Witness,
b: Witness,
num_bits: usize,
) -> Witness {
self.append_logic_component(a, b, num_bits, true)
self.append_logic_component::<BIT_PAIRS>(a, b, true)
}

/// Constrain `a` to be equal to `constant + pi`.
Expand Down Expand Up @@ -913,18 +902,18 @@ pub trait Composer: Sized + Index<Witness, Output = BlsScalar> {
}

/// Adds a range-constraint gate that checks and constrains a [`Witness`]
/// to be encoded in at most `num_bits`, which means that it will be within
/// the range `[0, 2^num_bits[`.
///
/// This function adds min(1, `num_bits/4`) gates to the circuit description
/// in order to add the range constraint.
/// to be encoded in at most `num_bits = BIT_PAIRS * 2` bits, which means
/// that the underlying [`BlsScalar`] of the [`Witness`] will be within the
/// range `[0, 2^num_bits[`, where `num_bits` is dividable by two.
///
///# Panics
/// This function will panic if the num_bits specified is not even, ie.
/// `num_bits % 2 != 0`.
fn component_range(&mut self, witness: Witness, num_bits: usize) {
// number of bits must be even
debug_assert_eq!(num_bits % 2, 0);
/// This function adds:
/// (num_bits - 1)/8 + 9 gates, when num_bits > 0,
/// and 7 gates, when num_bits = 0
/// to the circuit description.
fn component_range<const BIT_PAIRS: usize>(&mut self, witness: Witness) {
// the bits are iterated as chunks of two; hence, we require an even
// number
let num_bits = cmp::min(BIT_PAIRS * 2, 256);

// if num_bits = 0 constrain witness to 0
if num_bits == 0 {
Expand Down
Loading
Loading