From a20b5a4f6dfb5c67988456bf92d8006443f5635d Mon Sep 17 00:00:00 2001 From: bibbinth Date: Sat, 22 Aug 2020 23:48:31 -0700 Subject: [PATCH 1/4] Incremented version to 0.6 --- Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3d69c75..b803091 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "distaff" -version = "0.5.1" +version = "0.6.0" authors = ["Bobbin Threadbare "] edition = "2018" description="Zero-knowledge virtual machine written in Rust" @@ -19,11 +19,11 @@ harness = false [dependencies] hex = "0.4.2" rand = "0.7.3" -blake3 = "0.3.5" +blake3 = "0.3.6" sha3 = "0.8.2" crossbeam-utils = "0.7.2" bincode = "1.3.1" -serde = { version = "1.0.114", features = ["derive"] } +serde = { version = "1.0.115", features = ["derive"] } log = "0.4.11" env_logger = "0.7.1" From 395608a6678ae60edd9dea4be0453e209f60ffcc Mon Sep 17 00:00:00 2001 From: bibbinth Date: Mon, 7 Sep 2020 11:17:33 -0700 Subject: [PATCH 2/4] refactored op flag retrieval from trace state --- src/stark/constraints/decoder/mod.rs | 38 ++++---- src/stark/constraints/decoder/op_bits.rs | 24 ++--- src/stark/constraints/decoder/sponge.rs | 2 +- src/stark/constraints/stack/mod.rs | 69 +++++++------- src/stark/trace/trace_state.rs | 114 ++++------------------- 5 files changed, 81 insertions(+), 166 deletions(-) diff --git a/src/stark/constraints/decoder/mod.rs b/src/stark/constraints/decoder/mod.rs index 92ee978..52507af 100644 --- a/src/stark/constraints/decoder/mod.rs +++ b/src/stark/constraints/decoder/mod.rs @@ -137,16 +137,15 @@ impl Decoder { // evaluate constraints for flow control operations let result = &mut result[NUM_OP_CONSTRAINTS..]; - let op_flags = current.cf_op_flags(); - - enforce_hacc (result, current, next, &ark, op_flags[FlowOps::Hacc.op_index() ]); - enforce_begin(result, current, next, op_flags[FlowOps::Begin.op_index()]); - enforce_tend (result, current, next, op_flags[FlowOps::Tend.op_index() ]); - enforce_fend (result, current, next, op_flags[FlowOps::Fend.op_index() ]); - enforce_loop (result, current, next, op_flags[FlowOps::Loop.op_index() ]); - enforce_wrap (result, current, next, op_flags[FlowOps::Wrap.op_index() ]); - enforce_break(result, current, next, op_flags[FlowOps::Break.op_index()]); - enforce_void (result, current, next, op_flags[FlowOps::Void.op_index() ]); + + enforce_hacc (result, current, next, &ark, current.get_flow_op_flags(FlowOps::Hacc)); + enforce_begin(result, current, next, current.get_flow_op_flags(FlowOps::Begin)); + enforce_tend (result, current, next, current.get_flow_op_flags(FlowOps::Tend)); + enforce_fend (result, current, next, current.get_flow_op_flags(FlowOps::Fend)); + enforce_loop (result, current, next, current.get_flow_op_flags(FlowOps::Loop)); + enforce_wrap (result, current, next, current.get_flow_op_flags(FlowOps::Wrap)); + enforce_break(result, current, next, current.get_flow_op_flags(FlowOps::Break)); + enforce_void (result, current, next, current.get_flow_op_flags(FlowOps::Void)); } /// Evaluates decoder transition constraints at the specified x coordinate and saves the @@ -175,16 +174,15 @@ impl Decoder { // evaluate constraints for flow control operations let result = &mut result[NUM_OP_CONSTRAINTS..]; - let op_flags = current.cf_op_flags(); - - enforce_hacc (result, current, next, &ark, op_flags[FlowOps::Hacc as usize]); - enforce_begin(result, current, next, op_flags[FlowOps::Begin as usize]); - enforce_tend (result, current, next, op_flags[FlowOps::Tend as usize]); - enforce_fend (result, current, next, op_flags[FlowOps::Fend as usize]); - enforce_loop (result, current, next, op_flags[FlowOps::Loop as usize]); - enforce_wrap (result, current, next, op_flags[FlowOps::Wrap as usize]); - enforce_break(result, current, next, op_flags[FlowOps::Break as usize]); - enforce_void (result, current, next, op_flags[FlowOps::Void as usize]); + + enforce_hacc (result, current, next, &ark, current.get_flow_op_flags(FlowOps::Hacc)); + enforce_begin(result, current, next, current.get_flow_op_flags(FlowOps::Begin)); + enforce_tend (result, current, next, current.get_flow_op_flags(FlowOps::Tend)); + enforce_fend (result, current, next, current.get_flow_op_flags(FlowOps::Fend)); + enforce_loop (result, current, next, current.get_flow_op_flags(FlowOps::Loop)); + enforce_wrap (result, current, next, current.get_flow_op_flags(FlowOps::Wrap)); + enforce_break(result, current, next, current.get_flow_op_flags(FlowOps::Break)); + enforce_void (result, current, next, current.get_flow_op_flags(FlowOps::Void)); } } diff --git a/src/stark/constraints/decoder/op_bits.rs b/src/stark/constraints/decoder/op_bits.rs index e14a809..eac4884 100644 --- a/src/stark/constraints/decoder/op_bits.rs +++ b/src/stark/constraints/decoder/op_bits.rs @@ -36,7 +36,7 @@ pub fn enforce_op_bits(result: &mut [u128], current: &TraceState, next: &TraceSt // when cf_ops = hacc, operation counter should be incremented by 1; // otherwise, operation counter should remain the same let op_counter = current.op_counter(); - let is_hacc = current.cf_op_flags()[FlowOps::Hacc.op_index()]; + let is_hacc = current.get_flow_op_flags(FlowOps::Hacc); let hacc_transition = mul(add(op_counter, field::ONE), is_hacc); let rest_transition = mul(op_counter, binary_not(is_hacc)); result[i] = are_equal(add(hacc_transition, rest_transition), next.op_counter()); @@ -51,31 +51,27 @@ pub fn enforce_op_bits(result: &mut [u128], current: &TraceState, next: &TraceSt result[i] = mul(cf_bit_sum, binary_not(mul(ld_bit_prod, hd_bit_prod))); i += 1; - let cf_op_flags = current.cf_op_flags(); - // VOID can be followed only by VOID - let current_void_flag = cf_op_flags[FlowOps::Void.op_index()]; - let next_void_flag = next.cf_op_flags()[FlowOps::Void.op_index()]; + let current_void_flag = current.get_flow_op_flags(FlowOps::Void); + let next_void_flag = next.get_flow_op_flags(FlowOps::Void); result[i] = mul(current_void_flag, binary_not(next_void_flag)); i += 1; - let hd_op_flags = current.hd_op_flags(); - // BEGIN, LOOP, BREAK, and WRAP are allowed only on one less than multiple of 16 let prefix_mask = masks[PREFIX_MASK_IDX]; - result.agg_constraint(i, cf_op_flags[FlowOps::Begin.op_index()], prefix_mask); - result.agg_constraint(i, cf_op_flags[FlowOps::Loop.op_index()], prefix_mask); - result.agg_constraint(i, cf_op_flags[FlowOps::Wrap.op_index()], prefix_mask); - result.agg_constraint(i, cf_op_flags[FlowOps::Break.op_index()], prefix_mask); + result.agg_constraint(i, current.get_flow_op_flags(FlowOps::Begin), prefix_mask); + result.agg_constraint(i, current.get_flow_op_flags(FlowOps::Loop), prefix_mask); + result.agg_constraint(i, current.get_flow_op_flags(FlowOps::Wrap), prefix_mask); + result.agg_constraint(i, current.get_flow_op_flags(FlowOps::Break), prefix_mask); // TEND and FEND is allowed only on multiples of 16 let base_cycle_mask = masks[CYCLE_MASK_IDX]; - result.agg_constraint(i, cf_op_flags[FlowOps::Tend.op_index()], base_cycle_mask); - result.agg_constraint(i, cf_op_flags[FlowOps::Fend.op_index()], base_cycle_mask); + result.agg_constraint(i, current.get_flow_op_flags(FlowOps::Tend), base_cycle_mask); + result.agg_constraint(i, current.get_flow_op_flags(FlowOps::Fend), base_cycle_mask); // PUSH is allowed only on multiples of 8 let push_cycle_mask = masks[PUSH_MASK_IDX]; - result.agg_constraint(i, hd_op_flags[UserOps::Push.hd_index()], push_cycle_mask); + result.agg_constraint(i, current.get_user_op_flag(UserOps::Push), push_cycle_mask); } // TESTS diff --git a/src/stark/constraints/decoder/sponge.rs b/src/stark/constraints/decoder/sponge.rs index 3cad0c8..2840fe0 100644 --- a/src/stark/constraints/decoder/sponge.rs +++ b/src/stark/constraints/decoder/sponge.rs @@ -11,7 +11,7 @@ pub fn enforce_hacc(result: &mut [u128], current: &TraceState, next: &TraceState { // determine current op_value let stack_top = next.user_stack()[0]; - let push_flag = current.hd_op_flags()[UserOps::Push.hd_index()]; + let push_flag = current.get_user_op_flag(UserOps::Push); let op_value = mul(stack_top, push_flag); // evaluate the first half of Rescue round diff --git a/src/stark/constraints/stack/mod.rs b/src/stark/constraints/stack/mod.rs index ced6cd8..29ea252 100644 --- a/src/stark/constraints/stack/mod.rs +++ b/src/stark/constraints/stack/mod.rs @@ -129,56 +129,53 @@ fn enforce_constraints(current: &TraceState, next: &TraceState, ark: &[u128], re let mut evaluations = vec![field::ZERO; old_stack.len()]; // 1 ----- enforce constraints for low-degree operations -------------------------------------- - let ld_flags = current.ld_op_flags(); - + // assertion operations - enforce_assert (&mut evaluations, aux, old_stack, new_stack, ld_flags[OpCode::Assert.ld_index()]); - enforce_asserteq(&mut evaluations, aux, old_stack, new_stack, ld_flags[OpCode::AssertEq.ld_index()]); + enforce_assert (&mut evaluations, aux, old_stack, new_stack, current.get_user_op_flag(OpCode::Assert)); + enforce_asserteq(&mut evaluations, aux, old_stack, new_stack, current.get_user_op_flag(OpCode::AssertEq)); // input operations - enforce_read (&mut evaluations, old_stack, new_stack, ld_flags[OpCode::Read.ld_index()]); - enforce_read2 (&mut evaluations, old_stack, new_stack, ld_flags[OpCode::Read2.ld_index()]); + enforce_read (&mut evaluations, old_stack, new_stack, current.get_user_op_flag(OpCode::Read)); + enforce_read2 (&mut evaluations, old_stack, new_stack, current.get_user_op_flag(OpCode::Read2)); // stack manipulation operations - enforce_dup (&mut evaluations, old_stack, new_stack, ld_flags[OpCode::Dup.ld_index()]); - enforce_dup2 (&mut evaluations, old_stack, new_stack, ld_flags[OpCode::Dup2.ld_index()]); - enforce_dup4 (&mut evaluations, old_stack, new_stack, ld_flags[OpCode::Dup4.ld_index()]); - enforce_pad2 (&mut evaluations, old_stack, new_stack, ld_flags[OpCode::Pad2.ld_index()]); + enforce_dup (&mut evaluations, old_stack, new_stack, current.get_user_op_flag(OpCode::Dup)); + enforce_dup2 (&mut evaluations, old_stack, new_stack, current.get_user_op_flag(OpCode::Dup2)); + enforce_dup4 (&mut evaluations, old_stack, new_stack, current.get_user_op_flag(OpCode::Dup4)); + enforce_pad2 (&mut evaluations, old_stack, new_stack, current.get_user_op_flag(OpCode::Pad2)); - enforce_drop (&mut evaluations, old_stack, new_stack, ld_flags[OpCode::Drop.ld_index()]); - enforce_drop4 (&mut evaluations, old_stack, new_stack, ld_flags[OpCode::Drop4.ld_index()]); + enforce_drop (&mut evaluations, old_stack, new_stack, current.get_user_op_flag(OpCode::Drop)); + enforce_drop4 (&mut evaluations, old_stack, new_stack, current.get_user_op_flag(OpCode::Drop4)); - enforce_swap (&mut evaluations, old_stack, new_stack, ld_flags[OpCode::Swap.ld_index()]); - enforce_swap2 (&mut evaluations, old_stack, new_stack, ld_flags[OpCode::Swap2.ld_index()]); - enforce_swap4 (&mut evaluations, old_stack, new_stack, ld_flags[OpCode::Swap4.ld_index()]); + enforce_swap (&mut evaluations, old_stack, new_stack, current.get_user_op_flag(OpCode::Swap)); + enforce_swap2 (&mut evaluations, old_stack, new_stack, current.get_user_op_flag(OpCode::Swap2)); + enforce_swap4 (&mut evaluations, old_stack, new_stack, current.get_user_op_flag(OpCode::Swap4)); - enforce_roll4 (&mut evaluations, old_stack, new_stack, ld_flags[OpCode::Roll4.ld_index()]); - enforce_roll8 (&mut evaluations, old_stack, new_stack, ld_flags[OpCode::Roll8.ld_index()]); + enforce_roll4 (&mut evaluations, old_stack, new_stack, current.get_user_op_flag(OpCode::Roll4)); + enforce_roll8 (&mut evaluations, old_stack, new_stack, current.get_user_op_flag(OpCode::Roll8)); // arithmetic and boolean operations - enforce_add (&mut evaluations, old_stack, new_stack, ld_flags[OpCode::Add.ld_index()]); - enforce_mul (&mut evaluations, old_stack, new_stack, ld_flags[OpCode::Mul.ld_index()]); - enforce_inv (&mut evaluations, old_stack, new_stack, ld_flags[OpCode::Inv.ld_index()]); - enforce_neg (&mut evaluations, old_stack, new_stack, ld_flags[OpCode::Neg.ld_index()]); - enforce_not (&mut evaluations, aux, old_stack, new_stack, ld_flags[OpCode::Not.ld_index()]); - enforce_and (&mut evaluations, aux, old_stack, new_stack, ld_flags[OpCode::And.ld_index()]); - enforce_or (&mut evaluations, aux, old_stack, new_stack, ld_flags[OpCode::Or.ld_index()]); + enforce_add (&mut evaluations, old_stack, new_stack, current.get_user_op_flag(OpCode::Add)); + enforce_mul (&mut evaluations, old_stack, new_stack, current.get_user_op_flag(OpCode::Mul)); + enforce_inv (&mut evaluations, old_stack, new_stack, current.get_user_op_flag(OpCode::Inv)); + enforce_neg (&mut evaluations, old_stack, new_stack, current.get_user_op_flag(OpCode::Neg)); + enforce_not (&mut evaluations, aux, old_stack, new_stack, current.get_user_op_flag(OpCode::Not)); + enforce_and (&mut evaluations, aux, old_stack, new_stack, current.get_user_op_flag(OpCode::And)); + enforce_or (&mut evaluations, aux, old_stack, new_stack, current.get_user_op_flag(OpCode::Or)); // comparison operations - enforce_eq (&mut evaluations, aux, old_stack, new_stack, ld_flags[OpCode::Eq.ld_index()]); - enforce_binacc (&mut evaluations, old_stack, new_stack, ld_flags[OpCode::BinAcc.ld_index()]); + enforce_eq (&mut evaluations, aux, old_stack, new_stack, current.get_user_op_flag(OpCode::Eq)); + enforce_binacc (&mut evaluations, old_stack, new_stack, current.get_user_op_flag(OpCode::BinAcc)); // conditional selection operations - enforce_choose (&mut evaluations, aux, old_stack, new_stack, ld_flags[OpCode::Choose.ld_index()]); - enforce_choose2 (&mut evaluations, aux, old_stack, new_stack, ld_flags[OpCode::Choose2.ld_index()]); - enforce_cswap2 (&mut evaluations, aux, old_stack, new_stack, ld_flags[OpCode::CSwap2.ld_index()]); + enforce_choose (&mut evaluations, aux, old_stack, new_stack, current.get_user_op_flag(OpCode::Choose)); + enforce_choose2 (&mut evaluations, aux, old_stack, new_stack, current.get_user_op_flag(OpCode::Choose2)); + enforce_cswap2 (&mut evaluations, aux, old_stack, new_stack, current.get_user_op_flag(OpCode::CSwap2)); // 2 ----- enforce constraints for high-degree operations -------------------------------------- - let hd_flags = current.hd_op_flags(); - - enforce_push (&mut evaluations, old_stack, new_stack, hd_flags[OpCode::Push.hd_index() ]); - enforce_cmp (&mut evaluations, old_stack, new_stack, hd_flags[OpCode::Cmp.hd_index() ]); - enforce_rescr (&mut evaluations, old_stack, new_stack, ark, hd_flags[OpCode::RescR.hd_index()]); + enforce_push (&mut evaluations, old_stack, new_stack, current.get_user_op_flag(OpCode::Push)); + enforce_cmp (&mut evaluations, old_stack, new_stack, current.get_user_op_flag(OpCode::Cmp)); + enforce_rescr (&mut evaluations, old_stack, new_stack, ark, current.get_user_op_flag(OpCode::RescR)); // 3 ----- enforce constraints for composite operations --------------------------------------- @@ -187,8 +184,8 @@ fn enforce_constraints(current: &TraceState, next: &TraceState, ark: &[u128], re // this results in flag degree of 7 for each operation, but since both operations enforce the // same constraints (the stack doesn't change), higher degree terms cancel out, and we // end up with overall constraint degree of (6 + 1 = 7) for both operations. - enforce_stack_copy(&mut evaluations, old_stack, new_stack, 0, current.begin_flag()); - enforce_stack_copy(&mut evaluations, old_stack, new_stack, 0, current.noop_flag()); + enforce_stack_copy(&mut evaluations, old_stack, new_stack, 0, current.get_user_op_flag(OpCode::Begin)); + enforce_stack_copy(&mut evaluations, old_stack, new_stack, 0, current.get_user_op_flag(OpCode::Noop)); // 4 ----- copy evaluations into the result --------------------------------------------------- result.copy_from_slice(&evaluations[..result.len()]); diff --git a/src/stark/trace/trace_state.rs b/src/stark/trace/trace_state.rs index ef41d43..ffb9b8e 100644 --- a/src/stark/trace/trace_state.rs +++ b/src/stark/trace/trace_state.rs @@ -8,8 +8,10 @@ use crate::{ NUM_CF_OPS, NUM_LD_OPS, NUM_HD_OPS, NUM_CF_OP_BITS, NUM_LD_OP_BITS, NUM_HD_OP_BITS, CF_OP_BITS_RANGE, LD_OP_BITS_RANGE, HD_OP_BITS_RANGE, + processor::opcodes::{ FlowOps, UserOps } }; + // CONSTANTS // ================================================================================================ const NUM_OP_BITS: usize = NUM_CF_OP_BITS + NUM_LD_OP_BITS + NUM_HD_OP_BITS; @@ -37,7 +39,6 @@ pub struct TraceState { hd_op_flags : [u128; NUM_HD_OPS], begin_flag : u128, noop_flag : u128, - op_flags_set: bool, } // TRACE STATE IMPLEMENTATION @@ -66,7 +67,6 @@ impl TraceState { hd_op_flags : [0; NUM_HD_OPS], begin_flag : 0, noop_flag : 0, - op_flags_set: false, }; } @@ -97,7 +97,7 @@ impl TraceState { let mut user_stack = vec![0; cmp::max(stack_depth, MIN_STACK_DEPTH)]; user_stack[..stack_depth].copy_from_slice(&state[loop_stack_end..]); - return TraceState { + let mut state = TraceState { op_counter, sponge, cf_op_bits, ld_op_bits, hd_op_bits, ctx_stack, loop_stack, user_stack, @@ -107,8 +107,10 @@ impl TraceState { hd_op_flags : [0; NUM_HD_OPS], begin_flag : 0, noop_flag : 0, - op_flags_set: false, }; + state.set_op_flags(); + + return state; } // STATIC FUNCTIONS @@ -177,46 +179,24 @@ impl TraceState { self.cf_op_bits.copy_from_slice(&bits[..3]); self.ld_op_bits.copy_from_slice(&bits[3..8]); self.hd_op_bits.copy_from_slice(&bits[8..]); + self.set_op_flags(); } // OP FLAGS // -------------------------------------------------------------------------------------------- - pub fn cf_op_flags(&self) -> [u128; NUM_CF_OPS] { - if !self.op_flags_set { - unsafe { - let mutable_self = &mut *(self as *const _ as *mut TraceState); - mutable_self.set_op_flags(); - } - } - return self.cf_op_flags; + pub fn get_flow_op_flags(&self, opcode: FlowOps) -> u128 { + return self.cf_op_flags[opcode.op_index()]; } - pub fn ld_op_flags(&self) -> [u128; NUM_LD_OPS] { - if !self.op_flags_set { - unsafe { - let mutable_self = &mut *(self as *const _ as *mut TraceState); - mutable_self.set_op_flags(); - } - } - return self.ld_op_flags; - } + pub fn get_user_op_flag(&self, opcode: UserOps) -> u128 { + return match opcode { - pub fn hd_op_flags(&self) -> [u128; NUM_HD_OPS] { - if !self.op_flags_set { - unsafe { - let mutable_self = &mut *(self as *const _ as *mut TraceState); - mutable_self.set_op_flags(); - } - } - return self.hd_op_flags; - } + UserOps::Begin => self.begin_flag, + UserOps::Noop => self.noop_flag, + UserOps::Push | UserOps::Cmp | UserOps::RescR => self.hd_op_flags[opcode.hd_index()], - pub fn begin_flag(&self) -> u128 { - return self.begin_flag; - } - - pub fn noop_flag(&self) -> u128 { - return self.noop_flag; + _ => self.ld_op_flags[opcode.ld_index()], + }; } // STACKS @@ -273,7 +253,7 @@ impl TraceState { self.user_stack[i] = trace[j][step]; } - self.op_flags_set = false; + self.set_op_flags(); } // HELPER METHODS @@ -344,9 +324,6 @@ impl TraceState { debug_assert!(OpCode::Assert.ld_index() == 0, "ASSERT index is not 0!"); self.ld_op_flags[0] = field::mul(self.ld_op_flags[0], self.hd_op_bits[0]); - - // mark flags as set - self.op_flags_set = true; } } @@ -499,62 +476,9 @@ mod tests { #[test] fn op_flags() { - - // all zeros - let state = TraceState::from_vec(1, 0, 2, &vec![ - 101, 1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 16, 17 - ]); - - assert_eq!([1, 0, 0, 0, 0, 0, 0, 0], state.cf_op_flags()); - assert_eq!([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ], state.ld_op_flags()); - assert_eq!([0, 0, 0, 0], state.hd_op_flags()); - assert_eq!(1, state.begin_flag()); - assert_eq!(0, state.noop_flag()); - - // all ones - let state = TraceState::from_vec(1, 0, 2, &vec![ - 101, 1, 2, 3, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 15, 16, 17 - ]); - - assert_eq!([0, 0, 0, 0, 0, 0, 0, 1], state.cf_op_flags()); - assert_eq!([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, - ], state.ld_op_flags()); - assert_eq!([0, 0, 0, 1], state.hd_op_flags()); - assert_eq!(0, state.begin_flag()); - assert_eq!(1, state.noop_flag()); - - // mixed 1 - let state = TraceState::from_vec(1, 0, 2, &vec![ - 101, 1, 2, 3, 4, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 15, 16, 17 - ]); - - assert_eq!([0, 1, 0, 0, 0, 0, 0, 0], state.cf_op_flags()); - assert_eq!([ - 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ], state.ld_op_flags()); - assert_eq!([0, 1, 0, 0], state.hd_op_flags()); - assert_eq!(0, state.begin_flag()); - assert_eq!(0, state.noop_flag()); - - // mixed 2 - let state = TraceState::from_vec(1, 0, 2, &vec![ - 101, 1, 2, 3, 4, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 15, 16, 17 - ]); - - assert_eq!([0, 0, 0, 1, 0, 0, 0, 0], state.cf_op_flags()); - assert_eq!([ - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ], state.ld_op_flags()); - assert_eq!([0, 0, 1, 0], state.hd_op_flags()); + // TODO } - + #[test] fn op_code() { let state = TraceState::from_vec(1, 0, 2, &vec![ From 4ea8887894a84ecc24f5155aecfa079ebd0bec90 Mon Sep 17 00:00:00 2001 From: bibbinth Date: Tue, 8 Sep 2020 01:35:04 -0700 Subject: [PATCH 3/4] refactoring opcode encoding - WIP commit --- src/lib.rs | 21 +- src/processor/decoder/mod.rs | 54 ++-- src/processor/mod.rs | 50 ++-- src/processor/opcodes.rs | 223 +++++++++++------ src/processor/stack/mod.rs | 6 + src/stark/constraints/decoder/op_bits.rs | 23 +- src/stark/constraints/evaluator.rs | 12 +- src/stark/trace/mod.rs | 1 + src/stark/trace/op_flags.rs | 227 +++++++++++++++++ src/stark/trace/trace_state.rs | 300 +++++++---------------- src/stark/utils/coefficients.rs | 4 +- 11 files changed, 536 insertions(+), 385 deletions(-) create mode 100644 src/stark/trace/op_flags.rs diff --git a/src/lib.rs b/src/lib.rs index b4094b1..a900ba7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -109,23 +109,20 @@ const HACC_NUM_ROUNDS : usize = 14; // DECODER LAYOUT // ------------------------------------------------------------------------------------------------ // -// ctr ╒═════ sponge ══════╕╒═══ cf_ops ══╕╒═══════ ld_ops ═══════╕╒═ hd_ops ╕╒═ ctx ══╕╒═ loop ═╕ -// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 .. .. .. -// ├────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┤ +// ctr ╒═════ sponge ══════╕╒═ flow_ops ══╕╒═════════ user_ops ═════════╕╒═ ctx ══╕╒═ loop ═╕ +// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 .. .. .. +// ├────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┤ -const NUM_CF_OP_BITS : usize = 3; -const NUM_LD_OP_BITS : usize = 5; -const NUM_HD_OP_BITS : usize = 2; +const NUM_FLOW_OP_BITS : usize = 3; +const NUM_USER_OP_BITS : usize = 6; -const NUM_CF_OPS : usize = 8; -const NUM_LD_OPS : usize = 32; -const NUM_HD_OPS : usize = 4; +const NUM_FLOW_OPS : usize = 8; +const NUM_USER_OPS : usize = 36; const OP_COUNTER_IDX : usize = 0; const SPONGE_RANGE : Range = Range { start: 1, end: 5 }; -const CF_OP_BITS_RANGE : Range = Range { start: 5, end: 8 }; -const LD_OP_BITS_RANGE : Range = Range { start: 8, end: 13 }; -const HD_OP_BITS_RANGE : Range = Range { start: 13, end: 15 }; +const FLOW_OP_BITS_RANGE : Range = Range { start: 5, end: 8 }; +const USER_OP_BITS_RANGE : Range = Range { start: 8, end: 14 }; // STACK LAYOUT // ------------------------------------------------------------------------------------------------ diff --git a/src/processor/decoder/mod.rs b/src/processor/decoder/mod.rs index ce07b1c..4212929 100644 --- a/src/processor/decoder/mod.rs +++ b/src/processor/decoder/mod.rs @@ -2,7 +2,7 @@ use crate::{ math::field, utils::sponge, MAX_CONTEXT_DEPTH, MAX_LOOP_DEPTH, - NUM_CF_OP_BITS, NUM_LD_OP_BITS, NUM_HD_OP_BITS, + NUM_FLOW_OP_BITS, NUM_USER_OP_BITS, SPONGE_WIDTH, BASE_CYCLE_LENGTH, PUSH_OP_ALIGNMENT, }; use super::opcodes::{ FlowOps, UserOps }; @@ -20,9 +20,8 @@ pub struct Decoder { sponge_trace: [Vec; SPONGE_WIDTH], sponge : [u128; SPONGE_WIDTH], - cf_op_bits : [Vec; NUM_CF_OP_BITS], - ld_op_bits : [Vec; NUM_LD_OP_BITS], - hd_op_bits : [Vec; NUM_HD_OP_BITS], + flow_op_bits: [Vec; NUM_FLOW_OP_BITS], + user_op_bits: [Vec; NUM_USER_OP_BITS], ctx_stack : Vec>, ctx_depth : usize, @@ -49,16 +48,13 @@ impl Decoder { let sponge = [field::ZERO; SPONGE_WIDTH]; // initialize op_bits registers - let cf_op_bits = [ + let flow_op_bits = [ vec![field::ZERO; init_trace_length], vec![field::ZERO; init_trace_length], vec![field::ZERO; init_trace_length] ]; - let ld_op_bits = [ + let user_op_bits = [ vec![field::ZERO; init_trace_length], vec![field::ZERO; init_trace_length], vec![field::ZERO; init_trace_length], vec![field::ZERO; init_trace_length], - vec![field::ZERO; init_trace_length] - ]; - let hd_op_bits = [ vec![field::ZERO; init_trace_length], vec![field::ZERO; init_trace_length] ]; @@ -73,7 +69,7 @@ impl Decoder { return Decoder { step: 0, op_counter, sponge, sponge_trace, - cf_op_bits, ld_op_bits, hd_op_bits, + flow_op_bits, user_op_bits, ctx_stack, ctx_depth, loop_stack, loop_depth, }; } @@ -107,9 +103,8 @@ impl Decoder { state.push(self.op_counter[step]); for register in self.sponge_trace.iter() { state.push(register[step]); } - for register in self.cf_op_bits.iter() { state.push(register[step]); } - for register in self.ld_op_bits.iter() { state.push(register[step]); } - for register in self.hd_op_bits.iter() { state.push(register[step]); } + for register in self.flow_op_bits.iter() { state.push(register[step]); } + for register in self.user_op_bits.iter() { state.push(register[step]); } for register in self.ctx_stack.iter() { state.push(register[step]); } for register in self.loop_stack.iter() { state.push(register[step]); } @@ -128,21 +123,18 @@ impl Decoder { registers.push(r2); registers.push(r3); - let [r0, r1, r2] = self.cf_op_bits; + let [r0, r1, r2] = self.flow_op_bits; registers.push(r0); registers.push(r1); registers.push(r2); - let [r0, r1, r2, r3, r4] = self.ld_op_bits; + let [r0, r1, r2, r3, r4, r5] = self.user_op_bits; registers.push(r0); registers.push(r1); registers.push(r2); registers.push(r3); registers.push(r4); - - let [r0, r1] = self.hd_op_bits; - registers.push(r0); - registers.push(r1); + registers.push(r5); // for context stack, first get rid of the outer-most context because it is always 0 self.ctx_stack.pop(); @@ -255,10 +247,9 @@ impl Decoder { let last_op_count = self.op_counter[self.step]; fill_register(&mut self.op_counter, self.step + 1, last_op_count); - // set all bit registers to 1 to indicate NOOP operation - for register in self.cf_op_bits.iter_mut() { fill_register(register, self.step, field::ONE); } - for register in self.ld_op_bits.iter_mut() { fill_register(register, self.step, field::ONE); } - for register in self.hd_op_bits.iter_mut() { fill_register(register, self.step, field::ONE); } + // set all bit registers to 0 to indicate NOOP operation + for register in self.flow_op_bits.iter_mut() { fill_register(register, self.step, field::ZERO); } + for register in self.user_op_bits.iter_mut() { fill_register(register, self.step, field::ZERO); } // for sponge and stack registers, just copy the value of the last state of the register for register in self.sponge_trace.iter_mut() { fill_register(register, self.step + 1, register[self.step]); } @@ -283,9 +274,8 @@ impl Decoder { self.op_counter.resize(new_length, field::ZERO); for register in self.sponge_trace.iter_mut() { register.resize(new_length, field::ZERO); } - for register in self.cf_op_bits.iter_mut() { register.resize(new_length, field::ZERO); } - for register in self.ld_op_bits.iter_mut() { register.resize(new_length, field::ZERO); } - for register in self.hd_op_bits.iter_mut() { register.resize(new_length, field::ZERO); } + for register in self.flow_op_bits.iter_mut() { register.resize(new_length, field::ZERO); } + for register in self.user_op_bits.iter_mut() { register.resize(new_length, field::ZERO); } for register in self.ctx_stack.iter_mut() { register.resize(new_length, field::ZERO); } for register in self.loop_stack.iter_mut() { register.resize(new_length, field::ZERO); } } @@ -306,17 +296,13 @@ impl Decoder { let step = self.step - 1; let flow_op = flow_op as u8; - for i in 0..NUM_CF_OP_BITS { - self.cf_op_bits[i][step] = ((flow_op >> i) & 1) as u128; + for i in 0..NUM_FLOW_OP_BITS { + self.flow_op_bits[i][step] = ((flow_op >> i) & 1) as u128; } let user_op = user_op as u8; - for i in 0..NUM_LD_OP_BITS { - self.ld_op_bits[i][step] = ((user_op >> i) & 1) as u128; - } - - for i in 0..NUM_HD_OP_BITS { - self.hd_op_bits[i][step] = ((user_op >> (i + NUM_LD_OP_BITS)) & 1) as u128; + for i in 0..NUM_USER_OP_BITS { + self.user_op_bits[i][step] = ((user_op >> i) & 1) as u128; } } diff --git a/src/processor/mod.rs b/src/processor/mod.rs index 4eb6c55..a236dcf 100644 --- a/src/processor/mod.rs +++ b/src/processor/mod.rs @@ -196,15 +196,14 @@ mod tests { let trace_length = trace[0].len(); assert_eq!(64, trace_length); - assert_eq!(17, trace.len()); + assert_eq!(16, trace.len()); let mut state = build_trace_state(trace.len(), ctx_depth, loop_depth) ; state.update_from_trace(&trace, trace_length - 1); assert_eq!(46, state.op_counter()); assert_eq!(program.hash(), as_bytes(state.program_hash())); - assert_eq!([1, 1, 1], state.cf_op_bits()); - assert_eq!([1, 1, 1, 1, 1], state.ld_op_bits()); - assert_eq!([1, 1], state.hd_op_bits()); + assert_eq!([0, 0, 0], state.flow_op_bits()); + assert_eq!([0, 0, 0, 0, 0, 0], state.user_op_bits()); assert_eq!([0], state.ctx_stack()); assert_eq!([7, 15, 0, 0, 0, 0, 0, 0], state.user_stack()); } @@ -218,17 +217,15 @@ mod tests { let trace_length = trace[0].len(); assert_eq!(64, trace_length); - assert_eq!(18, trace.len()); + assert_eq!(17, trace.len()); let mut state = build_trace_state(trace.len(), ctx_depth, loop_depth) ; state.update_from_trace(&trace, trace_length - 1); assert_eq!(60, state.op_counter()); assert_eq!(program.hash(), as_bytes(state.program_hash())); - assert_eq!([1, 1, 1], state.cf_op_bits()); - assert_eq!([1, 1, 1, 1, 1], state.ld_op_bits()); - assert_eq!([1, 1], state.hd_op_bits()); - assert_eq!([0], state.ctx_stack()); + assert_eq!([0, 0, 0], state.flow_op_bits()); + assert_eq!([0, 0, 0, 0, 0, 0], state.user_op_bits()); assert_eq!([0], state.loop_stack()); assert_eq!([7, 15, 0, 0, 0, 0, 0, 0], state.user_stack()); } @@ -244,16 +241,15 @@ mod tests { let trace_length = trace[0].len(); assert_eq!(128, trace_length); - assert_eq!(19, trace.len()); + assert_eq!(18, trace.len()); let mut state = build_trace_state(trace.len(), ctx_depth, loop_depth) ; state.update_from_trace(&trace, trace_length - 1); assert_eq!(76, state.op_counter()); assert_eq!(program.hash(), as_bytes(state.program_hash())); - assert_eq!([1, 1, 1], state.cf_op_bits()); - assert_eq!([1, 1, 1, 1, 1], state.ld_op_bits()); - assert_eq!([1, 1], state.hd_op_bits()); + assert_eq!([0, 0, 0], state.flow_op_bits()); + assert_eq!([0, 0, 0, 0, 0, 0], state.user_op_bits()); assert_eq!([0], state.ctx_stack()); assert_eq!([0], state.loop_stack()); assert_eq!([24, 0, 0, 0, 0, 0, 0, 0], state.user_stack()); @@ -264,16 +260,15 @@ mod tests { let trace_length = trace[0].len(); assert_eq!(128, trace_length); - assert_eq!(19, trace.len()); + assert_eq!(18, trace.len()); let mut state = build_trace_state(trace.len(), ctx_depth, loop_depth) ; state.update_from_trace(&trace, trace_length - 1); assert_eq!(92, state.op_counter()); assert_eq!(program.hash(), as_bytes(state.program_hash())); - assert_eq!([1, 1, 1], state.cf_op_bits()); - assert_eq!([1, 1, 1, 1, 1], state.ld_op_bits()); - assert_eq!([1, 1], state.hd_op_bits()); + assert_eq!([0, 0, 0], state.flow_op_bits()); + assert_eq!([0, 0, 0, 0, 0, 0], state.user_op_bits()); assert_eq!([0], state.ctx_stack()); assert_eq!([0], state.loop_stack()); assert_eq!([96, 3, 0, 0, 0, 0, 0, 0], state.user_stack()); @@ -290,16 +285,15 @@ mod tests { let trace_length = trace[0].len(); assert_eq!(64, trace_length); - assert_eq!(18, trace.len()); + assert_eq!(17, trace.len()); let mut state = build_trace_state(trace.len(), ctx_depth, loop_depth) ; state.update_from_trace(&trace, trace_length - 1); assert_eq!(60, state.op_counter()); assert_eq!(program.hash(), as_bytes(state.program_hash())); - assert_eq!([1, 1, 1], state.cf_op_bits()); - assert_eq!([1, 1, 1, 1, 1], state.ld_op_bits()); - assert_eq!([1, 1], state.hd_op_bits()); + assert_eq!([0, 0, 0], state.flow_op_bits()); + assert_eq!([0, 0, 0, 0, 0, 0], state.user_op_bits()); assert_eq!([0], state.ctx_stack()); assert_eq!([0], state.loop_stack()); assert_eq!([15, 0, 0, 0, 0, 0, 0, 0], state.user_stack()); @@ -310,16 +304,15 @@ mod tests { let trace_length = trace[0].len(); assert_eq!(128, trace_length); - assert_eq!(19, trace.len()); + assert_eq!(18, trace.len()); let mut state = build_trace_state(trace.len(), ctx_depth, loop_depth) ; state.update_from_trace(&trace, trace_length - 1); assert_eq!(75, state.op_counter()); assert_eq!(program.hash(), as_bytes(state.program_hash())); - assert_eq!([1, 1, 1], state.cf_op_bits()); - assert_eq!([1, 1, 1, 1, 1], state.ld_op_bits()); - assert_eq!([1, 1], state.hd_op_bits()); + assert_eq!([0, 0, 0], state.flow_op_bits()); + assert_eq!([0, 0, 0, 0, 0, 0], state.user_op_bits()); assert_eq!([0], state.ctx_stack()); assert_eq!([0], state.loop_stack()); assert_eq!([225, 0, 0, 0, 0, 0, 0, 0], state.user_stack()); @@ -330,16 +323,15 @@ mod tests { let trace_length = trace[0].len(); assert_eq!(256, trace_length); - assert_eq!(19, trace.len()); + assert_eq!(18, trace.len()); let mut state = build_trace_state(trace.len(), ctx_depth, loop_depth) ; state.update_from_trace(&trace, trace_length - 1); assert_eq!(135, state.op_counter()); assert_eq!(program.hash(), as_bytes(state.program_hash())); - assert_eq!([1, 1, 1], state.cf_op_bits()); - assert_eq!([1, 1, 1, 1, 1], state.ld_op_bits()); - assert_eq!([1, 1], state.hd_op_bits()); + assert_eq!([0, 0, 0], state.flow_op_bits()); + assert_eq!([0, 0, 0, 0, 0, 0], state.user_op_bits()); assert_eq!([0], state.ctx_stack()); assert_eq!([0], state.loop_stack()); assert_eq!([43143988327398919500410556793212890625, 0, 0, 0, 0, 0, 0, 0], state.user_stack()); diff --git a/src/processor/opcodes.rs b/src/processor/opcodes.rs index 08e8745..8a8630f 100644 --- a/src/processor/opcodes.rs +++ b/src/processor/opcodes.rs @@ -13,12 +13,6 @@ pub enum FlowOps { Void = 0b111, } -impl FlowOps { - pub fn op_index(&self) -> usize { - return (*self as usize) & 0b111; - } -} - impl std::fmt::Display for FlowOps { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { @@ -39,81 +33,76 @@ impl std::fmt::Display for FlowOps { } } +impl std::convert::TryFrom for FlowOps { + + type Error = String; + + fn try_from(value: u8) -> Result { + return match value { + + 0b00000_000 => Ok(FlowOps::Hacc), + 0b00000_001 => Ok(FlowOps::Begin), + 0b00000_010 => Ok(FlowOps::Tend), + 0b00000_011 => Ok(FlowOps::Fend), + 0b00000_100 => Ok(FlowOps::Loop), + 0b00000_101 => Ok(FlowOps::Wrap), + 0b00000_110 => Ok(FlowOps::Break), + 0b00000_111 => Ok(FlowOps::Void), + + _ => Err(format!("value {} is not a valid control flow opcode", value)) + }; + } +} + // USER OPERATIONS // ================================================================================================ #[repr(u8)] #[derive(Copy, Clone, Debug, PartialEq)] pub enum UserOps { - // low-degree operations - Assert = 0b0_11_00000, // left shift: 1 - AssertEq = 0b0_11_00001, // left shift: 2 - Eq = 0b0_11_00010, // left shift: 2 - Drop = 0b0_11_00011, // left shift: 1 - Drop4 = 0b0_11_00100, // left shift: 4 - Choose = 0b0_11_00101, // left shift: 2 - Choose2 = 0b0_11_00110, // left shift: 4 - CSwap2 = 0b0_11_00111, // left shift: 2 - - Add = 0b0_11_01000, // left shift: 1 - Mul = 0b0_11_01001, // left shift: 1 - And = 0b0_11_01010, // left shift: 1 - Or = 0b0_11_01011, // left shift: 1 - Inv = 0b0_11_01100, // no shift - Neg = 0b0_11_01101, // no shift - Not = 0b0_11_01110, // no shift - //??? = 0b0_11_01111, - - Read = 0b0_11_10000, // right shift: 1 - Read2 = 0b0_11_10001, // right shift: 2 - Dup = 0b0_11_10010, // right shift: 1 - Dup2 = 0b0_11_10011, // right shift: 2 - Dup4 = 0b0_11_10100, // right shift: 4 - Pad2 = 0b0_11_10101, // right shift: 2 - //??? = 0b0_11_10110, - //??? = 0b0_11_10111, - - Swap = 0b0_11_11000, // no shift - Swap2 = 0b0_11_11001, // no shift - Swap4 = 0b0_11_11010, // no shift - Roll4 = 0b0_11_11011, // no shift - Roll8 = 0b0_11_11100, // no shift - BinAcc = 0b0_11_11101, // no shift - //??? = 0b0_11_11110, - - // high-degree operations - Push = 0b0_00_11111, // right shift: 1 - Cmp = 0b0_01_11111, // no shift - RescR = 0b0_10_11111, // no shift + Noop = 0b00_00_0000, // no shift + Begin = 0b00_11_1111, // no shift - // composite operations - Begin = 0b0_00_00000, // no shift - Noop = 0b0_11_11111, // no shift -} - -impl UserOps { + // degree 1 operations + Assert = 0b00_00_0001, // left shift: 1 + AssertEq = 0b00_00_0010, // left shift: 2 + Drop = 0b00_00_0011, // left shift: 1 + Drop4 = 0b00_00_0100, // left shift: 4 + Read = 0b00_00_0101, // right shift: 1 + Read2 = 0b00_00_0110, // right shift: 2 + Dup = 0b00_00_0111, // right shift: 1 + Dup2 = 0b00_00_1000, // right shift: 2 + Dup4 = 0b00_00_1001, // right shift: 4 + Pad2 = 0b00_00_1010, // right shift: 2 + Swap = 0b00_00_1011, // no shift + Swap2 = 0b00_00_1100, // no shift + Swap4 = 0b00_00_1101, // no shift + Roll4 = 0b00_00_1110, // no shift + Roll8 = 0b00_00_1111, // no shift - pub fn ld_index(&self) -> usize { - return match self { - UserOps::Push | UserOps::Cmp | UserOps::RescR => { - panic!("{} is not a low-degree operation", self); - }, - _ => { - (*self as usize) & 0b11111 - } - }; - } + // degree 2 operations + Eq = 0b00_01_0000, // left shift: 2 + Choose = 0b00_01_0001, // left shift: 2 + Choose2 = 0b00_01_0010, // left shift: 4 + CSwap2 = 0b00_01_0011, // left shift: 2 + Add = 0b00_01_0100, // left shift: 1 + Mul = 0b00_01_0101, // left shift: 1 + And = 0b00_01_0110, // left shift: 1 + Or = 0b00_01_0111, // left shift: 1 + Inv = 0b00_01_1000, // no shift + Neg = 0b00_01_1001, // no shift + Not = 0b00_01_1010, // no shift + BinAcc = 0b00_01_1011, // no shift + MLoad = 0b00_01_1100, + MStore = 0b00_01_1101, + Future1 = 0b00_01_1110, + //invalid = 0b00_01_1111, - pub fn hd_index(&self) -> usize { - return match self { - UserOps::Push | UserOps::Cmp | UserOps::RescR | UserOps::Noop | UserOps::Begin => { - ((*self as usize) >> 5) & 0b11 - }, - _ => { - panic!("{} is not a high-degree operation", self); - } - }; - } + // high-degree operations + Push = 0b00_10_0001, // right shift: 1 + Cmp = 0b00_10_0010, // no shift + RescR = 0b00_10_0100, // no shift + MemRR = 0b00_10_1000, // no shift } impl std::fmt::Display for UserOps { @@ -130,6 +119,10 @@ impl std::fmt::Display for UserOps { UserOps::Push => write!(f, "push"), UserOps::Read => write!(f, "read"), UserOps::Read2 => write!(f, "read2"), + + UserOps::MLoad => write!(f, "mload"), + UserOps::MStore => write!(f, "mstore"), + UserOps::MemRR => write!(f, "memrr"), UserOps::Dup => write!(f, "dup"), UserOps::Dup2 => write!(f, "dup2"), @@ -162,7 +155,60 @@ impl std::fmt::Display for UserOps { UserOps::Cmp => write!(f, "cmp"), UserOps::BinAcc => write!(f, "binacc"), - UserOps::RescR => write!(f, "rescr") + UserOps::RescR => write!(f, "rescr"), + UserOps::Future1 => write!(f, "future1") + }; + } +} + +impl std::convert::TryFrom for UserOps { + + type Error = String; + + fn try_from(value: u8) -> Result { + return match value { + + 0b00_11_1111 => Ok(UserOps::Begin), + 0b00_00_0000 => Ok(UserOps::Noop), + + 0b00_00_0001 => Ok(UserOps::Assert), + 0b00_00_0010 => Ok(UserOps::AssertEq), + 0b00_00_0011 => Ok(UserOps::Drop), + 0b00_00_0100 => Ok(UserOps::Drop4), + 0b00_00_0101 => Ok(UserOps::Read), + 0b00_00_0110 => Ok(UserOps::Read2), + 0b00_00_0111 => Ok(UserOps::Dup), + 0b00_00_1000 => Ok(UserOps::Dup2), + 0b00_00_1001 => Ok(UserOps::Dup4), + 0b00_00_1010 => Ok(UserOps::Pad2), + 0b00_00_1011 => Ok(UserOps::Swap), + 0b00_00_1100 => Ok(UserOps::Swap2), + 0b00_00_1101 => Ok(UserOps::Swap4), + 0b00_00_1110 => Ok(UserOps::Roll4), + 0b00_00_1111 => Ok(UserOps::Roll8), + + 0b00_01_0000 => Ok(UserOps::Eq), + 0b00_01_0001 => Ok(UserOps::Choose), + 0b00_01_0010 => Ok(UserOps::Choose2), + 0b00_01_0011 => Ok(UserOps::CSwap2), + 0b00_01_0100 => Ok(UserOps::Add), + 0b00_01_0101 => Ok(UserOps::Mul), + 0b00_01_0110 => Ok(UserOps::And), + 0b00_01_0111 => Ok(UserOps::Or), + 0b00_01_1000 => Ok(UserOps::Inv), + 0b00_01_1001 => Ok(UserOps::Neg), + 0b00_01_1010 => Ok(UserOps::Not), + 0b00_01_1011 => Ok(UserOps::BinAcc), + 0b00_01_1100 => Ok(UserOps::MLoad), + 0b00_01_1101 => Ok(UserOps::MStore), + 0b00_01_1110 => Ok(UserOps::Future1), + + 0b00_10_0001 => Ok(UserOps::Push), + 0b00_10_0010 => Ok(UserOps::Cmp), + 0b00_10_0100 => Ok(UserOps::RescR), + 0b00_10_1000 => Ok(UserOps::MemRR), + + _ => Err(format!("value {} is not a valid user opcode", value)) }; } } @@ -199,4 +245,35 @@ impl std::fmt::Display for OpHint { OpHint::None => Ok(()), }; } +} + +// TESTS +// ================================================================================================ + +#[cfg(test)] +mod tests { + + use std::convert::TryFrom; + + #[test] + fn parse_user_ops() { + + for i in 0..64 { + match super::UserOps::try_from(i) { + Ok(opcode) => assert_eq!(i, opcode as u8), + Err(_) => () + } + } + } + + #[test] + fn parse_flow_ops() { + + for i in 0..8 { + match super::FlowOps::try_from(i) { + Ok(opcode) => assert_eq!(i, opcode as u8), + Err(_) => () + } + } + } } \ No newline at end of file diff --git a/src/processor/stack/mod.rs b/src/processor/stack/mod.rs index 7dcfd73..c37ac78 100644 --- a/src/processor/stack/mod.rs +++ b/src/processor/stack/mod.rs @@ -76,6 +76,10 @@ impl Stack { OpCode::Read => self.op_read(op_hint), OpCode::Read2 => self.op_read2(op_hint), + OpCode::MLoad => self.op_noop(), // TODO + OpCode::MStore => self.op_noop(), // TODO + OpCode::MemRR => self.op_noop(), // TODO + OpCode::Dup => self.op_dup(), OpCode::Dup2 => self.op_dup2(), OpCode::Dup4 => self.op_dup4(), @@ -108,6 +112,8 @@ impl Stack { OpCode::BinAcc => self.op_binacc(op_hint), OpCode::RescR => self.op_rescr(), + + OpCode::Future1 => self.op_noop(), } } diff --git a/src/stark/constraints/decoder/op_bits.rs b/src/stark/constraints/decoder/op_bits.rs index eac4884..6b2cd4f 100644 --- a/src/stark/constraints/decoder/op_bits.rs +++ b/src/stark/constraints/decoder/op_bits.rs @@ -11,28 +11,21 @@ pub fn enforce_op_bits(result: &mut [u128], current: &TraceState, next: &TraceSt { let mut i = 0; - // make sure all op bits are binary and compute their product/sum + // TODO: make sure all op bits are binary and compute their product/sum let mut cf_bit_sum = 0; - for &op_bit in current.cf_op_bits() { + for &op_bit in current.flow_op_bits() { result[i] = is_binary(op_bit); cf_bit_sum = add(cf_bit_sum, op_bit); i += 1; } let mut ld_bit_prod = 1; - for &op_bit in current.ld_op_bits() { + for &op_bit in current.user_op_bits() { result[i] = is_binary(op_bit); ld_bit_prod = mul(ld_bit_prod, op_bit); i += 1; } - let mut hd_bit_prod = 1; - for &op_bit in current.hd_op_bits() { - result[i] = is_binary(op_bit); - hd_bit_prod = mul(hd_bit_prod, op_bit); - i += 1; - } - // when cf_ops = hacc, operation counter should be incremented by 1; // otherwise, operation counter should remain the same let op_counter = current.op_counter(); @@ -44,11 +37,11 @@ pub fn enforce_op_bits(result: &mut [u128], current: &TraceState, next: &TraceSt // ld_ops and hd_ops can be all 0s at the first step, but cannot be all 0s // at any other step - result[i] = mul(op_counter, mul(binary_not(ld_bit_prod), binary_not(hd_bit_prod))); + result[i] = 0; // TODO mul(op_counter, mul(binary_not(ld_bit_prod), binary_not(hd_bit_prod))); i += 1; // when cf_ops are not all 0s, ld_ops and hd_ops must be all 1s - result[i] = mul(cf_bit_sum, binary_not(mul(ld_bit_prod, hd_bit_prod))); + result[i] = 0; // TODO mul(cf_bit_sum, binary_not(mul(ld_bit_prod, hd_bit_prod))); i += 1; // VOID can be followed only by VOID @@ -204,12 +197,12 @@ mod tests { fn new_state(flow_op: u8, user_op: u8, op_counter: u128) -> TraceState { let mut state = TraceState::new(1, 0, 1); - let mut op_bits = [0; 10]; + let mut op_bits = [0; 9]; for i in 0..3 { op_bits[i] = ((flow_op as u128) >> i) & 1; } - for i in 0..7 { + for i in 0..6 { op_bits[i + 3] = ((user_op as u128) >> i) & 1; } @@ -222,7 +215,7 @@ mod tests { let mut state = TraceState::new(1, 0, 1); state.set_op_bits([ cf_bits[0], cf_bits[1], cf_bits[2], - u_bits[0], u_bits[1], u_bits[2], u_bits[3], u_bits[4], u_bits[5], u_bits[6] + u_bits[0], u_bits[1], u_bits[2], u_bits[3], u_bits[4], u_bits[5] ]); return state; } diff --git a/src/stark/constraints/evaluator.rs b/src/stark/constraints/evaluator.rs index 2e42613..31f8bad 100644 --- a/src/stark/constraints/evaluator.rs +++ b/src/stark/constraints/evaluator.rs @@ -203,7 +203,7 @@ impl Evaluator { // make sure cf_bits are set to HACC (000) let mut cc_idx = 0; - let op_bits = current.cf_op_bits(); + let op_bits = current.flow_op_bits(); for i in 0..op_bits.len() { i_result = field::add(i_result, field::mul(op_bits[i], cc.op_bits[cc_idx])); result_adj = field::add(result_adj, field::mul(op_bits[i], cc.op_bits[cc_idx + 1])); @@ -211,7 +211,7 @@ impl Evaluator { } // make sure low-degree op_bits are set to BEGIN (0000) - let op_bits = current.ld_op_bits(); + let op_bits = current.user_op_bits(); for i in 0..op_bits.len() { i_result = field::add(i_result, field::mul(op_bits[i], cc.op_bits[cc_idx])); result_adj = field::add(result_adj, field::mul(op_bits[i], cc.op_bits[cc_idx + 1])); @@ -219,7 +219,7 @@ impl Evaluator { } // make sure high-degree op_bits are set to BEGIN (00) - let op_bits = current.hd_op_bits(); + let op_bits = current.user_op_bits(); // TODO for i in 0..op_bits.len() { i_result = field::add(i_result, field::mul(op_bits[i], cc.op_bits[cc_idx])); result_adj = field::add(result_adj, field::mul(op_bits[i], cc.op_bits[cc_idx + 1])); @@ -272,7 +272,7 @@ impl Evaluator { // make sure control flow op_bits are set VOID (111) let mut cc_idx = 0; - let op_bits = current.cf_op_bits(); + let op_bits = current.flow_op_bits(); for i in 0..op_bits.len() { let val = field::sub(op_bits[i], field::ONE); f_result = field::add(f_result, field::mul(val, cc.op_bits[cc_idx])); @@ -281,7 +281,7 @@ impl Evaluator { } // make sure low-degree op_bits are set to NOOP (11111) - let op_bits = current.ld_op_bits(); + let op_bits = current.user_op_bits(); for i in 0..op_bits.len() { let val = field::sub(op_bits[i], field::ONE); f_result = field::add(f_result, field::mul(val, cc.op_bits[cc_idx])); @@ -290,7 +290,7 @@ impl Evaluator { } // make sure high-degree op_bits are set to NOOP (11) - let op_bits = current.hd_op_bits(); + let op_bits = current.user_op_bits(); // TODO for i in 0..op_bits.len() { let val = field::sub(op_bits[i], field::ONE); f_result = field::add(f_result, field::mul(val, cc.op_bits[cc_idx])); diff --git a/src/stark/trace/mod.rs b/src/stark/trace/mod.rs index 36e9b4d..9ca40e2 100644 --- a/src/stark/trace/mod.rs +++ b/src/stark/trace/mod.rs @@ -1,5 +1,6 @@ mod trace_state; mod trace_table; +mod op_flags; pub use trace_state::TraceState; pub use trace_table::TraceTable; \ No newline at end of file diff --git a/src/stark/trace/op_flags.rs b/src/stark/trace/op_flags.rs new file mode 100644 index 0000000..1b7e8b1 --- /dev/null +++ b/src/stark/trace/op_flags.rs @@ -0,0 +1,227 @@ +use crate::{ + math::field, + processor::opcodes::{ FlowOps, UserOps }, + NUM_FLOW_OP_BITS, NUM_FLOW_OPS, + NUM_USER_OP_BITS, NUM_USER_OPS +}; + +// TYPES AND INTERFACES +// ================================================================================================ + +pub struct OpFlags { + flow_ops : [u128; NUM_FLOW_OPS], + user_ops : [u128; NUM_USER_OPS], +} + +// OP FLAGS IMPLEMENTATION +// ================================================================================================ + +impl OpFlags { + + // CONSTRUCTOR + // -------------------------------------------------------------------------------------------- + pub fn new() -> OpFlags { + return OpFlags { + flow_ops : [0; NUM_FLOW_OPS], + user_ops : [0; NUM_USER_OPS] + }; + } + + // FLAG GETTERS + // -------------------------------------------------------------------------------------------- + + pub fn get_flow_op_flag(&self, op: FlowOps) -> u128 { + return match op { + FlowOps::Hacc => self.flow_ops[0], + FlowOps::Begin => self.flow_ops[1], + FlowOps::Tend => self.flow_ops[2], + FlowOps::Fend => self.flow_ops[3], + FlowOps::Loop => self.flow_ops[4], + FlowOps::Wrap => self.flow_ops[5], + FlowOps::Break => self.flow_ops[6], + FlowOps::Void => self.flow_ops[7], + }; + } + + pub fn get_user_op_flag(&self, op: UserOps) -> u128 { + return match op { + UserOps::Noop => self.user_ops[0], + UserOps::Assert => self.user_ops[1], + UserOps::AssertEq => self.user_ops[2], + UserOps::Drop => self.user_ops[3], + UserOps::Drop4 => self.user_ops[4], + UserOps::Pad2 => self.user_ops[5], + UserOps::Dup => self.user_ops[6], + UserOps::Dup2 => self.user_ops[7], + UserOps::Dup4 => self.user_ops[8], + UserOps::Read => self.user_ops[9], + UserOps::Read2 => self.user_ops[10], + UserOps::Swap => self.user_ops[11], + UserOps::Swap2 => self.user_ops[12], + UserOps::Swap4 => self.user_ops[13], + UserOps::Roll4 => self.user_ops[14], + UserOps::Roll8 => self.user_ops[15], + + UserOps::Eq => self.user_ops[16], + UserOps::Choose => self.user_ops[17], + UserOps::Choose2 => self.user_ops[18], + UserOps::CSwap2 => self.user_ops[19], + UserOps::Add => self.user_ops[20], + UserOps::Mul => self.user_ops[21], + UserOps::And => self.user_ops[22], + UserOps::Or => self.user_ops[23], + UserOps::Inv => self.user_ops[24], + UserOps::Neg => self.user_ops[25], + UserOps::Not => self.user_ops[26], + UserOps::BinAcc => self.user_ops[27], + UserOps::MLoad => self.user_ops[28], + UserOps::MStore => self.user_ops[29], + UserOps::Future1 => self.user_ops[30], + + UserOps::Push => self.user_ops[31], + UserOps::Cmp => self.user_ops[32], + UserOps::RescR => self.user_ops[33], + UserOps::MemRR => self.user_ops[34], + + UserOps::Begin => self.user_ops[35] + }; + } + + // FLAG SETTER + // -------------------------------------------------------------------------------------------- + + pub fn update(&mut self, flow_op_bits: &[u128; NUM_FLOW_OP_BITS], user_op_bits: &[u128; NUM_USER_OP_BITS]) { + + // 1 ----- compute control flow op flags -------------------------------------------------- + + let not_0 = binary_not(flow_op_bits[0]); + let not_1 = binary_not(flow_op_bits[1]); + self.flow_ops[0] = field::mul(not_0, not_1); + self.flow_ops[1] = field::mul(flow_op_bits[0], not_1); + self.flow_ops[2] = field::mul(not_0, flow_op_bits[1]); + self.flow_ops[3] = field::mul(flow_op_bits[0], flow_op_bits[1]); + self.flow_ops.copy_within(0..4, 4); + + let not_2 = binary_not(flow_op_bits[2]); + for i in 0..4 { self.flow_ops[i] = field::mul(self.flow_ops[i], not_2); } + for i in 4..8 { self.flow_ops[i] = field::mul(self.flow_ops[i], flow_op_bits[2]); } + + // 2 ----- compute user op flags ---------------------------------------------------------- + + let not_0 = binary_not(user_op_bits[0]); + let not_1 = binary_not(user_op_bits[1]); + self.user_ops[0] = field::mul(not_0, not_1); + self.user_ops[1] = field::mul(user_op_bits[0], not_1); + self.user_ops[2] = field::mul(not_0, user_op_bits[1]); + self.user_ops[3] = field::mul(user_op_bits[0], user_op_bits[1]); + self.user_ops.copy_within(0..4, 4); + + let not_2 = binary_not(user_op_bits[2]); + for i in 0..4 { self.user_ops[i] = field::mul(self.user_ops[i], not_2); } + for i in 4..8 { self.user_ops[i] = field::mul(self.user_ops[i], user_op_bits[2]); } + self.user_ops.copy_within(0..8, 8); + + let not_3 = binary_not(user_op_bits[3]); + for i in 0..8 { self.user_ops[i] = field::mul(self.user_ops[i], not_3); } + for i in 8..16 { self.user_ops[i] = field::mul(self.user_ops[i], user_op_bits[3]); } + + self.user_ops.copy_within(0..15, 16); + + // all op_bits are 1's: for begin op only + let class_1 = field::mul(user_op_bits[4], user_op_bits[5]); + self.user_ops[35] = field::mul(self.user_ops[15], class_1); // begin + + // class 2 ops: can be degree 5 or smaller + let not_4 = binary_not(user_op_bits[4]); + let class_2 = field::mul(not_4, user_op_bits[5]); + self.user_ops[31] = field::mul(user_op_bits[0], class_2); // push + self.user_ops[32] = field::mul(user_op_bits[1], class_2); // cmp + self.user_ops[33] = field::mul(user_op_bits[2], class_2); // rescr + self.user_ops[34] = field::mul(user_op_bits[3], class_2); // memrr + + // class 3 ops: can be degree 2 or smaller + let not_5 = binary_not(user_op_bits[5]); + let class_3 = field::mul(user_op_bits[4], not_5); + for i in 16..31 { self.user_ops[i] = field::mul(self.user_ops[i], class_3); } + + // class 4 ops: must be degree 1 + let class_4 = field::mul(not_4, not_5); + for i in 0..16 { self.user_ops[i] = field::mul(self.user_ops[i], class_4); } + } +} + +impl PartialEq for OpFlags { + fn eq(&self, other: &Self) -> bool { + return self.flow_ops == other.flow_ops + && self.user_ops.to_vec() == other.user_ops.to_vec(); + } +} + +// HELPER FUNCTIONS +// ================================================================================================ +#[inline(always)] +fn binary_not(v: u128) -> u128 { + return field::sub(field::ONE, v); +} + +// TESTS +// ================================================================================================ +#[cfg(test)] +mod tests { + + use std::convert::TryFrom; + use super::{ NUM_FLOW_OP_BITS, NUM_USER_OP_BITS }; + + #[test] + fn flow_ops() { + let mut flags = super::OpFlags::new(); + for i in 0..8 { + match super::UserOps::try_from(i) { + Ok(_) => { + let mut flow_op_bits = [0; NUM_FLOW_OP_BITS]; + for j in 0..NUM_FLOW_OP_BITS { + flow_op_bits[j] = ((i >> j) & 1) as u128; + } + + flags.update(&flow_op_bits, &[0, 0, 0, 0, 0, 0]); + + let mut flag_count = 0; + for flag in flags.flow_ops.to_vec() { + if flag == 1 { flag_count += 1; } + } + + // one and only one flag can be set for each valid operation + assert_eq!(flag_count, 1); + }, + Err(_) => () + } + } + } + + #[test] + fn user_ops() { + let mut flags = super::OpFlags::new(); + for i in 0..64 { + match super::UserOps::try_from(i) { + Ok(_) => { + let mut user_op_bits = [0; NUM_USER_OP_BITS]; + for j in 0..NUM_USER_OP_BITS { + user_op_bits[j] = ((i >> j) & 1) as u128; + } + + flags.update(&[0, 0, 0], &user_op_bits); + + let mut flag_count = 0; + for flag in flags.user_ops.to_vec() { + if flag == 1 { flag_count += 1; } + } + + // one and only one flag can be set for each valid operation + assert_eq!(flag_count, 1); + }, + Err(_) => () + } + } + } + +} \ No newline at end of file diff --git a/src/stark/trace/trace_state.rs b/src/stark/trace/trace_state.rs index ffb9b8e..7c7022c 100644 --- a/src/stark/trace/trace_state.rs +++ b/src/stark/trace/trace_state.rs @@ -1,20 +1,18 @@ use std::{ fmt, cmp }; use crate::{ math::field, - OpCode, + processor::opcodes::{ FlowOps, UserOps }, PROGRAM_DIGEST_SIZE, MIN_STACK_DEPTH, MIN_CONTEXT_DEPTH, MIN_LOOP_DEPTH, OP_COUNTER_IDX, SPONGE_WIDTH, SPONGE_RANGE, - NUM_CF_OPS, NUM_LD_OPS, NUM_HD_OPS, - NUM_CF_OP_BITS, NUM_LD_OP_BITS, NUM_HD_OP_BITS, - CF_OP_BITS_RANGE, LD_OP_BITS_RANGE, HD_OP_BITS_RANGE, - processor::opcodes::{ FlowOps, UserOps } + NUM_FLOW_OP_BITS, NUM_USER_OP_BITS, + FLOW_OP_BITS_RANGE, USER_OP_BITS_RANGE, }; - +use super::op_flags::OpFlags; // CONSTANTS // ================================================================================================ -const NUM_OP_BITS: usize = NUM_CF_OP_BITS + NUM_LD_OP_BITS + NUM_HD_OP_BITS; +const NUM_OP_BITS: usize = NUM_FLOW_OP_BITS + NUM_USER_OP_BITS; const NUM_STATIC_DECODER_REGISTERS: usize = 1 + SPONGE_WIDTH + NUM_OP_BITS; // 1 is for op_counter // TYPES AND INTERFACES @@ -23,9 +21,8 @@ const NUM_STATIC_DECODER_REGISTERS: usize = 1 + SPONGE_WIDTH + NUM_OP_BITS; // 1 pub struct TraceState { op_counter : u128, sponge : [u128; SPONGE_WIDTH], - cf_op_bits : [u128; NUM_CF_OP_BITS], - ld_op_bits : [u128; NUM_LD_OP_BITS], - hd_op_bits : [u128; NUM_HD_OP_BITS], + flow_op_bits: [u128; NUM_FLOW_OP_BITS], + user_op_bits: [u128; NUM_USER_OP_BITS], ctx_stack : Vec, loop_stack : Vec, user_stack : Vec, @@ -34,11 +31,7 @@ pub struct TraceState { loop_depth : usize, stack_depth : usize, - cf_op_flags : [u128; NUM_CF_OPS], - ld_op_flags : [u128; NUM_LD_OPS], - hd_op_flags : [u128; NUM_HD_OPS], - begin_flag : u128, - noop_flag : u128, + op_flags : OpFlags, } // TRACE STATE IMPLEMENTATION @@ -53,20 +46,15 @@ impl TraceState { return TraceState { op_counter : 0, sponge : [0; SPONGE_WIDTH], - cf_op_bits : [0; NUM_CF_OP_BITS], - ld_op_bits : [0; NUM_LD_OP_BITS], - hd_op_bits : [0; NUM_HD_OP_BITS], + flow_op_bits: [0; NUM_FLOW_OP_BITS], + user_op_bits: [0; NUM_USER_OP_BITS], ctx_stack : vec![0; cmp::max(ctx_depth, MIN_CONTEXT_DEPTH)], loop_stack : vec![0; cmp::max(loop_depth, MIN_LOOP_DEPTH)], user_stack : vec![0; cmp::max(stack_depth, MIN_STACK_DEPTH)], ctx_depth : ctx_depth, loop_depth : loop_depth, stack_depth : stack_depth, - cf_op_flags : [0; NUM_CF_OPS], - ld_op_flags : [0; NUM_LD_OPS], - hd_op_flags : [0; NUM_HD_OPS], - begin_flag : 0, - noop_flag : 0, + op_flags : OpFlags::new(), }; } @@ -77,18 +65,15 @@ impl TraceState { let mut sponge = [0; SPONGE_WIDTH]; sponge.copy_from_slice(&state[SPONGE_RANGE]); - let mut cf_op_bits = [0; NUM_CF_OP_BITS]; - cf_op_bits.copy_from_slice(&state[CF_OP_BITS_RANGE]); - - let mut ld_op_bits = [0; NUM_LD_OP_BITS]; - ld_op_bits.copy_from_slice(&state[LD_OP_BITS_RANGE]); + let mut flow_op_bits = [0; NUM_FLOW_OP_BITS]; + flow_op_bits.copy_from_slice(&state[FLOW_OP_BITS_RANGE]); - let mut hd_op_bits = [0; NUM_HD_OP_BITS]; - hd_op_bits.copy_from_slice(&state[HD_OP_BITS_RANGE]); + let mut user_op_bits = [0; NUM_USER_OP_BITS]; + user_op_bits.copy_from_slice(&state[USER_OP_BITS_RANGE]); let mut ctx_stack = vec![0; cmp::max(ctx_depth, MIN_CONTEXT_DEPTH)]; - let ctx_stack_end = HD_OP_BITS_RANGE.end + ctx_depth; - ctx_stack[..ctx_depth].copy_from_slice(&state[HD_OP_BITS_RANGE.end..ctx_stack_end]); + let ctx_stack_end = USER_OP_BITS_RANGE.end + ctx_depth; + ctx_stack[..ctx_depth].copy_from_slice(&state[USER_OP_BITS_RANGE.end..ctx_stack_end]); let mut loop_stack = vec![0; cmp::max(loop_depth, MIN_LOOP_DEPTH)]; let loop_stack_end = ctx_stack_end + loop_depth; @@ -99,16 +84,12 @@ impl TraceState { let mut state = TraceState { op_counter, sponge, - cf_op_bits, ld_op_bits, hd_op_bits, + flow_op_bits, user_op_bits, ctx_stack, loop_stack, user_stack, ctx_depth, loop_depth, stack_depth, - cf_op_flags : [0; NUM_CF_OPS], - ld_op_flags : [0; NUM_LD_OPS], - hd_op_flags : [0; NUM_HD_OPS], - begin_flag : 0, - noop_flag : 0, + op_flags: OpFlags::new() }; - state.set_op_flags(); + state.op_flags.update(&state.flow_op_bits, &state.user_op_bits); return state; } @@ -122,7 +103,7 @@ impl TraceState { // PUBLIC ACCESSORS // -------------------------------------------------------------------------------------------- pub fn width(&self) -> usize { - return HD_OP_BITS_RANGE.end + self.ctx_depth + self.loop_depth + self.stack_depth; + return USER_OP_BITS_RANGE.end + self.ctx_depth + self.loop_depth + self.stack_depth; } pub fn stack_depth(&self) -> usize { @@ -152,51 +133,38 @@ impl TraceState { // OP BITS // -------------------------------------------------------------------------------------------- - pub fn cf_op_bits(&self) -> &[u128] { - return &self.cf_op_bits; - } - - pub fn ld_op_bits(&self) -> &[u128] { - return &self.ld_op_bits; + pub fn flow_op_bits(&self) -> &[u128] { + return &self.flow_op_bits; } - pub fn hd_op_bits(&self) -> &[u128] { - return &self.hd_op_bits; + pub fn user_op_bits(&self) -> &[u128] { + return &self.user_op_bits; } pub fn op_code(&self) -> u128 { - let mut result = self.ld_op_bits[0]; - result = field::add(result, field::mul(self.ld_op_bits[1], 2)); - result = field::add(result, field::mul(self.ld_op_bits[2], 4)); - result = field::add(result, field::mul(self.ld_op_bits[3], 8)); - result = field::add(result, field::mul(self.ld_op_bits[4], 16)); - result = field::add(result, field::mul(self.hd_op_bits[0], 32)); - result = field::add(result, field::mul(self.hd_op_bits[1], 64)); + let mut result = self.user_op_bits[0]; + result = field::add(result, field::mul(self.user_op_bits[1], 2)); + result = field::add(result, field::mul(self.user_op_bits[2], 4)); + result = field::add(result, field::mul(self.user_op_bits[3], 8)); + result = field::add(result, field::mul(self.user_op_bits[4], 16)); + result = field::add(result, field::mul(self.user_op_bits[5], 32)); return result; } pub fn set_op_bits(&mut self, bits: [u128; NUM_OP_BITS]) { - self.cf_op_bits.copy_from_slice(&bits[..3]); - self.ld_op_bits.copy_from_slice(&bits[3..8]); - self.hd_op_bits.copy_from_slice(&bits[8..]); - self.set_op_flags(); + self.flow_op_bits.copy_from_slice(&bits[..3]); + self.user_op_bits.copy_from_slice(&bits[3..9]); + self.op_flags.update(&self.flow_op_bits, &self.user_op_bits); } // OP FLAGS // -------------------------------------------------------------------------------------------- pub fn get_flow_op_flags(&self, opcode: FlowOps) -> u128 { - return self.cf_op_flags[opcode.op_index()]; + return self.op_flags.get_flow_op_flag(opcode); } pub fn get_user_op_flag(&self, opcode: UserOps) -> u128 { - return match opcode { - - UserOps::Begin => self.begin_flag, - UserOps::Noop => self.noop_flag, - UserOps::Push | UserOps::Cmp | UserOps::RescR => self.hd_op_flags[opcode.hd_index()], - - _ => self.ld_op_flags[opcode.ld_index()], - }; + return self.op_flags.get_user_op_flag(opcode); } // STACKS @@ -219,9 +187,8 @@ impl TraceState { let mut result = Vec::with_capacity(self.width()); result.push(self.op_counter); result.extend_from_slice(&self.sponge); - result.extend_from_slice(&self.cf_op_bits); - result.extend_from_slice(&self.ld_op_bits); - result.extend_from_slice(&self.hd_op_bits); + result.extend_from_slice(&self.flow_op_bits); + result.extend_from_slice(&self.user_op_bits); result.extend_from_slice(&self.ctx_stack[..self.ctx_depth]); result.extend_from_slice(&self.loop_stack[..self.loop_depth]); result.extend_from_slice(&self.user_stack[..self.stack_depth]); @@ -232,12 +199,11 @@ impl TraceState { self.op_counter = trace[OP_COUNTER_IDX][step]; - for (i, j) in SPONGE_RANGE.enumerate() { self.sponge[i] = trace[j][step]; } - for (i, j) in CF_OP_BITS_RANGE.enumerate() { self.cf_op_bits[i] = trace[j][step]; } - for (i, j) in LD_OP_BITS_RANGE.enumerate() { self.ld_op_bits[i] = trace[j][step]; } - for (i, j) in HD_OP_BITS_RANGE.enumerate() { self.hd_op_bits[i] = trace[j][step]; } + for (i, j) in SPONGE_RANGE.enumerate() { self.sponge[i] = trace[j][step]; } + for (i, j) in FLOW_OP_BITS_RANGE.enumerate() { self.flow_op_bits[i] = trace[j][step]; } + for (i, j) in USER_OP_BITS_RANGE.enumerate() { self.user_op_bits[i] = trace[j][step]; } - let ctx_stack_start = HD_OP_BITS_RANGE.end; + let ctx_stack_start = USER_OP_BITS_RANGE.end; let ctx_stack_end = ctx_stack_start + self.ctx_depth; for (i, j) in (ctx_stack_start..ctx_stack_end).enumerate() { self.ctx_stack[i] = trace[j][step]; @@ -253,88 +219,17 @@ impl TraceState { self.user_stack[i] = trace[j][step]; } - self.set_op_flags(); - } - - // HELPER METHODS - // -------------------------------------------------------------------------------------------- - fn set_op_flags(&mut self) { - - // set control flow flags - let not_0 = binary_not(self.cf_op_bits[0]); - let not_1 = binary_not(self.cf_op_bits[1]); - self.cf_op_flags[0] = field::mul(not_0, not_1); - self.cf_op_flags[1] = field::mul(self.cf_op_bits[0], not_1); - self.cf_op_flags[2] = field::mul(not_0, self.cf_op_bits[1]); - self.cf_op_flags[3] = field::mul(self.cf_op_bits[0], self.cf_op_bits[1]); - self.cf_op_flags.copy_within(0..4, 4); - - let not_2 = binary_not(self.cf_op_bits[2]); - for i in 0..4 { self.cf_op_flags[i] = field::mul(self.cf_op_flags[i], not_2); } - for i in 4..8 { self.cf_op_flags[i] = field::mul(self.cf_op_flags[i], self.cf_op_bits[2]); } - - // set low-degree operation flags - let not_0 = binary_not(self.ld_op_bits[0]); - let not_1 = binary_not(self.ld_op_bits[1]); - self.ld_op_flags[0] = field::mul(not_0, not_1); - self.ld_op_flags[1] = field::mul(self.ld_op_bits[0], not_1); - self.ld_op_flags[2] = field::mul(not_0, self.cf_op_bits[1]); - self.ld_op_flags[3] = field::mul(self.ld_op_bits[0], self.ld_op_bits[1]); - self.ld_op_flags.copy_within(0..4, 4); - - let not_2 = binary_not(self.ld_op_bits[2]); - for i in 0..4 { self.ld_op_flags[i] = field::mul(self.ld_op_flags[i], not_2); } - for i in 4..8 { self.ld_op_flags[i] = field::mul(self.ld_op_flags[i], self.ld_op_bits[2]); } - self.ld_op_flags.copy_within(0..8, 8); - - let not_3 = binary_not(self.ld_op_bits[3]); - for i in 0..8 { self.ld_op_flags[i] = field::mul(self.ld_op_flags[i], not_3); } - for i in 8..16 { self.ld_op_flags[i] = field::mul(self.ld_op_flags[i], self.ld_op_bits[3]); } - self.ld_op_flags.copy_within(0..16, 16); - - let not_4 = binary_not(self.ld_op_bits[4]); - for i in 0..16 { self.ld_op_flags[i] = field::mul(self.ld_op_flags[i], not_4); } - for i in 16..32 { self.ld_op_flags[i] = field::mul(self.ld_op_flags[i], self.ld_op_bits[4]); } - - // set high-degree operation flags - let not_0 = binary_not(self.hd_op_bits[0]); - let not_1 = binary_not(self.hd_op_bits[1]); - self.hd_op_flags[0] = field::mul(not_0, not_1); - self.hd_op_flags[1] = field::mul(self.hd_op_bits[0], not_1); - self.hd_op_flags[2] = field::mul(not_0, self.hd_op_bits[1]); - self.hd_op_flags[3] = field::mul(self.hd_op_bits[0], self.hd_op_bits[1]); - - // compute flag for BEGIN operation which is just 0000000; the below is equivalent - // to multiplying binary inverses of all op bits together. - self.begin_flag = field::mul( - self.ld_op_flags[OpCode::Begin.ld_index()], - self.hd_op_flags[OpCode::Begin.hd_index()]); - - // compute flag for NOOP operation which is just 1111111; the below is equivalent to - // multiplying all op bits together. - self.noop_flag = field::mul( - self.ld_op_flags[OpCode::Noop.ld_index()], - self.hd_op_flags[OpCode::Noop.hd_index()]); - - // we need to make special adjustments for PUSH and ASSERT op flags so that they - // don't coincide with BEGIN operation; we do this by multiplying each flag by a - // single op_bit from another op bank; this increases degree of each flag by 1 - debug_assert!(OpCode::Push.hd_index() == 0, "PUSH index is not 0!"); - self.hd_op_flags[0] = field::mul(self.hd_op_flags[0], self.ld_op_bits[0]); - - debug_assert!(OpCode::Assert.ld_index() == 0, "ASSERT index is not 0!"); - self.ld_op_flags[0] = field::mul(self.ld_op_flags[0], self.hd_op_bits[0]); + self.op_flags.update(&self.flow_op_bits, &self.user_op_bits); } } impl fmt::Debug for TraceState { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "[{:>4}] {:>32X?} {:?} {:?} {:?} {:>32X?} {:>32X?} {:?}", + write!(f, "[{:>4}] {:>32X?} {:?} {:?} {:>32X?} {:>32X?} {:?}", self.op_counter, self.sponge, - self.cf_op_bits, - self.ld_op_bits, - self.hd_op_bits, + self.flow_op_bits, + self.user_op_bits, self.ctx_stack, self.loop_stack, self.user_stack @@ -344,12 +239,11 @@ impl fmt::Debug for TraceState { impl fmt::Display for TraceState { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "[{:>4}] {:>16X?} {:?} {:?} {:?} {:>16X?} {:>16X?} {:?}", + write!(f, "[{:>4}] {:>16X?} {:?} {:?} {:>16X?} {:>16X?} {:?}", self.op_counter, self.sponge.iter().map(|x| x >> 64).collect::>(), - self.cf_op_bits, - self.ld_op_bits, - self.hd_op_bits, + self.flow_op_bits, + self.user_op_bits, self.ctx_stack.iter().map(|x| x >> 64).collect::>(), self.loop_stack.iter().map(|x| x >> 64).collect::>(), &self.user_stack[..self.stack_depth] @@ -357,13 +251,6 @@ impl fmt::Display for TraceState { } } -// HELPER FUNCTIONS -// ================================================================================================ -#[inline(always)] -fn binary_not(v: u128) -> u128 { - return field::sub(field::ONE, v); -} - // TESTS // ================================================================================================ #[cfg(test)] @@ -376,68 +263,65 @@ mod tests { // empty context and loop stacks let state = TraceState::from_vec(0, 0, 2, &vec![ - 101, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 + 101, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ]); assert_eq!(101, state.op_counter()); assert_eq!([1, 2, 3, 4], state.sponge()); - assert_eq!([5, 6, 7], state.cf_op_bits()); - assert_eq!([8, 9, 10, 11, 12], state.ld_op_bits()); - assert_eq!([13, 14], state.hd_op_bits()); + assert_eq!([5, 6, 7], state.flow_op_bits()); + assert_eq!([8, 9, 10, 11, 12, 13], state.user_op_bits()); assert_eq!([0], state.ctx_stack()); assert_eq!([0], state.loop_stack()); - assert_eq!([15, 16, 0, 0, 0, 0, 0, 0], state.user_stack()); - assert_eq!(17, state.width()); + assert_eq!([14, 15, 0, 0, 0, 0, 0, 0], state.user_stack()); + assert_eq!(16, state.width()); assert_eq!(2, state.stack_depth()); assert_eq!(vec![ - 101, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 + 101, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ], state.to_vec()); // 1 item on context stack, empty loop stack let state = TraceState::from_vec(1, 0, 2, &vec![ - 101, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 + 101, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 ]); assert_eq!(101, state.op_counter()); assert_eq!([1, 2, 3, 4], state.sponge()); - assert_eq!([5, 6, 7], state.cf_op_bits()); - assert_eq!([8, 9, 10, 11, 12], state.ld_op_bits()); - assert_eq!([13, 14], state.hd_op_bits()); - assert_eq!([15], state.ctx_stack()); + assert_eq!([5, 6, 7], state.flow_op_bits()); + assert_eq!([8, 9, 10, 11, 12, 13], state.user_op_bits()); + assert_eq!([14], state.ctx_stack()); assert_eq!([0], state.loop_stack()); - assert_eq!([16, 17, 0, 0, 0, 0, 0, 0], state.user_stack()); - assert_eq!(18, state.width()); + assert_eq!([15, 16, 0, 0, 0, 0, 0, 0], state.user_stack()); + assert_eq!(17, state.width()); assert_eq!(2, state.stack_depth()); assert_eq!(vec![ - 101, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 + 101, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 ], state.to_vec()); // non-empty loop stack let state = TraceState::from_vec(2, 1, 9, &vec![ - 101, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, + 101, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25 ]); assert_eq!(101, state.op_counter()); assert_eq!([1, 2, 3, 4], state.sponge()); - assert_eq!([5, 6, 7], state.cf_op_bits()); - assert_eq!([8, 9, 10, 11, 12], state.ld_op_bits()); - assert_eq!([13, 14], state.hd_op_bits()); - assert_eq!([15, 16], state.ctx_stack()); - assert_eq!([17], state.loop_stack()); - assert_eq!([18, 19, 20, 21, 22, 23, 24, 25, 26], state.user_stack()); - assert_eq!(27, state.width()); + assert_eq!([5, 6, 7], state.flow_op_bits()); + assert_eq!([8, 9, 10, 11, 12, 13], state.user_op_bits()); + assert_eq!([14, 15], state.ctx_stack()); + assert_eq!([16], state.loop_stack()); + assert_eq!([17, 18, 19, 20, 21, 22, 23, 24, 25], state.user_stack()); + assert_eq!(26, state.width()); assert_eq!(9, state.stack_depth()); assert_eq!(vec![ - 101, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, + 101, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, ], state.to_vec()); } #[test] fn update_from_trace() { let data = vec![ - 101, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 + 101, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 ]; let mut trace = Vec::with_capacity(data.len()); for i in 0..data.len() { @@ -450,13 +334,12 @@ mod tests { assert_eq!(0, state.op_counter()); assert_eq!([0, 0, 0, 0], state.sponge()); - assert_eq!([0, 0, 0], state.cf_op_bits()); - assert_eq!([0, 0, 0, 0, 0], state.ld_op_bits()); - assert_eq!([0, 0], state.hd_op_bits()); + assert_eq!([0, 0, 0], state.flow_op_bits()); + assert_eq!([0, 0, 0, 0, 0, 0], state.user_op_bits()); assert_eq!([0, 0], state.ctx_stack()); assert_eq!([0], state.loop_stack()); assert_eq!([0, 0, 0, 0, 0, 0, 0, 0], state.user_stack()); - assert_eq!(21, state.width()); + assert_eq!(20, state.width()); assert_eq!(3, state.stack_depth()); // second row @@ -464,41 +347,30 @@ mod tests { assert_eq!(101, state.op_counter()); assert_eq!([1, 2, 3, 4], state.sponge()); - assert_eq!([5, 6, 7], state.cf_op_bits()); - assert_eq!([8, 9, 10, 11, 12], state.ld_op_bits()); - assert_eq!([13, 14], state.hd_op_bits()); - assert_eq!([15, 16], state.ctx_stack()); - assert_eq!([17], state.loop_stack()); - assert_eq!([18, 19, 20, 0, 0, 0, 0, 0], state.user_stack()); - assert_eq!(21, state.width()); + assert_eq!([5, 6, 7], state.flow_op_bits()); + assert_eq!([8, 9, 10, 11, 12, 13], state.user_op_bits()); + assert_eq!([14, 15], state.ctx_stack()); + assert_eq!([16], state.loop_stack()); + assert_eq!([17, 18, 19, 0, 0, 0, 0, 0], state.user_stack()); + assert_eq!(20, state.width()); assert_eq!(3, state.stack_depth()); } - #[test] - fn op_flags() { - // TODO - } - #[test] fn op_code() { let state = TraceState::from_vec(1, 0, 2, &vec![ - 101, 1, 2, 3, 4, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 15, 16, 17 + 101, 1, 2, 3, 4, 1, 1, 1, 0, 0, 0, 0, 0, 0, 14, 15, 16 ]); assert_eq!(0, state.op_code()); let state = TraceState::from_vec(1, 0, 2, &vec![ - 101, 1, 2, 3, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 15, 16, 17 - ]); - assert_eq!(127, state.op_code()); - - let state = TraceState::from_vec(1, 0, 2, &vec![ - 101, 1, 2, 3, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 15, 16, 17 + 101, 1, 2, 3, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 14, 15, 16 ]); assert_eq!(63, state.op_code()); let state = TraceState::from_vec(1, 0, 2, &vec![ - 101, 1, 2, 3, 4, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 15, 16, 17 + 101, 1, 2, 3, 4, 1, 1, 1, 1, 1, 1, 1, 0, 0, 14, 15, 16 ]); - assert_eq!(97, state.op_code()); + assert_eq!(15, state.op_code()); } } \ No newline at end of file diff --git a/src/stark/utils/coefficients.rs b/src/stark/utils/coefficients.rs index 005d68f..bfa74bb 100644 --- a/src/stark/utils/coefficients.rs +++ b/src/stark/utils/coefficients.rs @@ -6,13 +6,13 @@ use crate::{ SPONGE_WIDTH, MAX_CONTEXT_DEPTH, MAX_LOOP_DEPTH, MAX_STACK_DEPTH, MIN_CONTEXT_DEPTH, MIN_LOOP_DEPTH, MIN_STACK_DEPTH, - NUM_CF_OP_BITS, NUM_LD_OP_BITS, NUM_HD_OP_BITS, + NUM_FLOW_OP_BITS, NUM_USER_OP_BITS, stark::constraints::{ NUM_STATIC_DECODER_CONSTRAINTS, NUM_AUX_STACK_CONSTRAINTS }, }; // CONSTANTS // ================================================================================================ -const NUM_OP_BITS: usize = NUM_CF_OP_BITS + NUM_LD_OP_BITS + NUM_HD_OP_BITS; +const NUM_OP_BITS: usize = NUM_FLOW_OP_BITS + NUM_USER_OP_BITS; const MAX_USER_STACK_IO_CONSTRAINTS: usize = MAX_PUBLIC_INPUTS; // same as MAX_OUTPUTS const NUM_BOUNDARY_CONSTRAINTS: usize = 1 // for op_counter From 84c0335e5196502960699e893384a8631b6d0081 Mon Sep 17 00:00:00 2001 From: bibbinth Date: Sat, 12 Sep 2020 00:48:00 -0700 Subject: [PATCH 4/4] updating decoder constraints - WIP commit --- src/processor/decoder/mod.rs | 2 +- src/stark/constraints/decoder/mod.rs | 13 +++++---- src/stark/constraints/decoder/op_bits.rs | 35 ++++++++++++++++-------- src/stark/constraints/evaluator.rs | 33 ++++++---------------- src/stark/constraints/stack/mod.rs | 4 +-- 5 files changed, 42 insertions(+), 45 deletions(-) diff --git a/src/processor/decoder/mod.rs b/src/processor/decoder/mod.rs index 4212929..35e4adf 100644 --- a/src/processor/decoder/mod.rs +++ b/src/processor/decoder/mod.rs @@ -248,7 +248,7 @@ impl Decoder { fill_register(&mut self.op_counter, self.step + 1, last_op_count); // set all bit registers to 0 to indicate NOOP operation - for register in self.flow_op_bits.iter_mut() { fill_register(register, self.step, field::ZERO); } + for register in self.flow_op_bits.iter_mut() { fill_register(register, self.step, field::ONE); } for register in self.user_op_bits.iter_mut() { fill_register(register, self.step, field::ZERO); } // for sponge and stack registers, just copy the value of the last state of the register diff --git a/src/stark/constraints/decoder/mod.rs b/src/stark/constraints/decoder/mod.rs index 52507af..0355a3c 100644 --- a/src/stark/constraints/decoder/mod.rs +++ b/src/stark/constraints/decoder/mod.rs @@ -29,12 +29,13 @@ mod tests; // ================================================================================================ const NUM_OP_CONSTRAINTS: usize = 15; const OP_CONSTRAINT_DEGREES: [usize; NUM_OP_CONSTRAINTS] = [ - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // all op bits are binary - 3, // op_counter should be incremented for HACC operations - 8, // ld_ops and hd_ops cannot be all 0s - 8, // when cf_ops are not all 0s, ld_ops and hd_ops must be all 1s - 6, // VOID can be followed only by VOID - 4, // operations happen on allowed step multiples + 2, 2, 2, 2, 2, 2, 2, 2, 2, // all op bits are binary + 3, // op_counter should be incremented for HACC operations + 7, // unless flow_op is HACC, user_op must be NOOP + 4, // TODO + 6, // TODO + 6, // VOID can be followed only by VOID + 4, // operations happen on allowed step multiples ]; const NUM_SPONGE_CONSTRAINTS: usize = 4; diff --git a/src/stark/constraints/decoder/op_bits.rs b/src/stark/constraints/decoder/op_bits.rs index 6b2cd4f..9e77f91 100644 --- a/src/stark/constraints/decoder/op_bits.rs +++ b/src/stark/constraints/decoder/op_bits.rs @@ -11,22 +11,22 @@ pub fn enforce_op_bits(result: &mut [u128], current: &TraceState, next: &TraceSt { let mut i = 0; - // TODO: make sure all op bits are binary and compute their product/sum - let mut cf_bit_sum = 0; + // make sure all op bits are binary and compute their product/sum + let mut flow_op_bit_sum = 0; for &op_bit in current.flow_op_bits() { result[i] = is_binary(op_bit); - cf_bit_sum = add(cf_bit_sum, op_bit); + flow_op_bit_sum = add(flow_op_bit_sum, op_bit); i += 1; } - let mut ld_bit_prod = 1; + let mut user_op_bit_prod = 1; for &op_bit in current.user_op_bits() { result[i] = is_binary(op_bit); - ld_bit_prod = mul(ld_bit_prod, op_bit); + user_op_bit_prod = mul(user_op_bit_prod, binary_not(op_bit)); i += 1; } - // when cf_ops = hacc, operation counter should be incremented by 1; + // when flow_op = HACC, operation counter should be incremented by 1; // otherwise, operation counter should remain the same let op_counter = current.op_counter(); let is_hacc = current.get_flow_op_flags(FlowOps::Hacc); @@ -35,13 +35,26 @@ pub fn enforce_op_bits(result: &mut [u128], current: &TraceState, next: &TraceSt result[i] = are_equal(add(hacc_transition, rest_transition), next.op_counter()); i += 1; - // ld_ops and hd_ops can be all 0s at the first step, but cannot be all 0s - // at any other step - result[i] = 0; // TODO mul(op_counter, mul(binary_not(ld_bit_prod), binary_not(hd_bit_prod))); + // unless flow_op is HACC, user_op must be NOOP + result[i] = mul(flow_op_bit_sum, binary_not(user_op_bit_prod)); i += 1; - // when cf_ops are not all 0s, ld_ops and hd_ops must be all 1s - result[i] = 0; // TODO mul(cf_bit_sum, binary_not(mul(ld_bit_prod, hd_bit_prod))); + // TODO: add comment + let mut low_user_op_bit_sum = current.user_op_bits()[0]; + for j in 1..4 { + low_user_op_bit_sum = add(current.user_op_bits()[j], low_user_op_bit_sum); + } + let is_one_bit = binary_not(mul(low_user_op_bit_sum, low_user_op_bit_sum)); + let is_one_bit = add(is_one_bit, current.user_op_bits()[4]); + result[i] = mul(mul(is_one_bit, current.user_op_bits()[5]), op_counter); + i += 1; + + // TODO: add comment + let mut low_user_op_bit_prod = current.user_op_bits()[0]; + for j in 1..5 { + low_user_op_bit_prod = mul(low_user_op_bit_prod, current.user_op_bits()[j]); + } + result[i] = mul(binary_not(current.user_op_bits()[5]), low_user_op_bit_prod); i += 1; // VOID can be followed only by VOID diff --git a/src/stark/constraints/evaluator.rs b/src/stark/constraints/evaluator.rs index 31f8bad..f7c8640 100644 --- a/src/stark/constraints/evaluator.rs +++ b/src/stark/constraints/evaluator.rs @@ -201,7 +201,7 @@ impl Evaluator { result_adj = field::add(result_adj, field::mul(sponge[i], cc.sponge[i * 2 + 1])); } - // make sure cf_bits are set to HACC (000) + // make sure flow op_bits are set to HACC (000) let mut cc_idx = 0; let op_bits = current.flow_op_bits(); for i in 0..op_bits.len() { @@ -210,19 +210,12 @@ impl Evaluator { cc_idx += 2; } - // make sure low-degree op_bits are set to BEGIN (0000) + // make sure user op_bits are set to BEGIN (111111) let op_bits = current.user_op_bits(); for i in 0..op_bits.len() { - i_result = field::add(i_result, field::mul(op_bits[i], cc.op_bits[cc_idx])); - result_adj = field::add(result_adj, field::mul(op_bits[i], cc.op_bits[cc_idx + 1])); - cc_idx += 2; - } - - // make sure high-degree op_bits are set to BEGIN (00) - let op_bits = current.user_op_bits(); // TODO - for i in 0..op_bits.len() { - i_result = field::add(i_result, field::mul(op_bits[i], cc.op_bits[cc_idx])); - result_adj = field::add(result_adj, field::mul(op_bits[i], cc.op_bits[cc_idx + 1])); + let val = field::sub(op_bits[i], field::ONE); + i_result = field::add(i_result, field::mul(val, cc.op_bits[cc_idx])); + result_adj = field::add(result_adj, field::mul(val, cc.op_bits[cc_idx + 1])); cc_idx += 2; } @@ -280,21 +273,11 @@ impl Evaluator { cc_idx += 2; } - // make sure low-degree op_bits are set to NOOP (11111) + // make sure user op_bits are set to NOOP (000000) let op_bits = current.user_op_bits(); for i in 0..op_bits.len() { - let val = field::sub(op_bits[i], field::ONE); - f_result = field::add(f_result, field::mul(val, cc.op_bits[cc_idx])); - result_adj = field::add(result_adj, field::mul(val, cc.op_bits[cc_idx + 1])); - cc_idx += 2; - } - - // make sure high-degree op_bits are set to NOOP (11) - let op_bits = current.user_op_bits(); // TODO - for i in 0..op_bits.len() { - let val = field::sub(op_bits[i], field::ONE); - f_result = field::add(f_result, field::mul(val, cc.op_bits[cc_idx])); - result_adj = field::add(result_adj, field::mul(val, cc.op_bits[cc_idx + 1])); + f_result = field::add(f_result, field::mul(op_bits[i], cc.op_bits[cc_idx])); + result_adj = field::add(result_adj, field::mul(op_bits[i], cc.op_bits[cc_idx + 1])); cc_idx += 2; } diff --git a/src/stark/constraints/stack/mod.rs b/src/stark/constraints/stack/mod.rs index 29ea252..078a1d6 100644 --- a/src/stark/constraints/stack/mod.rs +++ b/src/stark/constraints/stack/mod.rs @@ -37,8 +37,8 @@ use hash::{ enforce_rescr }; // CONSTANTS // ================================================================================================ pub const NUM_AUX_CONSTRAINTS: usize = 2; -const AUX_CONSTRAINT_DEGREES: [usize; NUM_AUX_CONSTRAINTS] = [7, 7]; -const STACK_TRANSITION_DEGREE: usize = 7; // degree for all stack register transition constraints +const AUX_CONSTRAINT_DEGREES: [usize; NUM_AUX_CONSTRAINTS] = [8, 7]; +const STACK_TRANSITION_DEGREE: usize = 8; // degree for all stack register transition constraints // TYPES AND INTERFACES // ================================================================================================