diff --git a/contrib/zk.lua b/contrib/zk.lua index b25829b23..4fa4a0cd0 100644 --- a/contrib/zk.lua +++ b/contrib/zk.lua @@ -43,7 +43,8 @@ local instruction = token('instruction', word_match{ 'ec_get_x', 'ec_get_y', 'base_add', 'base_mul', 'base_sub', 'greater_than', 'poseidon_hash', 'merkle_root', 'constrain_instance', - 'range_check', 'less_than', 'witness_base', + 'range_check', 'less_than', 'bool_check', + 'witness_base', }) -- Identifiers. diff --git a/contrib/zk.vim b/contrib/zk.vim index 53a86931f..bc9ba520e 100644 --- a/contrib/zk.vim +++ b/contrib/zk.vim @@ -23,7 +23,7 @@ syn keyword zkasInstruction \ ec_get_x ec_get_y \ base_add base_mul base_sub \ poseidon_hash merkle_root constrain_instance - \ range_check less_than witness_base + \ range_check less_than bool_check witness_base syn region zkasString start='"' end='"' contained diff --git a/proof/opcodes.zk b/proof/opcodes.zk index 84ff65b26..d9a87f84a 100644 --- a/proof/opcodes.zk +++ b/proof/opcodes.zk @@ -45,4 +45,6 @@ circuit "Opcodes" { public = ec_mul_base(secret, NULLIFIER_K); constrain_instance(ec_get_x(public)); constrain_instance(ec_get_y(public)); + + bool_check(one); } diff --git a/src/zk/vm.rs b/src/zk/vm.rs index fb367520d..f5497a479 100644 --- a/src/zk/vm.rs +++ b/src/zk/vm.rs @@ -31,6 +31,7 @@ use super::{ arithmetic::{ArithChip, ArithConfig, ArithInstruction}, less_than::{LessThanChip, LessThanConfig}, native_range_check::{NativeRangeCheckChip, NativeRangeCheckConfig}, + small_range_check::{SmallRangeCheckChip, SmallRangeCheckConfig}, }, }; use crate::{ @@ -59,6 +60,7 @@ pub struct VmConfig { native_64_range_check_config: NativeRangeCheckConfig<3, 64, 22>, native_253_range_check_config: NativeRangeCheckConfig<3, 253, 85>, lessthan_config: LessThanConfig<3, 253, 85>, + boolcheck_config: SmallRangeCheckConfig, } impl VmConfig { @@ -232,6 +234,10 @@ impl Circuit for ZkCircuit { k_values_table_253, ); + // Configuration for boolean checks, it uses the small_range_check + // chip with a range of 2, which enforces one bit, i.e. 0 or 1. + let boolcheck_config = SmallRangeCheckChip::configure(meta, advices[9], 2); + VmConfig { primary, advices, @@ -245,6 +251,7 @@ impl Circuit for ZkCircuit { native_64_range_check_config, native_253_range_check_config, lessthan_config, + boolcheck_config, } } @@ -300,6 +307,9 @@ impl Circuit for ZkCircuit { // Construct the Arithmetic chip. let arith_chip = config.arithmetic_chip(); + // Construct the boolean check chip. + let boolcheck_chip = SmallRangeCheckChip::construct(config.boolcheck_config.clone()); + // ========================== // Constants setup // ========================== @@ -697,6 +707,16 @@ impl Circuit for ZkCircuit { )?; } + Opcode::BoolCheck => { + debug!("Executing `BoolCheck{:?}` opcode", opcode.1); + let args = &opcode.1; + + let w = stack[args[0].1].clone().into(); + + boolcheck_chip + .small_range_check(layouter.namespace(|| "copy boolean check"), w)?; + } + Opcode::ConstrainInstance => { debug!("Executing `ConstrainInstance{:?}` opcode", opcode.1); let args = &opcode.1; diff --git a/src/zkas/opcode.rs b/src/zkas/opcode.rs index 3ab8fa10f..c72436f12 100644 --- a/src/zkas/opcode.rs +++ b/src/zkas/opcode.rs @@ -49,6 +49,9 @@ pub enum Opcode { /// Compare two Base field elements and see if a is less than b LessThan = 0x51, + /// Check if a field element fits in a boolean (Either 0 or 1) + BoolCheck = 0x52, + /// Constrain a Base field element to a circuit's public input ConstrainInstance = 0xf0, @@ -73,6 +76,7 @@ impl Opcode { "witness_base" => Some(Self::WitnessBase), "range_check" => Some(Self::RangeCheck), "less_than" => Some(Self::LessThan), + "bool_check" => Some(Self::BoolCheck), "constrain_instance" => Some(Self::ConstrainInstance), "debug" => Some(Self::DebugPrint), _ => None, @@ -95,6 +99,7 @@ impl Opcode { 0x40 => Some(Self::WitnessBase), 0x50 => Some(Self::RangeCheck), 0x51 => Some(Self::LessThan), + 0x52 => Some(Self::BoolCheck), 0xf0 => Some(Self::ConstrainInstance), 0xff => Some(Self::DebugPrint), _ => None, @@ -141,6 +146,8 @@ impl Opcode { Opcode::LessThan => (vec![], vec![VarType::Base, VarType::Base]), + Opcode::BoolCheck => (vec![], vec![VarType::Base]), + Opcode::ConstrainInstance => (vec![], vec![VarType::Base]), Opcode::DebugPrint => (vec![], vec![]),