Skip to content

Commit

Permalink
Introduce BoolVar struct (#94)
Browse files Browse the repository at this point in the history
* update nix and rust

* introduce BoolVar, first pass

* update more APIs

* use true_var() and false_var() instead

* update CHANGELOG

* address comments
  • Loading branch information
alxiong authored Aug 9, 2022
1 parent 682bba7 commit 918d038
Show file tree
Hide file tree
Showing 13 changed files with 280 additions and 337 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
- Refactored `UniversalSNARK` trait (#80, #87)
- Restore `no_std` compliance (#85, #87)
- Use [blst](https://github.com/supranational/blst) library for BLS signature/VRF (#89)
- Introduce `struct BoolVar` whenever necessary and possible (#91)

## v0.1.2

Expand Down
4 changes: 2 additions & 2 deletions nix/nixpkgs.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"url": "https://github.com/nixos/nixpkgs/archive/db8ab32efd3a4ad59044848d889480954e458f25.tar.gz",
"sha256": "1i7ayivjm3rx62qq263jjj55m0nzhn4b99wax25kw6a8zhhwcwjb"
"url": "https://github.com/nixos/nixpkgs/archive/6f38b43c8c84c800f93465b2241156419fd4fd52.tar.gz",
"sha256": "0xw3y3jx1bcnwsc0imacbp5m8f51b66s9h8kk8qnfbckwv67dhgd"
}
6 changes: 3 additions & 3 deletions nix/oxalica_rust_overlay.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "9d7c777625640b70a4d211f62711fa316bca7176",
"sha256": "025bw59nl12jqf4nrvbn0a8xn03aj9bz54nvf1rb25zl2l1nkrnd",
"rev": "53f8467a9ef7a49c8729b28660bb83d1a75da508",
"sha256": "aeno3vAJm5ReC2ZCOQoZHDoNsBsqM64HgSWgqhzF6yk=",
"fetchSubmodules": true
}
}
31 changes: 13 additions & 18 deletions plonk/src/circuit/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// along with the Jellyfish library. If not, see <https://mit-license.org/>.

//! Basic instantiations of Plonk-based constraint systems
use super::{Arithmetization, Circuit, GateId, Variable, WireId};
use super::{Arithmetization, BoolVar, Circuit, GateId, Variable, WireId};
use crate::{
circuit::{gates::*, SortedLookupVecAndPolys},
constants::{compute_coset_representatives, GATE_WIDTH, N_MUL_SELECTORS},
Expand Down Expand Up @@ -264,6 +264,18 @@ impl<F: FftField> PlonkCircuit<F> {
pub fn range_size(&self) -> Result<usize, PlonkError> {
Ok(1 << self.range_bit_len()?)
}

/// creating a `BoolVar` without checking if `v` is a boolean value!
/// You should absolutely sure about what you are doing.
/// You should normally only use this API if you already enforce `v` to be a
/// boolean value using other constraints.
pub(crate) fn create_boolean_variable_unchecked(
&mut self,
a: F,
) -> Result<BoolVar, PlonkError> {
let var = self.create_variable(a)?;
Ok(BoolVar::new_unchecked(var))
}
}

impl<F: FftField> Circuit<F> for PlonkCircuit<F> {
Expand Down Expand Up @@ -715,23 +727,6 @@ impl<F: FftField> PlonkCircuit<F> {
Ok(())
}

// Check whether the variable `var` is a boolean value
// this is used to return error to invalid parameter early in the circuit
// building development lifecycle, it should NOT be used as a circuit constraint
// for which you should use bool_gate() instead
#[inline]
pub(crate) fn check_bool(&self, var: Variable) -> Result<(), PlonkError> {
let val = self.witness(var)?;
if val != F::zero() && val != F::one() {
Err(ParameterError(
"Expecting a boolean value, something is wrong with your circuit logic".to_string(),
)
.into())
} else {
Ok(())
}
}

// Return the variable that maps to a wire `(i, j)` where i is the wire type and
// j is the gate index. If gate `j` is a padded dummy gate, return zero
// variable.
Expand Down
35 changes: 15 additions & 20 deletions plonk/src/circuit/customized/ecc/glv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use crate::{
circuit::{
customized::ecc::{MultiScalarMultiplicationCircuit, PointVariable},
Circuit, PlonkCircuit, Variable,
BoolVar, Circuit, PlonkCircuit, Variable,
},
errors::PlonkError,
};
Expand Down Expand Up @@ -93,17 +93,10 @@ where
self.check_var_bound(scalar)?;
self.check_point_var_bound(base)?;

let k_vars = scalar_decomposition_gate::<_, P, _>(self, &scalar)?;
let (s1_var, s2_var, s2_sign_var) = scalar_decomposition_gate::<_, P, _>(self, &scalar)?;

let endo_base_var = endomorphism_circuit::<_, P>(self, base)?;
multi_scalar_mul_circuit::<_, P>(
self,
base,
k_vars[0],
&endo_base_var,
k_vars[1],
k_vars[2],
)
multi_scalar_mul_circuit::<_, P>(self, base, s1_var, &endo_base_var, s2_var, s2_sign_var)
}
}

Expand All @@ -114,7 +107,7 @@ fn multi_scalar_mul_circuit<F, P>(
scalar_1: Variable,
endo_base: &PointVariable,
scalar_2: Variable,
scalar_2_sign_var: Variable,
scalar_2_sign_var: BoolVar,
) -> Result<PointVariable, PlonkError>
where
F: PrimeField,
Expand Down Expand Up @@ -273,7 +266,7 @@ macro_rules! int_to_fq {
fn scalar_decomposition_gate<F, P, S>(
circuit: &mut PlonkCircuit<F>,
s_var: &Variable,
) -> Result<([Variable; 3]), PlonkError>
) -> Result<(Variable, Variable, BoolVar), PlonkError>
where
F: PrimeField,
P: TEModelParameters<BaseField = F, ScalarField = S> + Clone,
Expand Down Expand Up @@ -466,7 +459,7 @@ where

let k1_var = circuit.create_variable(int_to_fq!(k1_int))?;
let k2_var = circuit.create_variable(int_to_fq!(k2_int))?;
let k2_sign_var = circuit.create_bool_variable(is_k2_positive)?;
let k2_sign_var = circuit.create_boolean_variable(is_k2_positive)?;

let t_var = circuit.create_variable(int_to_fq!(t_int))?;

Expand Down Expand Up @@ -521,7 +514,8 @@ where
};

// (f.3) either f.1 or f.2 is satisfied
let sat = circuit.conditional_select(k2_sign_var, k2_is_neg_sat, k2_is_pos_sat)?;
let sat =
circuit.conditional_select(k2_sign_var, k2_is_neg_sat.into(), k2_is_pos_sat.into())?;
circuit.enforce_true(sat)?;

// (g) tmp2 + lambda_2 * k2_sign * k2 + s2 = t * t_sign * r2
Expand Down Expand Up @@ -551,11 +545,12 @@ where
};

// (g.3) either g.1 or g.2 is satisfied
let sat = circuit.conditional_select(k2_sign_var, k2_is_neg_sat, k2_is_pos_sat)?;
let sat =
circuit.conditional_select(k2_sign_var, k2_is_neg_sat.into(), k2_is_pos_sat.into())?;
circuit.enforce_true(sat)?;

// extract the output
Ok([k1_var, k2_var, k2_sign_var])
Ok((k1_var, k2_var, k2_sign_var))
}

#[cfg(test)]
Expand Down Expand Up @@ -702,15 +697,15 @@ mod tests {

let mut circuit: PlonkCircuit<Fq> = PlonkCircuit::new_ultra_plonk(16);
let scalar_var = circuit.create_variable(field_switching(&scalar)).unwrap();
let res =
let (k1_var, k2_var, k2_sign_var) =
scalar_decomposition_gate::<_, EdwardsParameters, _>(&mut circuit, &scalar_var)
.unwrap();

let k1_rec = circuit.witness(res[0]).unwrap();
let k1_rec = circuit.witness(k1_var).unwrap();
assert_eq!(field_switching::<_, Fq>(&k1), k1_rec);

let k2_rec = circuit.witness(res[1]).unwrap();
let k2_sign = circuit.witness(res[2]).unwrap();
let k2_rec = circuit.witness(k2_var).unwrap();
let k2_sign = circuit.witness(k2_sign_var.into()).unwrap();
let k2_with_sign_rec = if k2_sign == Fq::one() {
field_switching::<_, Fr>(&k2_rec)
} else {
Expand Down
Loading

0 comments on commit 918d038

Please sign in to comment.