From 80e7a4b8fbf22854cc593a6ca7e9b538b3ad0c0b Mon Sep 17 00:00:00 2001 From: Wisdom Ogwu <40731160+iammadab@users.noreply.github.com> Date: Tue, 2 Jul 2024 00:10:30 +0100 Subject: [PATCH] Revert "refactor: uint module (#75)" (#82) This reverts commit 8ca70a9a10df1faf4f405979aee0220d53c56143. --- singer-pro/src/basic_block.rs | 2 +- singer-pro/src/basic_block/bb_final.rs | 12 +- singer-pro/src/basic_block/bb_ret.rs | 16 +- singer-pro/src/basic_block/bb_start.rs | 22 +- singer-pro/src/instructions/add.rs | 14 +- singer-pro/src/instructions/calldataload.rs | 8 +- singer-pro/src/instructions/gt.rs | 16 +- singer-pro/src/instructions/jump.rs | 6 +- singer-pro/src/instructions/jumpi.rs | 16 +- singer-pro/src/instructions/mstore.rs | 28 +- singer-pro/src/instructions/ret.rs | 14 +- singer-utils/src/chip_handler.rs | 6 +- singer-utils/src/chip_handler/range.rs | 18 +- singer-utils/src/chips/bytecode.rs | 14 +- singer-utils/src/chips/calldata.rs | 8 +- singer-utils/src/constants.rs | 1 - singer-utils/src/error.rs | 3 +- singer-utils/src/structs.rs | 8 +- singer-utils/src/uint.rs | 332 ++++++++++- singer-utils/src/uint/add_sub.rs | 341 +++++++++++ singer-utils/src/uint/arithmetic.rs | 612 -------------------- singer-utils/src/uint/cmp.rs | 189 ++++-- singer-utils/src/uint/constants.rs | 66 --- singer-utils/src/uint/uint.rs | 260 --------- singer-utils/src/uint/util.rs | 330 ----------- singer-utils/src/uint/witness_extractors.rs | 40 -- singer/src/instructions/add.rs | 41 +- singer/src/instructions/calldataload.rs | 28 +- singer/src/instructions/dup.rs | 24 +- singer/src/instructions/gt.rs | 38 +- singer/src/instructions/jump.rs | 18 +- singer/src/instructions/jumpdest.rs | 10 +- singer/src/instructions/jumpi.rs | 32 +- singer/src/instructions/mstore.rs | 48 +- singer/src/instructions/pop.rs | 20 +- singer/src/instructions/push.rs | 18 +- singer/src/instructions/ret.rs | 38 +- singer/src/instructions/swap.rs | 34 +- singer/src/test.rs | 2 +- 39 files changed, 1078 insertions(+), 1655 deletions(-) create mode 100644 singer-utils/src/uint/add_sub.rs delete mode 100644 singer-utils/src/uint/arithmetic.rs delete mode 100644 singer-utils/src/uint/constants.rs delete mode 100644 singer-utils/src/uint/uint.rs delete mode 100644 singer-utils/src/uint/util.rs delete mode 100644 singer-utils/src/uint/witness_extractors.rs diff --git a/singer-pro/src/basic_block.rs b/singer-pro/src/basic_block.rs index ee1fb8c35..c9ea30eba 100644 --- a/singer-pro/src/basic_block.rs +++ b/singer-pro/src/basic_block.rs @@ -536,7 +536,7 @@ mod test { LayerWitness::default(), LayerWitness::default(), LayerWitness { - instances: random_matrix(n_instances, PCUInt::N_OPERAND_CELLS), + instances: random_matrix(n_instances, PCUInt::N_OPRAND_CELLS), }, LayerWitness::default(), LayerWitness::default(), diff --git a/singer-pro/src/basic_block/bb_final.rs b/singer-pro/src/basic_block/bb_final.rs index 7d3b1fef6..8bcd88f69 100644 --- a/singer-pro/src/basic_block/bb_final.rs +++ b/singer-pro/src/basic_block/bb_final.rs @@ -4,7 +4,6 @@ use gkr::structs::Circuit; use itertools::Itertools; use paste::paste; use simple_frontend::structs::{CircuitBuilder, MixedCell}; -use singer_utils::uint::constants::AddSubConstants; use singer_utils::{ chip_handler::{ GlobalStateChipOperations, OAMOperations, ROMOperations, RangeChipOperations, @@ -13,6 +12,7 @@ use singer_utils::{ chips::IntoEnumIterator, register_witness, structs::{ChipChallenges, InstOutChipType, PCUInt, RAMHandler, ROMHandler, StackUInt, TSUInt}, + uint::UIntAddSub, }; use std::sync::Arc; @@ -28,7 +28,7 @@ pub struct BasicBlockFinal; register_witness!(BasicBlockFinal, phase0 { // State in related - stack_ts_add => AddSubConstants::::N_WITNESS_CELLS_NO_CARRY_OVERFLOW + stack_ts_add => UIntAddSub::::N_NO_OVERFLOW_WITNESS_CELLS }); impl BasicBlockFinal { @@ -49,12 +49,12 @@ impl BasicBlockFinal { let (phase0_wire_id, phase0) = circuit_builder.create_witness_in(Self::phase0_size()); // From BB start - let (stack_ts_id, stack_ts) = circuit_builder.create_witness_in(TSUInt::N_OPERAND_CELLS); + let (stack_ts_id, stack_ts) = circuit_builder.create_witness_in(TSUInt::N_OPRAND_CELLS); let (stack_top_id, stack_top) = circuit_builder.create_witness_in(1); let (clk_id, clk) = circuit_builder.create_witness_in(1); // From inst pc. - let (next_pc_id, next_pc) = circuit_builder.create_witness_in(PCUInt::N_OPERAND_CELLS); + let (next_pc_id, next_pc) = circuit_builder.create_witness_in(PCUInt::N_OPRAND_CELLS); let mut ram_handler = RAMHandler::new(&challenges); let mut rom_handler = ROMHandler::new(&challenges); @@ -68,7 +68,7 @@ impl BasicBlockFinal { stack_ts_add_witness, )?; - let (memory_ts_id, memory_ts) = circuit_builder.create_witness_in(TSUInt::N_OPERAND_CELLS); + let (memory_ts_id, memory_ts) = circuit_builder.create_witness_in(TSUInt::N_OPRAND_CELLS); let stack_top_expr = MixedCell::Cell(stack_top[0]); let clk_expr = MixedCell::Cell(clk[0]); ram_handler.state_out( @@ -92,7 +92,7 @@ impl BasicBlockFinal { .iter() .map(|offset| { let (stack_from_insts_id, stack_from_insts) = - circuit_builder.create_witness_in(StackUInt::N_OPERAND_CELLS); + circuit_builder.create_witness_in(StackUInt::N_OPRAND_CELLS); ram_handler.stack_push( &mut circuit_builder, stack_top_expr.add(i64_to_base_field::(*offset)), diff --git a/singer-pro/src/basic_block/bb_ret.rs b/singer-pro/src/basic_block/bb_ret.rs index 2eafaab73..18a55fd9c 100644 --- a/singer-pro/src/basic_block/bb_ret.rs +++ b/singer-pro/src/basic_block/bb_ret.rs @@ -46,7 +46,7 @@ impl BasicBlockReturn { let n_stack_items = stack_top_offsets.len(); // From BB Start - let (stack_ts_id, stack_ts) = circuit_builder.create_witness_in(TSUInt::N_OPERAND_CELLS); + let (stack_ts_id, stack_ts) = circuit_builder.create_witness_in(TSUInt::N_OPRAND_CELLS); let (stack_top_id, stack_top) = circuit_builder.create_witness_in(1); let (clk_id, _) = circuit_builder.create_witness_in(1); @@ -62,7 +62,7 @@ impl BasicBlockReturn { rom_handler.range_check_stack_top(&mut circuit_builder, stack_top_r)?; // From predesessor instruction - let (memory_ts_id, _) = circuit_builder.create_witness_in(TSUInt::N_OPERAND_CELLS); + let (memory_ts_id, _) = circuit_builder.create_witness_in(TSUInt::N_OPRAND_CELLS); let stack_operand_ids = stack_top_offsets .iter() .map(|offset| { @@ -113,8 +113,8 @@ register_witness!( BBReturnRestMemLoad, phase0 { mem_byte => 1, - old_memory_ts => TSUInt::N_OPERAND_CELLS, - offset => StackUInt::N_OPERAND_CELLS + old_memory_ts => TSUInt::N_OPRAND_CELLS, + offset => StackUInt::N_OPRAND_CELLS } ); @@ -160,7 +160,7 @@ register_witness!( BBReturnRestMemStore, phase0 { mem_byte => 1, - offset => StackUInt::N_OPERAND_CELLS + offset => StackUInt::N_OPRAND_CELLS } ); @@ -176,7 +176,7 @@ impl BBReturnRestMemStore { let offset = &phase0[Self::phase0_offset()]; let mem_byte = phase0[Self::phase0_mem_byte().start]; // memory_ts is zero. - let memory_ts = circuit_builder.create_cells(StackUInt::N_OPERAND_CELLS); + let memory_ts = circuit_builder.create_cells(StackUInt::N_OPRAND_CELLS); ram_handler.oam_store(&mut circuit_builder, offset, &memory_ts, &[mem_byte]); let (ram_load_id, ram_store_id) = ram_handler.finalize(&mut circuit_builder); @@ -206,8 +206,8 @@ pub struct BBReturnRestStackPop; register_witness!( BBReturnRestStackPop, phase0 { - old_stack_ts => TSUInt::N_OPERAND_CELLS, - stack_values => StackUInt::N_OPERAND_CELLS + old_stack_ts => TSUInt::N_OPRAND_CELLS, + stack_values => StackUInt::N_OPRAND_CELLS } ); diff --git a/singer-pro/src/basic_block/bb_start.rs b/singer-pro/src/basic_block/bb_start.rs index 2616b9076..f6a63a18b 100644 --- a/singer-pro/src/basic_block/bb_start.rs +++ b/singer-pro/src/basic_block/bb_start.rs @@ -3,7 +3,6 @@ use ff_ext::ExtensionField; use gkr::structs::Circuit; use paste::paste; use simple_frontend::structs::{CircuitBuilder, MixedCell}; -use singer_utils::uint::constants::AddSubConstants; use singer_utils::{ chip_handler::{ GlobalStateChipOperations, OAMOperations, ROMOperations, RangeChipOperations, @@ -12,6 +11,7 @@ use singer_utils::{ chips::IntoEnumIterator, register_multi_witness, structs::{ChipChallenges, InstOutChipType, PCUInt, RAMHandler, ROMHandler, StackUInt, TSUInt}, + uint::UIntCmp, }; use std::sync::Arc; @@ -27,16 +27,16 @@ pub(crate) struct BasicBlockStart; register_multi_witness!(BasicBlockStart, phase0(n_stack_items) { // State in related - pc => PCUInt::N_OPERAND_CELLS, - stack_ts => TSUInt::N_OPERAND_CELLS, - memory_ts => TSUInt::N_OPERAND_CELLS, + pc => PCUInt::N_OPRAND_CELLS, + stack_ts => TSUInt::N_OPRAND_CELLS, + memory_ts => TSUInt::N_OPRAND_CELLS, stack_top => 1, clk => 1, // Stack values - old_stack_values(n_stack_items) => StackUInt::N_OPERAND_CELLS, - old_stack_ts(n_stack_items) => TSUInt::N_OPERAND_CELLS, - old_stack_ts_lt(n_stack_items) => AddSubConstants::::N_WITNESS_CELLS_NO_CARRY_OVERFLOW + old_stack_values(n_stack_items) => StackUInt::N_OPRAND_CELLS, + old_stack_ts(n_stack_items) => TSUInt::N_OPRAND_CELLS, + old_stack_ts_lt(n_stack_items) => UIntCmp::::N_NO_OVERFLOW_WITNESS_CELLS }); impl BasicBlockStart { @@ -83,7 +83,7 @@ impl BasicBlockStart { for (i, offset) in stack_top_offsets.iter().enumerate() { let old_stack_ts = TSUInt::try_from(&phase0[Self::phase0_old_stack_ts(i, n_stack_items)])?; - TSUInt::assert_lt( + UIntCmp::::assert_lt( &mut circuit_builder, &mut rom_handler, &old_stack_ts, @@ -102,9 +102,9 @@ impl BasicBlockStart { let mut stack_result_ids = Vec::with_capacity(n_stack_items); for i in 0..n_stack_items { let (stack_operand_id, stack_operand) = - circuit_builder.create_witness_out(StackUInt::N_OPERAND_CELLS); + circuit_builder.create_witness_out(StackUInt::N_OPRAND_CELLS); let old_stack = &phase0[Self::phase0_old_stack_values(i, n_stack_items)]; - for j in 0..StackUInt::N_OPERAND_CELLS { + for j in 0..StackUInt::N_OPRAND_CELLS { circuit_builder.add(stack_operand[j], old_stack[j], E::BaseField::ONE); } stack_result_ids.push(stack_operand_id); @@ -114,7 +114,7 @@ impl BasicBlockStart { // To BB final let (out_stack_ts_id, out_stack_ts) = - circuit_builder.create_witness_out(TSUInt::N_OPERAND_CELLS); + circuit_builder.create_witness_out(TSUInt::N_OPRAND_CELLS); add_assign_each_cell(&mut circuit_builder, &out_stack_ts, stack_ts.values()); let (out_stack_top_id, out_stack_top) = circuit_builder.create_witness_out(1); circuit_builder.add(out_stack_top[0], stack_top, E::BaseField::ONE); diff --git a/singer-pro/src/instructions/add.rs b/singer-pro/src/instructions/add.rs index b9fa98d25..e136a8744 100644 --- a/singer-pro/src/instructions/add.rs +++ b/singer-pro/src/instructions/add.rs @@ -2,13 +2,13 @@ use ff_ext::ExtensionField; use gkr::structs::Circuit; use paste::paste; use simple_frontend::structs::CircuitBuilder; -use singer_utils::uint::constants::AddSubConstants; use singer_utils::{ chip_handler::ROMOperations, chips::IntoEnumIterator, constants::OpcodeType, register_witness, structs::{ChipChallenges, InstOutChipType, ROMHandler, StackUInt, TSUInt}, + uint::UIntAddSub, }; use std::sync::Arc; @@ -30,7 +30,7 @@ register_witness!( AddInstruction, phase0 { // Witness for addend_0 + addend_1 - instruction_add => AddSubConstants::::N_WITNESS_CELLS + instruction_add => UIntAddSub::::N_WITNESS_CELLS } ); @@ -44,16 +44,16 @@ impl Instruction for AddInstruction { let (phase0_wire_id, phase0) = circuit_builder.create_witness_in(Self::phase0_size()); // From predesessor instruction - let (memory_ts_id, memory_ts) = circuit_builder.create_witness_in(TSUInt::N_OPERAND_CELLS); - let (addend_0_id, addend_0) = circuit_builder.create_witness_in(StackUInt::N_OPERAND_CELLS); - let (addend_1_id, addend_1) = circuit_builder.create_witness_in(StackUInt::N_OPERAND_CELLS); + let (memory_ts_id, memory_ts) = circuit_builder.create_witness_in(TSUInt::N_OPRAND_CELLS); + let (addend_0_id, addend_0) = circuit_builder.create_witness_in(StackUInt::N_OPRAND_CELLS); + let (addend_1_id, addend_1) = circuit_builder.create_witness_in(StackUInt::N_OPRAND_CELLS); let mut rom_handler = ROMHandler::new(&challenges); // Execution result = addend0 + addend1, with carry. let addend_0 = addend_0.try_into()?; let addend_1 = addend_1.try_into()?; - let result = StackUInt::add( + let result = UIntAddSub::::add( &mut circuit_builder, &mut rom_handler, &addend_0, @@ -63,7 +63,7 @@ impl Instruction for AddInstruction { // To successor instruction let stack_result_id = circuit_builder.create_witness_out_from_cells(result.values()); let (next_memory_ts_id, next_memory_ts) = - circuit_builder.create_witness_out(TSUInt::N_OPERAND_CELLS); + circuit_builder.create_witness_out(TSUInt::N_OPRAND_CELLS); add_assign_each_cell(&mut circuit_builder, &next_memory_ts, &memory_ts); // To chips diff --git a/singer-pro/src/instructions/calldataload.rs b/singer-pro/src/instructions/calldataload.rs index 0da68e250..2d9436c32 100644 --- a/singer-pro/src/instructions/calldataload.rs +++ b/singer-pro/src/instructions/calldataload.rs @@ -28,7 +28,7 @@ pub struct CalldataloadInstruction; register_witness!( CalldataloadInstruction, phase0 { - data => StackUInt::N_OPERAND_CELLS + data => StackUInt::N_OPRAND_CELLS } ); @@ -41,8 +41,8 @@ impl Instruction for CalldataloadInstruction { // From witness let (phase0_wire_id, phase0) = circuit_builder.create_witness_in(Self::phase0_size()); // From predesessor instruction - let (memory_ts_id, memory_ts) = circuit_builder.create_witness_in(TSUInt::N_OPERAND_CELLS); - let (offset_id, offset) = circuit_builder.create_witness_in(UInt64::N_OPERAND_CELLS); + let (memory_ts_id, memory_ts) = circuit_builder.create_witness_in(TSUInt::N_OPRAND_CELLS); + let (offset_id, offset) = circuit_builder.create_witness_in(UInt64::N_OPRAND_CELLS); let mut rom_handler = ROMHandler::new(&challenges); @@ -54,7 +54,7 @@ impl Instruction for CalldataloadInstruction { let (data_copy_id, data_copy) = circuit_builder.create_witness_out(data.len()); add_assign_each_cell(&mut circuit_builder, &data_copy, &data); let (next_memory_ts_id, next_memory_ts) = - circuit_builder.create_witness_out(TSUInt::N_OPERAND_CELLS); + circuit_builder.create_witness_out(TSUInt::N_OPRAND_CELLS); add_assign_each_cell(&mut circuit_builder, &next_memory_ts, &memory_ts); // To chips diff --git a/singer-pro/src/instructions/gt.rs b/singer-pro/src/instructions/gt.rs index ea55a3dc6..99099070b 100644 --- a/singer-pro/src/instructions/gt.rs +++ b/singer-pro/src/instructions/gt.rs @@ -2,13 +2,13 @@ use ff_ext::ExtensionField; use gkr::structs::Circuit; use paste::paste; use simple_frontend::structs::CircuitBuilder; -use singer_utils::uint::constants::AddSubConstants; use singer_utils::{ chip_handler::ROMOperations, chips::IntoEnumIterator, constants::OpcodeType, register_witness, structs::{ChipChallenges, InstOutChipType, ROMHandler, StackUInt, TSUInt}, + uint::UIntCmp, }; use std::sync::Arc; @@ -28,7 +28,7 @@ register_witness!( GtInstruction, phase0 { // Witness for operand_0 > operand_1 - instruction_gt => AddSubConstants::::N_WITNESS_CELLS + instruction_gt => UIntCmp::::N_WITNESS_CELLS } ); @@ -42,18 +42,18 @@ impl Instruction for GtInstruction { let (phase0_wire_id, phase0) = circuit_builder.create_witness_in(Self::phase0_size()); // From predesessor instruction - let (memory_ts_id, memory_ts) = circuit_builder.create_witness_in(TSUInt::N_OPERAND_CELLS); + let (memory_ts_id, memory_ts) = circuit_builder.create_witness_in(TSUInt::N_OPRAND_CELLS); let (operand_0_id, operand_0) = - circuit_builder.create_witness_in(StackUInt::N_OPERAND_CELLS); + circuit_builder.create_witness_in(StackUInt::N_OPRAND_CELLS); let (operand_1_id, operand_1) = - circuit_builder.create_witness_in(StackUInt::N_OPERAND_CELLS); + circuit_builder.create_witness_in(StackUInt::N_OPRAND_CELLS); let mut rom_handler = ROMHandler::new(&challenges); // Execution operand_1 > operand_0. let operand_0 = operand_0.try_into()?; let operand_1 = operand_1.try_into()?; - let (result, _) = StackUInt::lt( + let (result, _) = UIntCmp::::lt( &mut circuit_builder, &mut rom_handler, &operand_0, @@ -62,13 +62,13 @@ impl Instruction for GtInstruction { )?; let result = [ vec![result], - circuit_builder.create_cells(StackUInt::N_OPERAND_CELLS - 1), + circuit_builder.create_cells(StackUInt::N_OPRAND_CELLS - 1), ] .concat(); // To successor instruction let stack_result_id = circuit_builder.create_witness_out_from_cells(&result); let (next_memory_ts_id, next_memory_ts) = - circuit_builder.create_witness_out(TSUInt::N_OPERAND_CELLS); + circuit_builder.create_witness_out(TSUInt::N_OPRAND_CELLS); add_assign_each_cell(&mut circuit_builder, &next_memory_ts, &memory_ts); // To chips diff --git a/singer-pro/src/instructions/jump.rs b/singer-pro/src/instructions/jump.rs index fd3919de9..e297230f9 100644 --- a/singer-pro/src/instructions/jump.rs +++ b/singer-pro/src/instructions/jump.rs @@ -27,8 +27,8 @@ impl Instruction for JumpInstruction { fn construct_circuit(_: ChipChallenges) -> Result, ZKVMError> { let mut circuit_builder = CircuitBuilder::new(); // From predesessor instruction - let (memory_ts_id, memory_ts) = circuit_builder.create_witness_in(TSUInt::N_OPERAND_CELLS); - let (next_pc_id, next_pc) = circuit_builder.create_witness_in(StackUInt::N_OPERAND_CELLS); + let (memory_ts_id, memory_ts) = circuit_builder.create_witness_in(TSUInt::N_OPRAND_CELLS); + let (next_pc_id, next_pc) = circuit_builder.create_witness_in(StackUInt::N_OPRAND_CELLS); // To BB final let (next_pc_copy_id, next_pc_copy) = circuit_builder.create_witness_out(next_pc.len()); @@ -36,7 +36,7 @@ impl Instruction for JumpInstruction { // To Succesor instruction let (next_memory_ts_id, next_memory_ts) = - circuit_builder.create_witness_out(TSUInt::N_OPERAND_CELLS); + circuit_builder.create_witness_out(TSUInt::N_OPRAND_CELLS); add_assign_each_cell(&mut circuit_builder, &next_memory_ts, &memory_ts); // To chips diff --git a/singer-pro/src/instructions/jumpi.rs b/singer-pro/src/instructions/jumpi.rs index a9855e4d4..3ab9ef735 100644 --- a/singer-pro/src/instructions/jumpi.rs +++ b/singer-pro/src/instructions/jumpi.rs @@ -30,9 +30,9 @@ impl InstructionGraph for JumpiInstruction { register_witness!( JumpiInstruction, phase0 { - pc_plus_1 => PCUInt::N_OPERAND_CELLS, + pc_plus_1 => PCUInt::N_OPRAND_CELLS, pc_plus_1_opcode => 1, - cond_values_inv => StackUInt::N_OPERAND_CELLS, + cond_values_inv => StackUInt::N_OPRAND_CELLS, cond_non_zero_or_inv => 1 } ); @@ -47,10 +47,10 @@ impl Instruction for JumpiInstruction { let (phase0_wire_id, phase0) = circuit_builder.create_witness_in(Self::phase0_size()); // From predesessor instruction - let (memory_ts_id, memory_ts) = circuit_builder.create_witness_in(TSUInt::N_OPERAND_CELLS); - let (dest_id, dest) = circuit_builder.create_witness_in(StackUInt::N_OPERAND_CELLS); + let (memory_ts_id, memory_ts) = circuit_builder.create_witness_in(TSUInt::N_OPRAND_CELLS); + let (dest_id, dest) = circuit_builder.create_witness_in(StackUInt::N_OPRAND_CELLS); let (cond_values_id, cond_values) = - circuit_builder.create_witness_in(StackUInt::N_OPERAND_CELLS); + circuit_builder.create_witness_in(StackUInt::N_OPRAND_CELLS); let mut rom_handler = ROMHandler::new(&challenges); @@ -71,8 +71,8 @@ impl Instruction for JumpiInstruction { // If cond_non_zero, next_pc = dest, otherwise, pc = pc + 1 let pc_plus_1 = &phase0[Self::phase0_pc_plus_1()]; - let (next_pc_id, next_pc) = circuit_builder.create_witness_out(PCUInt::N_OPERAND_CELLS); - for i in 0..PCUInt::N_OPERAND_CELLS { + let (next_pc_id, next_pc) = circuit_builder.create_witness_out(PCUInt::N_OPRAND_CELLS); + for i in 0..PCUInt::N_OPRAND_CELLS { circuit_builder.select(next_pc[i], pc_plus_1[i], dest[i], cond_non_zero); } @@ -90,7 +90,7 @@ impl Instruction for JumpiInstruction { // To successor instruction let (next_memory_ts_id, next_memory_ts) = - circuit_builder.create_witness_out(TSUInt::N_OPERAND_CELLS); + circuit_builder.create_witness_out(TSUInt::N_OPRAND_CELLS); add_assign_each_cell(&mut circuit_builder, &next_memory_ts, &memory_ts); let rom_id = rom_handler.finalize(&mut circuit_builder); diff --git a/singer-pro/src/instructions/mstore.rs b/singer-pro/src/instructions/mstore.rs index be309a1ce..dcc290c7e 100644 --- a/singer-pro/src/instructions/mstore.rs +++ b/singer-pro/src/instructions/mstore.rs @@ -4,13 +4,13 @@ use gkr_graph::structs::{CircuitGraphBuilder, NodeOutputType, PredType}; use itertools::Itertools; use paste::paste; use simple_frontend::structs::CircuitBuilder; -use singer_utils::uint::constants::AddSubConstants; use singer_utils::{ chip_handler::{MemoryChipOperations, ROMOperations, RangeChipOperations}, chips::{IntoEnumIterator, SingerChipBuilder}, constants::{OpcodeType, EVM_STACK_BYTE_WIDTH}, register_witness, structs::{ChipChallenges, InstOutChipType, RAMHandler, ROMHandler, StackUInt, TSUInt}, + uint::{UIntAddSub, UIntCmp}, }; use std::{mem, sync::Arc}; @@ -111,7 +111,7 @@ impl InstructionGraph for MstoreInstruction { register_witness!( MstoreInstruction, phase0 { - memory_ts_add => AddSubConstants::::N_WITNESS_CELLS_NO_CARRY_OVERFLOW, + memory_ts_add => UIntAddSub::::N_NO_OVERFLOW_WITNESS_CELLS, mem_bytes => EVM_STACK_BYTE_WIDTH } ); @@ -125,10 +125,10 @@ impl Instruction for MstoreInstruction { let (phase0_wire_id, phase0) = circuit_builder.create_witness_in(Self::phase0_size()); // From predesessor instruction - let (memory_ts_id, memory_ts) = circuit_builder.create_witness_in(TSUInt::N_OPERAND_CELLS); - let (offset_id, offset) = circuit_builder.create_witness_in(StackUInt::N_OPERAND_CELLS); + let (memory_ts_id, memory_ts) = circuit_builder.create_witness_in(TSUInt::N_OPRAND_CELLS); + let (offset_id, offset) = circuit_builder.create_witness_in(StackUInt::N_OPRAND_CELLS); let (mem_value_id, mem_values) = - circuit_builder.create_witness_in(StackUInt::N_OPERAND_CELLS); + circuit_builder.create_witness_in(StackUInt::N_OPRAND_CELLS); let mut rom_handler = ROMHandler::new(&challenges); @@ -150,8 +150,8 @@ impl Instruction for MstoreInstruction { let mem_values = StackUInt::try_from(mem_values.as_slice())?; let mem_values_from_bytes = - StackUInt::from_bytes_big_endian(&mut circuit_builder, &mem_bytes)?; - StackUInt::assert_eq(&mut circuit_builder, &mem_values_from_bytes, &mem_values)?; + StackUInt::from_bytes_big_endien(&mut circuit_builder, &mem_bytes)?; + UIntCmp::::assert_eq(&mut circuit_builder, &mem_values_from_bytes, &mem_values)?; // To chips. let rom_id = rom_handler.finalize(&mut circuit_builder); @@ -211,17 +211,17 @@ pub struct MstoreAccessory; register_witness!( MstoreAccessory, pred_dup { - memory_ts => TSUInt::N_OPERAND_CELLS, - offset => StackUInt::N_OPERAND_CELLS + memory_ts => TSUInt::N_OPRAND_CELLS, + offset => StackUInt::N_OPRAND_CELLS }, pred_ooo { mem_byte => 1 }, phase0 { - old_memory_ts => TSUInt::N_OPERAND_CELLS, - old_memory_ts_lt => AddSubConstants::::N_WITNESS_CELLS_NO_CARRY_OVERFLOW, + old_memory_ts => TSUInt::N_OPRAND_CELLS, + old_memory_ts_lt => UIntCmp::::N_NO_OVERFLOW_WITNESS_CELLS, - offset_add_delta => AddSubConstants::::N_WITNESS_CELLS, + offset_add_delta => UIntAddSub::::N_WITNESS_CELLS, prev_mem_byte => 1 } ); @@ -250,14 +250,14 @@ impl MstoreAccessory { let offset = StackUInt::try_from(&pred_dup[Self::pred_dup_offset()])?; let offset_add_delta = &phase0[Self::phase0_offset_add_delta()]; let delta = circuit_builder.create_counter_in(0)[0]; - let offset_plus_delta = StackUInt::add_cell( + let offset_plus_delta = UIntAddSub::::add_small( &mut circuit_builder, &mut rom_handler, &offset, delta, offset_add_delta, )?; - TSUInt::assert_lt( + UIntCmp::::assert_lt( &mut circuit_builder, &mut rom_handler, &old_memory_ts, diff --git a/singer-pro/src/instructions/ret.rs b/singer-pro/src/instructions/ret.rs index 84ea49685..605475560 100644 --- a/singer-pro/src/instructions/ret.rs +++ b/singer-pro/src/instructions/ret.rs @@ -3,13 +3,13 @@ use gkr::structs::Circuit; use gkr_graph::structs::{CircuitGraphBuilder, NodeOutputType, PredType}; use paste::paste; use simple_frontend::structs::CircuitBuilder; -use singer_utils::uint::constants::AddSubConstants; use singer_utils::{ chip_handler::{OAMOperations, ROMOperations}, chips::{IntoEnumIterator, SingerChipBuilder}, constants::OpcodeType, register_witness, structs::{ChipChallenges, InstOutChipType, RAMHandler, ROMHandler, StackUInt, TSUInt}, + uint::UIntAddSub, }; use std::{mem, sync::Arc}; @@ -110,8 +110,8 @@ register_witness!( byte => 1 }, phase0 { - old_memory_ts => TSUInt::N_OPERAND_CELLS, - offset_add => AddSubConstants::::N_WITNESS_CELLS + old_memory_ts => TSUInt::N_OPRAND_CELLS, + offset_add => UIntAddSub::::N_WITNESS_CELLS } ); @@ -128,8 +128,8 @@ impl Instruction for ReturnInstruction { let (phase0_wire_id, phase0) = circuit_builder.create_witness_in(Self::phase0_size()); // From predesessor instruction - let (memory_ts_id, memory_ts) = circuit_builder.create_witness_in(TSUInt::N_OPERAND_CELLS); - let (offset_id, offset) = circuit_builder.create_witness_in(StackUInt::N_OPERAND_CELLS); + let (memory_ts_id, memory_ts) = circuit_builder.create_witness_in(TSUInt::N_OPRAND_CELLS); + let (offset_id, offset) = circuit_builder.create_witness_in(StackUInt::N_OPRAND_CELLS); let mut rom_handler = ROMHandler::new(&challenges); let mut ram_handler = RAMHandler::new(&challenges); @@ -138,7 +138,7 @@ impl Instruction for ReturnInstruction { let delta = circuit_builder.create_counter_in(0)[0]; let offset = StackUInt::try_from(offset.as_slice())?; let offset_add_delta = &phase0[Self::phase0_offset_add()]; - let offset_plus_delta = StackUInt::add_cell( + let offset_plus_delta = UIntAddSub::::add_small( &mut circuit_builder, &mut rom_handler, &offset, @@ -160,7 +160,7 @@ impl Instruction for ReturnInstruction { // To successor instruction let (next_memory_ts_id, next_memory_ts) = - circuit_builder.create_witness_out(TSUInt::N_OPERAND_CELLS); + circuit_builder.create_witness_out(TSUInt::N_OPRAND_CELLS); add_assign_each_cell(&mut circuit_builder, &next_memory_ts, memory_ts.values()); let (ram_load_id, ram_store_id) = ram_handler.finalize(&mut circuit_builder); diff --git a/singer-utils/src/chip_handler.rs b/singer-utils/src/chip_handler.rs index b8cb096ad..c9268a116 100644 --- a/singer-utils/src/chip_handler.rs +++ b/singer-utils/src/chip_handler.rs @@ -1,7 +1,11 @@ use ff_ext::ExtensionField; use simple_frontend::structs::{CellId, ChallengeId, CircuitBuilder, MixedCell, WitnessId}; -use crate::{constants::OpcodeType, error::UtilError, structs::ChipChallenges, uint::UInt}; +use crate::{ + constants::OpcodeType, + error::UtilError, + structs::{ChipChallenges, UInt}, +}; pub mod bytecode; pub mod calldata; diff --git a/singer-utils/src/chip_handler/range.rs b/singer-utils/src/chip_handler/range.rs index 1f6f37896..fdc6081b8 100644 --- a/singer-utils/src/chip_handler/range.rs +++ b/singer-utils/src/chip_handler/range.rs @@ -5,8 +5,8 @@ use simple_frontend::structs::{CellId, CircuitBuilder, MixedCell}; use crate::{ constants::{RANGE_CHIP_BIT_WIDTH, STACK_TOP_BIT_WIDTH}, error::UtilError, - structs::{PCUInt, ROMHandler, TSUInt}, - uint::UInt, + structs::{PCUInt, ROMHandler, TSUInt, UInt}, + uint::UIntAddSub, }; use super::{ROMOperations, RangeChipOperations}; @@ -40,8 +40,7 @@ impl RangeChipOperations for ROMHandler { Ok((*uint).clone()) } else if let Some(range_values) = range_value_witness { let range_value = UInt::::from_range_values(circuit_builder, range_values)?; - // TODO: use the self paradigm here - UInt::::assert_eq(circuit_builder, uint, &range_value)?; + uint.assert_eq(circuit_builder, &range_value); let b: usize = M.min(C); let chunk_size = (b + RANGE_CHIP_BIT_WIDTH - 1) / RANGE_CHIP_BIT_WIDTH; for chunk in range_values.chunks(chunk_size) { @@ -99,9 +98,8 @@ impl ROMHandler { constant: i64, witness: &[CellId], ) -> Result { - // TODO: why unsafe here? - let carry = PCUInt::extract_unsafe_carry_add_sub(witness); - PCUInt::add_const_unsafe( + let carry = UIntAddSub::::extract_unsafe_carry(witness); + UIntAddSub::::add_const_unsafe( circuit_builder, &pc, i64_to_base_field::(constant), @@ -116,10 +114,8 @@ impl ROMHandler { constant: i64, witness: &[CellId], ) -> Result { - // TODO: why safe but with unsafe carry - // TODO: there must be a bug here - // let carry = TSUInt::extract_unsafe_carry(witness); - TSUInt::add_const( + //let carry = UIntAddSub::::extract_unsafe_carry(witness); + UIntAddSub::::add_const( circuit_builder, self, &ts, diff --git a/singer-utils/src/chips/bytecode.rs b/singer-utils/src/chips/bytecode.rs index 314b3afa1..20ef83126 100644 --- a/singer-utils/src/chips/bytecode.rs +++ b/singer-utils/src/chips/bytecode.rs @@ -17,7 +17,7 @@ use super::ChipCircuitGadgets; fn construct_circuit(challenges: &ChipChallenges) -> Arc> { let mut circuit_builder = CircuitBuilder::::new(); - let (_, pc_cells) = circuit_builder.create_witness_in(PCUInt::N_OPERAND_CELLS); + let (_, pc_cells) = circuit_builder.create_witness_in(PCUInt::N_OPRAND_CELLS); let (_, bytecode_cells) = circuit_builder.create_witness_in(1); let mut rom_handler = ROMHandler::new(&challenges); @@ -51,8 +51,16 @@ pub(crate) fn construct_bytecode_table_and_witness( let wits_in = vec![ LayerWitness { instances: PCUInt::counter_vector::(bytecode.len().next_power_of_two()) - }; - 2 + .into_iter() + .map(|x| vec![x]) + .collect_vec(), + }, + LayerWitness { + instances: bytecode + .iter() + .map(|x| vec![E::BaseField::from(*x as u64)]) + .collect_vec(), + }, ]; let table_node_id = builder.add_node_with_witness( diff --git a/singer-utils/src/chips/calldata.rs b/singer-utils/src/chips/calldata.rs index 2968ea0f2..cc2f8f187 100644 --- a/singer-utils/src/chips/calldata.rs +++ b/singer-utils/src/chips/calldata.rs @@ -16,8 +16,8 @@ use sumcheck::util::ceil_log2; fn construct_circuit(challenges: &ChipChallenges) -> Arc> { let mut circuit_builder = CircuitBuilder::::new(); - let (_, id_cells) = circuit_builder.create_witness_in(UInt64::N_OPERAND_CELLS); - let (_, calldata_cells) = circuit_builder.create_witness_in(StackUInt::N_OPERAND_CELLS); + let (_, id_cells) = circuit_builder.create_witness_in(UInt64::N_OPRAND_CELLS); + let (_, calldata_cells) = circuit_builder.create_witness_in(StackUInt::N_OPRAND_CELLS); let mut rom_handler = ROMHandler::new(&challenges); rom_handler.calldataload(&mut circuit_builder, &id_cells, &calldata_cells); let _ = rom_handler.finalize(&mut circuit_builder); @@ -58,9 +58,9 @@ pub(crate) fn construct_calldata_table_and_witness( }, LayerWitness { instances: (0..calldata.len()) - .step_by(StackUInt::N_OPERAND_CELLS) + .step_by(StackUInt::N_OPRAND_CELLS) .map(|i| { - calldata[i..(i + StackUInt::N_OPERAND_CELLS).min(calldata.len())] + calldata[i..(i + StackUInt::N_OPRAND_CELLS).min(calldata.len())] .iter() .cloned() .rev() diff --git a/singer-utils/src/constants.rs b/singer-utils/src/constants.rs index 7427f4a62..c6d78b49e 100644 --- a/singer-utils/src/constants.rs +++ b/singer-utils/src/constants.rs @@ -2,7 +2,6 @@ use strum_macros::EnumIter; pub const STACK_TOP_BIT_WIDTH: usize = 10; -pub const BYTE_BIT_WIDTH: usize = 8; pub const RANGE_CHIP_BIT_WIDTH: usize = 16; pub const VALUE_BIT_WIDTH: usize = 32; pub const EVM_STACK_BIT_WIDTH: usize = 256; diff --git a/singer-utils/src/error.rs b/singer-utils/src/error.rs index 2c17c10b0..91832a141 100644 --- a/singer-utils/src/error.rs +++ b/singer-utils/src/error.rs @@ -4,8 +4,7 @@ use gkr_graph::error::GKRGraphError; pub enum UtilError { ChipError, ChipHandlerError, - // TODO: consider splitting this into smaller errors - UIntError(String), + UIntError, GKRGraphError(GKRGraphError), } diff --git a/singer-utils/src/structs.rs b/singer-utils/src/structs.rs index 48ee0efdc..e21b432bf 100644 --- a/singer-utils/src/structs.rs +++ b/singer-utils/src/structs.rs @@ -1,10 +1,8 @@ use ff_ext::ExtensionField; use simple_frontend::structs::{CellId, ChallengeId, ExtCellId}; use strum_macros::EnumIter; -use uint::UInt; use crate::constants::{EVM_STACK_BIT_WIDTH, VALUE_BIT_WIDTH}; -use crate::uint; #[derive(Clone, Debug, Copy, EnumIter)] pub enum RAMType { @@ -48,6 +46,12 @@ pub struct ROMHandler { pub(crate) challenge: ChipChallenges, } +/// Unsigned integer with `M` bits. C denotes the cell bit width. +#[derive(Clone, Debug)] +pub struct UInt { + pub(crate) values: Vec, +} + pub type UInt64 = UInt<64, VALUE_BIT_WIDTH>; pub type PCUInt = UInt64; pub type TSUInt = UInt<56, 56>; diff --git a/singer-utils/src/uint.rs b/singer-utils/src/uint.rs index 1bf0190f0..09dade8f2 100644 --- a/singer-utils/src/uint.rs +++ b/singer-utils/src/uint.rs @@ -1,7 +1,325 @@ -mod arithmetic; -mod cmp; -pub mod constants; -mod uint; -pub use uint::UInt; -pub mod util; -mod witness_extractors; +use ff::Field; +use ff_ext::ExtensionField; +use goldilocks::SmallField; +use itertools::Itertools; +use simple_frontend::structs::{CellId, CircuitBuilder}; +use std::marker::PhantomData; +use sumcheck::util::ceil_log2; + +use crate::{constants::RANGE_CHIP_BIT_WIDTH, error::UtilError, structs::UInt}; + +pub mod add_sub; +pub mod cmp; + +impl TryFrom<&[usize]> for UInt { + type Error = UtilError; + fn try_from(values: &[usize]) -> Result { + if values.len() != Self::N_OPRAND_CELLS { + panic!( + "expected = {}, got = {}", + Self::N_OPRAND_CELLS, + values.len() + ); + } + Ok(Self { + values: values.to_vec(), + }) + } +} + +impl TryFrom> for UInt { + type Error = UtilError; + fn try_from(values: Vec) -> Result { + let values = values.as_slice().try_into()?; + Ok(values) + } +} + +impl UInt { + pub const N_OPRAND_CELLS: usize = (M + C - 1) / C; + + const N_CARRY_CELLS: usize = Self::N_OPRAND_CELLS; + const N_CARRY_NO_OVERFLOW_CELLS: usize = Self::N_OPRAND_CELLS - 1; + pub const N_RANGE_CHECK_CELLS: usize = + Self::N_OPRAND_CELLS * ((C + RANGE_CHIP_BIT_WIDTH - 1) / RANGE_CHIP_BIT_WIDTH); + pub const N_RANGE_CHECK_NO_OVERFLOW_CELLS: usize = + (Self::N_OPRAND_CELLS - 1) * ((C + RANGE_CHIP_BIT_WIDTH - 1) / RANGE_CHIP_BIT_WIDTH); + + pub fn values(&self) -> &[CellId] { + &self.values + } + + pub fn from_range_values( + circuit_builder: &mut CircuitBuilder, + range_values: &[CellId], + ) -> Result { + let mut values = if C <= M { + convert_decomp(circuit_builder, range_values, RANGE_CHIP_BIT_WIDTH, C, true) + } else { + convert_decomp(circuit_builder, range_values, RANGE_CHIP_BIT_WIDTH, M, true) + }; + while values.len() < Self::N_OPRAND_CELLS { + values.push(circuit_builder.create_cell()); + } + Self::try_from(values) + } + + pub fn from_bytes_big_endien( + circuit_builder: &mut CircuitBuilder, + bytes: &[CellId], + ) -> Result { + let mut values = if C <= M { + convert_decomp(circuit_builder, bytes, 8, C, true) + } else { + convert_decomp(circuit_builder, bytes, 8, M, true) + }; + while values.len() < Self::N_OPRAND_CELLS { + values.push(circuit_builder.create_cell()); + } + Self::try_from(values) + } + + pub fn assert_eq( + &self, + circuit_builder: &mut CircuitBuilder, + other: &Self, + ) { + for i in 0..self.values.len() { + let diff = circuit_builder.create_cell(); + circuit_builder.add(diff, self.values[i], E::BaseField::ONE); + circuit_builder.add(diff, other.values[i], -E::BaseField::ONE); + circuit_builder.assert_const(diff, 0); + } + } + + pub fn assert_eq_range_values( + &self, + circuit_builder: &mut CircuitBuilder, + range_values: &[CellId], + ) { + let values = if C <= M { + convert_decomp(circuit_builder, range_values, RANGE_CHIP_BIT_WIDTH, C, true) + } else { + convert_decomp(circuit_builder, range_values, RANGE_CHIP_BIT_WIDTH, M, true) + }; + let length = self.values.len().min(values.len()); + for i in 0..length { + let diff = circuit_builder.create_cell(); + circuit_builder.add(diff, self.values[i], E::BaseField::ONE); + circuit_builder.add(diff, values[i], -E::BaseField::ONE); + circuit_builder.assert_const(diff, 0); + } + for i in length..values.len() { + circuit_builder.assert_const(values[i], 0); + } + for i in length..self.values.len() { + circuit_builder.assert_const(self.values[i], 0); + } + } + + /// Generate (0, 1, ..., size) + pub fn counter_vector(size: usize) -> Vec { + let num_vars = ceil_log2(size); + let tensor = |a: &[F], b: Vec| { + let mut res = vec![F::ZERO; a.len() * b.len()]; + for i in 0..b.len() { + for j in 0..a.len() { + res[i * a.len() + j] = b[i] * a[j]; + } + } + res + }; + let counter = (0..(1 << C)).map(|x| F::from(x as u64)).collect_vec(); + let (di, mo) = (num_vars / C, num_vars % C); + let mut res = (0..(1 << mo)).map(|x| F::from(x as u64)).collect_vec(); + for _ in 0..di { + res = tensor(&counter, res); + } + res + } +} + +pub struct UIntAddSub { + _phantom: PhantomData, +} +pub struct UIntCmp { + _phantom: PhantomData, +} + +/// Big-endian bytes to little-endien field values. We don't require +/// `BIG_BIT_WIDTH` % `SMALL_BIT_WIDTH` == 0 because we assume `small_values` +/// can be splitted into chunks with size ceil(BIG_BIT_WIDTH / SMALL_BIT_WIDTH). +/// Each chunk is converted to a value with BIG_BIT_WIDTH bits. +fn convert_decomp( + circuit_builder: &mut CircuitBuilder, + small_values: &[CellId], + small_bit_width: usize, + big_bit_width: usize, + is_little_endian: bool, +) -> Vec { + let small_values = if is_little_endian { + small_values.to_vec() + } else { + small_values.iter().rev().map(|x: &usize| *x).collect_vec() + }; + let chunk_size = (big_bit_width + small_bit_width - 1) / small_bit_width; + let small_len = small_values.len(); + let values = (0..small_len) + .step_by(chunk_size) + .map(|j| { + let tmp = circuit_builder.create_cell(); + for k in j..(j + chunk_size).min(small_len) { + let k = k as usize; + circuit_builder.add( + tmp, + small_values[k], + E::BaseField::from((1 as u64) << (k - j) * small_bit_width), + ); + } + tmp + }) + .collect_vec(); + values +} + +#[cfg(test)] +mod test { + use crate::uint::convert_decomp; + + use super::UInt; + use gkr::structs::{Circuit, CircuitWitness}; + use goldilocks::{Goldilocks, GoldilocksExt2}; + use simple_frontend::structs::CircuitBuilder; + + #[test] + fn test_convert_decomp() { + // test case 1 + let mut circuit_builder = CircuitBuilder::::new(); + let big_bit_width = 3; + let small_bit_width = 2; + let (small_values_wire_in_id, small_values) = circuit_builder.create_witness_in(31); + let values = convert_decomp( + &mut circuit_builder, + &small_values, + small_bit_width, + big_bit_width, + true, + ); + assert_eq!(values.len(), 16); + circuit_builder.configure(); + let circuit = Circuit::new(&circuit_builder); + let n_witness_in = circuit.n_witness_in; + let mut wires_in = vec![vec![]; n_witness_in]; + wires_in[small_values_wire_in_id as usize] = + vec![Goldilocks::from(1u64), Goldilocks::from(1u64)]; + wires_in[small_values_wire_in_id as usize].extend(vec![Goldilocks::from(0u64); 29]); + let circuit_witness = { + let challenges = vec![GoldilocksExt2::from(2)]; + let mut circuit_witness = CircuitWitness::new(&circuit, challenges); + circuit_witness.add_instance(&circuit, wires_in); + circuit_witness + }; + #[cfg(feature = "test-dbg")] + println!("{:?}", circuit_witness); + circuit_witness.check_correctness(&circuit); + // check the result + let result_values = circuit_witness.output_layer_witness_ref(); + assert_eq!(result_values.instances[0][0], Goldilocks::from(5u64)); + for i in 1..16 { + assert_eq!(result_values.instances[0][i], Goldilocks::from(0u64)); + } + // test case 2 + let mut circuit_builder = CircuitBuilder::::new(); + let big_bit_width = 32; + let small_bit_width = 16; + let (small_values_wire_in_id, small_values) = circuit_builder.create_witness_in(4); + let values = convert_decomp( + &mut circuit_builder, + &small_values, + small_bit_width, + big_bit_width, + true, + ); + assert_eq!(values.len(), 2); + circuit_builder.configure(); + let circuit = Circuit::new(&circuit_builder); + let n_witness_in = circuit.n_witness_in; + let mut wires_in = vec![vec![]; n_witness_in]; + wires_in[small_values_wire_in_id as usize] = vec![ + Goldilocks::from(0u64), + Goldilocks::from(0u64), + Goldilocks::from(1u64), + Goldilocks::from(0u64), + ]; + let circuit_witness = { + let challenges = vec![GoldilocksExt2::from(2)]; + let mut circuit_witness = CircuitWitness::new(&circuit, challenges); + circuit_witness.add_instance(&circuit, wires_in); + circuit_witness + }; + #[cfg(feature = "test-dbg")] + println!("{:?}", circuit_witness); + circuit_witness.check_correctness(&circuit); + // check the result + let result_values = circuit_witness.output_layer_witness_ref(); + assert_eq!( + result_values.instances[0], + vec![Goldilocks::from(0u64), Goldilocks::from(1u64)] + ); + } + + #[test] + fn test_from_range_values() { + let mut circuit_builder = CircuitBuilder::::new(); + let (range_values_wire_in_id, range_values) = circuit_builder.create_witness_in(16); + let range_value = + UInt::<256, 32>::from_range_values(&mut circuit_builder, &range_values).unwrap(); + assert_eq!(range_value.values.len(), 8); + circuit_builder.configure(); + let circuit = Circuit::new(&circuit_builder); + let n_witness_in = circuit.n_witness_in; + let mut wires_in = vec![vec![]; n_witness_in]; + wires_in[range_values_wire_in_id as usize] = vec![ + Goldilocks::from(0u64), + Goldilocks::from(0u64), + Goldilocks::from(1u64), + Goldilocks::from(0u64), + Goldilocks::from(0u64), + Goldilocks::from(0u64), + Goldilocks::from(0u64), + Goldilocks::from(0u64), + Goldilocks::from(0u64), + Goldilocks::from(0u64), + Goldilocks::from(0u64), + Goldilocks::from(0u64), + Goldilocks::from(0u64), + Goldilocks::from(0u64), + Goldilocks::from(0u64), + Goldilocks::from(0u64), + ]; + let circuit_witness = { + let challenges = vec![GoldilocksExt2::from(2)]; + let mut circuit_witness = CircuitWitness::new(&circuit, challenges); + circuit_witness.add_instance(&circuit, wires_in); + circuit_witness + }; + #[cfg(feature = "test-dbg")] + println!("{:?}", circuit_witness); + circuit_witness.check_correctness(&circuit); + // check the result + let result_values = circuit_witness.output_layer_witness_ref(); + assert_eq!( + result_values.instances[0], + vec![ + Goldilocks::from(0), + Goldilocks::from(1), + Goldilocks::from(0), + Goldilocks::from(0), + Goldilocks::from(0), + Goldilocks::from(0), + Goldilocks::from(0), + Goldilocks::from(0), + ] + ); + } +} diff --git a/singer-utils/src/uint/add_sub.rs b/singer-utils/src/uint/add_sub.rs new file mode 100644 index 000000000..48e02ce3f --- /dev/null +++ b/singer-utils/src/uint/add_sub.rs @@ -0,0 +1,341 @@ +use ff::Field; +use ff_ext::ExtensionField; +use simple_frontend::structs::{CellId, CircuitBuilder}; + +use crate::{chip_handler::RangeChipOperations, error::UtilError, structs::UInt}; + +use super::UIntAddSub; + +impl UIntAddSub> { + pub const N_NO_OVERFLOW_WITNESS_CELLS: usize = + UInt::::N_RANGE_CHECK_CELLS + UInt::::N_CARRY_NO_OVERFLOW_CELLS; + pub const N_NO_OVERFLOW_WITNESS_UNSAFE_CELLS: usize = UInt::::N_CARRY_NO_OVERFLOW_CELLS; + + pub const N_WITNESS_UNSAFE_CELLS: usize = UInt::::N_CARRY_CELLS; + pub const N_WITNESS_CELLS: usize = + UInt::::N_RANGE_CHECK_CELLS + UInt::::N_CARRY_CELLS; + + pub fn extract_range_values(witness: &[CellId]) -> &[CellId] { + &witness[..UInt::::N_RANGE_CHECK_CELLS] + } + + pub fn extract_range_values_no_overflow(witness: &[CellId]) -> &[CellId] { + &witness[..UInt::::N_RANGE_CHECK_NO_OVERFLOW_CELLS] + } + + pub fn extract_carry_no_overflow(witness: &[CellId]) -> &[CellId] { + &witness[UInt::::N_RANGE_CHECK_NO_OVERFLOW_CELLS..] + } + + pub fn extract_carry(witness: &[CellId]) -> &[CellId] { + &witness[UInt::::N_RANGE_CHECK_CELLS..] + } + + pub fn extract_unsafe_carry(witness: &[CellId]) -> &[CellId] { + witness + } + + /// Little-endian addition. Assume users to check the correct range of the + /// result by themselves. + pub fn add_unsafe( + circuit_builder: &mut CircuitBuilder, + addend_0: &UInt, + addend_1: &UInt, + carry: &[CellId], + ) -> Result, UtilError> { + let result: UInt = circuit_builder + .create_cells(UInt::::N_OPRAND_CELLS) + .try_into()?; + for i in 0..UInt::::N_OPRAND_CELLS { + let (a, b, result) = (addend_0.values[i], addend_1.values[i], result.values[i]); + // result = addend_0 + addend_1 + last_carry - carry * (1 << VALUE_BIT_WIDTH) + circuit_builder.add(result, a, Ext::BaseField::ONE); + circuit_builder.add(result, b, Ext::BaseField::ONE); + // It is equivalent to pad carry with 0s. + if i < carry.len() { + circuit_builder.add(result, carry[i], -Ext::BaseField::from(1 << C)); + } + if i > 0 && i - 1 < carry.len() { + circuit_builder.add(result, carry[i - 1], Ext::BaseField::ONE); + } + } + Ok(result) + } + + /// Little-endian addition. + pub fn add>( + circuit_builder: &mut CircuitBuilder, + range_chip_handler: &mut H, + addend_0: &UInt, + addend_1: &UInt, + witness: &[CellId], + ) -> Result, UtilError> { + let carry = Self::extract_carry(witness); + let range_values = Self::extract_range_values(witness); + let computed_result = Self::add_unsafe(circuit_builder, addend_0, addend_1, carry)?; + range_chip_handler.range_check_uint(circuit_builder, &computed_result, Some(range_values)) + } + + /// Little-endian addition with a constant. Assume users to check the + /// correct range of the result by themselves. + pub fn add_const_unsafe( + circuit_builder: &mut CircuitBuilder, + addend_0: &UInt, + constant: Ext::BaseField, + carry: &[CellId], + ) -> Result, UtilError> { + let result: UInt = circuit_builder + .create_cells(UInt::::N_OPRAND_CELLS) + .try_into()?; + for i in 0..result.values.len() { + let (a, result) = (addend_0.values[i], result.values[i]); + // result = addend_0 + addend_1 + last_carry - carry * (256 << BYTE_WIDTH) + circuit_builder.add(result, a, Ext::BaseField::ONE); + circuit_builder.add_const(result, constant); + // It is equivalent to pad carry with 0s. + if i < carry.len() { + circuit_builder.add(result, carry[i], -Ext::BaseField::from(1 << C)); + } + if i > 0 && i - 1 < carry.len() { + circuit_builder.add(result, carry[i - 1], Ext::BaseField::ONE); + } + } + Ok(result) + } + + /// Little-endian addition with a constant. + pub fn add_const>( + circuit_builder: &mut CircuitBuilder, + range_chip_handler: &mut H, + addend_0: &UInt, + constant: Ext::BaseField, + witness: &[CellId], + ) -> Result, UtilError> { + let carry = Self::extract_carry(witness); + let range_values = Self::extract_range_values(witness); + let computed_result = Self::add_const_unsafe(circuit_builder, addend_0, constant, carry)?; + range_chip_handler.range_check_uint(circuit_builder, &computed_result, Some(range_values)) + } + + /// Little-endian addition with a constant, guaranteed no overflow. + pub fn add_const_no_overflow>( + circuit_builder: &mut CircuitBuilder, + range_chip_handler: &mut H, + addend_0: &UInt, + constant: Ext::BaseField, + witness: &[CellId], + ) -> Result, UtilError> { + let carry = Self::extract_carry_no_overflow(witness); + let range_values = Self::extract_range_values_no_overflow(witness); + let computed_result = Self::add_const_unsafe(circuit_builder, addend_0, constant, carry)?; + range_chip_handler.range_check_uint(circuit_builder, &computed_result, Some(range_values)) + } + + /// Little-endian addition with a small number. Notice that the user should + /// guarantee addend_1 < 1 << C. + pub fn add_small_unsafe( + circuit_builder: &mut CircuitBuilder, + addend_0: &UInt, + addend_1: CellId, + carry: &[CellId], + ) -> Result, UtilError> { + let result: UInt = circuit_builder + .create_cells(UInt::::N_OPRAND_CELLS) + .try_into()?; + for i in 0..result.values.len() { + let (a, result) = (addend_0.values[i], result.values[i]); + // result = addend_0 + addend_1 + last_carry - carry * (256 << BYTE_WIDTH) + circuit_builder.add(result, a, E::BaseField::ONE); + circuit_builder.add(result, addend_1, E::BaseField::ONE); + // It is equivalent to pad carry with 0s. + if i < carry.len() { + circuit_builder.add(result, carry[i], -E::BaseField::from(1 << C)); + } + if i > 0 && i - 1 < carry.len() { + circuit_builder.add(result, carry[i - 1], E::BaseField::ONE); + } + } + Ok(result) + } + + /// Little-endian addition with a small number. Notice that the user should + /// guarantee addend_1 < 1 << C. + pub fn add_small>( + circuit_builder: &mut CircuitBuilder, + range_chip_handler: &mut H, + addend_0: &UInt, + addend_1: CellId, + witness: &[CellId], + ) -> Result, UtilError> { + let carry = Self::extract_carry(witness); + let range_values = Self::extract_range_values(witness); + let computed_result = Self::add_small_unsafe(circuit_builder, addend_0, addend_1, carry)?; + range_chip_handler.range_check_uint(circuit_builder, &computed_result, Some(range_values)) + } + + /// Little-endian addition with a small number, guaranteed no overflow. + /// Notice that the user should guarantee addend_1 < 1 << C. + pub fn add_small_no_overflow>( + circuit_builder: &mut CircuitBuilder, + range_chip_handler: &mut H, + addend_0: &UInt, + addend_1: CellId, + witness: &[CellId], + ) -> Result, UtilError> { + let carry = Self::extract_carry_no_overflow(witness); + let range_values = Self::extract_range_values_no_overflow(witness); + let computed_result = Self::add_small_unsafe(circuit_builder, addend_0, addend_1, carry)?; + range_chip_handler.range_check_uint(circuit_builder, &computed_result, Some(range_values)) + } + + /// Little-endian subtraction. Assume users to check the correct range of + /// the result by themselves. + pub fn sub_unsafe( + circuit_builder: &mut CircuitBuilder, + minuend: &UInt, + subtrahend: &UInt, + borrow: &[CellId], + ) -> Result, UtilError> { + let result: UInt = circuit_builder + .create_cells(UInt::::N_OPRAND_CELLS) + .try_into()?; + // result = minuend - subtrahend + borrow * (1 << BIT_WIDTH) - last_borrow + for i in 0..result.values.len() { + let (minuend, subtrahend, result) = + (minuend.values[i], subtrahend.values[i], result.values[i]); + circuit_builder.add(result, minuend, E::BaseField::ONE); + circuit_builder.add(result, subtrahend, -E::BaseField::ONE); + if i < borrow.len() { + circuit_builder.add(result, borrow[i], E::BaseField::from(1 << C)); + } + if i > 0 && i - 1 < borrow.len() { + circuit_builder.add(result, borrow[i - 1], -E::BaseField::ONE); + } + } + Ok(result) + } +} + +#[cfg(test)] +mod test { + use super::{UInt, UIntAddSub}; + use gkr::structs::{Circuit, CircuitWitness}; + use goldilocks::{Goldilocks, GoldilocksExt2}; + use simple_frontend::structs::CircuitBuilder; + + #[test] + fn test_add_unsafe() { + type Uint256_8 = UInt<256, 8>; + assert_eq!(Uint256_8::N_OPRAND_CELLS, 32); + let mut circuit_builder: CircuitBuilder = CircuitBuilder::new(); + + // configure circuit with cells for addend_0, addend_1 and carry as wire_in + let (addend_0_wire_in_id, addend_0_wire_in_cells) = + circuit_builder.create_witness_in(Uint256_8::N_OPRAND_CELLS); + let (addend_1_wire_in_id, addend_1_wire_in_cells) = + circuit_builder.create_witness_in(Uint256_8::N_OPRAND_CELLS); + let (carry_wire_in_id, carry_wire_in_cells) = + circuit_builder.create_witness_in(Uint256_8::N_OPRAND_CELLS); + let addend_0 = Uint256_8::try_from(addend_0_wire_in_cells); + let addend_1 = Uint256_8::try_from(addend_1_wire_in_cells); + let result = UIntAddSub::::add_unsafe( + &mut circuit_builder, + &addend_0.unwrap(), + &addend_1.unwrap(), + &carry_wire_in_cells, + ); + assert_eq!(result.unwrap().values(), (96..128).collect::>()); + circuit_builder.configure(); + let circuit = Circuit::new(&circuit_builder); + //println!("add unsafe circuit {:?}", circuit); + + // generate witnesses for addend_0, addend_1 and carry + // must pad each witness to the size of N_OPERAND_CELLS + let n_witness_in = circuit.n_witness_in; + let mut wires_in = vec![vec![]; n_witness_in]; + wires_in[addend_0_wire_in_id as usize] = + vec![Goldilocks::from(255u64), Goldilocks::from(255u64)]; + wires_in[addend_0_wire_in_id as usize] + .extend(vec![Goldilocks::from(0u64); Uint256_8::N_OPRAND_CELLS - 2]); + wires_in[addend_1_wire_in_id as usize] = + vec![Goldilocks::from(255u64), Goldilocks::from(254u64)]; + wires_in[addend_1_wire_in_id as usize] + .extend(vec![Goldilocks::from(0u64); Uint256_8::N_OPRAND_CELLS - 2]); + wires_in[carry_wire_in_id as usize] = vec![Goldilocks::from(1u64), Goldilocks::from(1u64)]; + wires_in[carry_wire_in_id as usize] + .extend(vec![Goldilocks::from(0u64); Uint256_8::N_OPRAND_CELLS - 2]); + let circuit_witness = { + let challenges = vec![GoldilocksExt2::from(2)]; + let mut circuit_witness = CircuitWitness::new(&circuit, challenges); + circuit_witness.add_instance(&circuit, wires_in); + circuit_witness + }; + //println!("{:?}", circuit_witness); + circuit_witness.check_correctness(&circuit); + + // check the result + let result_values = circuit_witness.output_layer_witness_ref(); + //println!("{:?}", result_values[0]); + assert_eq!(result_values.instances[0][0], Goldilocks::from(254u64)); + assert_eq!(result_values.instances[0][1], Goldilocks::from(254u64)); + assert_eq!(result_values.instances[0][2], Goldilocks::from(1u64)); + } + + #[test] + fn test_sub_unsafe() { + type Uint256_8 = UInt<256, 8>; + assert_eq!(Uint256_8::N_OPRAND_CELLS, 32); + let mut circuit_builder = CircuitBuilder::::new(); + + // configure circuit with cells for minuend, subtrend and borrow as wire_in + let (minuend_wire_in_id, minuend_wire_in_cells) = + circuit_builder.create_witness_in(Uint256_8::N_OPRAND_CELLS); + let (subtrend_wire_in_id, subtrend_wire_in_cells) = + circuit_builder.create_witness_in(Uint256_8::N_OPRAND_CELLS); + let (borrow_wire_in_id, borrow_wire_in_cells) = + circuit_builder.create_witness_in(Uint256_8::N_OPRAND_CELLS); + let minuend = Uint256_8::try_from(minuend_wire_in_cells); + let subtrend = Uint256_8::try_from(subtrend_wire_in_cells); + let result = UIntAddSub::::sub_unsafe( + &mut circuit_builder, + &minuend.unwrap(), + &subtrend.unwrap(), + &borrow_wire_in_cells, + ); + assert_eq!(result.unwrap().values(), (96..128).collect::>()); + circuit_builder.configure(); + let circuit = Circuit::new(&circuit_builder); + //println!("add unsafe circuit {:?}", circuit); + + // generate witnesses for addend_0, addend_1 and carry + // must pad each witness to the size of N_OPERAND_CELLS + let n_witness_in = circuit.n_witness_in; + let mut wires_in = vec![vec![]; n_witness_in]; + wires_in[minuend_wire_in_id as usize] = + vec![Goldilocks::from(1u64), Goldilocks::from(1u64)]; + wires_in[minuend_wire_in_id as usize] + .extend(vec![Goldilocks::from(0u64); Uint256_8::N_OPRAND_CELLS - 2]); + wires_in[subtrend_wire_in_id as usize] = + vec![Goldilocks::from(255u64), Goldilocks::from(254u64)]; + wires_in[subtrend_wire_in_id as usize] + .extend(vec![Goldilocks::from(0u64); Uint256_8::N_OPRAND_CELLS - 2]); + wires_in[borrow_wire_in_id as usize] = vec![Goldilocks::from(1u64), Goldilocks::from(1u64)]; + wires_in[borrow_wire_in_id as usize] + .extend(vec![Goldilocks::from(0u64); Uint256_8::N_OPRAND_CELLS - 2]); + let circuit_witness = { + let challenges = vec![GoldilocksExt2::from(2)]; + let mut circuit_witness = CircuitWitness::new(&circuit, challenges); + circuit_witness.add_instance(&circuit, wires_in); + circuit_witness + }; + //println!("{:?}", circuit_witness); + circuit_witness.check_correctness(&circuit); + + // check the result + let result_values = circuit_witness.output_layer_witness_ref(); + //println!("{:?}", result_values[0]); + assert_eq!(result_values.instances[0][0], Goldilocks::from(2u64)); + assert_eq!(result_values.instances[0][1], Goldilocks::from(2u64)); + assert_eq!(result_values.instances[0][2], -Goldilocks::from(1u64)); + } +} diff --git a/singer-utils/src/uint/arithmetic.rs b/singer-utils/src/uint/arithmetic.rs deleted file mode 100644 index b1ab1a882..000000000 --- a/singer-utils/src/uint/arithmetic.rs +++ /dev/null @@ -1,612 +0,0 @@ -use crate::chip_handler::RangeChipOperations; -use crate::error::UtilError; -use crate::uint::uint::UInt; -use ff::Field; -use ff_ext::ExtensionField; -use simple_frontend::structs::{Cell, CellId, CircuitBuilder}; - -impl UInt { - /// Little-endian addition. - /// Assumes users will check the correct range of the result themselves. - // Addition of A + B with limbs [a, b, c] and [d, e, f] respectively - // - // cell_modulo = 2^C - // addend_0 - a b c - // addend_1 - d e f - // -------------------------------------------------- - // result - (a + d) % 2^C (b + e) % 2^C (c + f) % 2^C - // carry - (a + d) // 2^C (b + e) // 2^C (c + f) % 2^C - // - // every limb in addend_0 and addend_1 exists in the range [0, ..., 2^C - 1] - // after summing two limb values, the result exists in [0, ..., 2^(C+1) - 2] - // the carry value is either 0 or 1, - // it cannot be >= 2 as that will require result value >= 2^(C+1) - // - // assuming result range check, there is a unique carry vector that makes all - // constraint pass. - // if a + b > max_cell_value then carry must be set to 1 (if not range check fails) - // if a + b <= max_cell_value then carry must be set to 0 (if not range check fails) - // - // NOTE: this function doesn't perform the required range check! - pub fn add_unsafe( - circuit_builder: &mut CircuitBuilder, - addend_0: &UInt, - addend_1: &UInt, - carry: &[CellId], - ) -> Result, UtilError> { - let result: UInt = circuit_builder - .create_cells(Self::N_OPERAND_CELLS) - .try_into()?; - - for i in 0..Self::N_OPERAND_CELLS { - let (a, b, result) = (addend_0.values[i], addend_1.values[i], result.values[i]); - - // result = a + b - overflow_carry + last_carry - circuit_builder.add(result, a, E::BaseField::ONE); - circuit_builder.add(result, b, E::BaseField::ONE); - Self::handle_carry(result, circuit_builder, i, carry); - } - - Ok(result) - } - - /// Little-endian addition. - pub fn add>( - circuit_builder: &mut CircuitBuilder, - range_chip_handler: &mut H, - addend_0: &UInt, - addend_1: &UInt, - witness: &[CellId], - ) -> Result, UtilError> { - let carry = Self::extract_carry_add_sub(witness); - let range_values = Self::extract_range_values(witness); - let computed_result = Self::add_unsafe(circuit_builder, addend_0, addend_1, carry)?; - range_chip_handler.range_check_uint(circuit_builder, &computed_result, Some(range_values)) - } - - /// Add a constant value to a `UInt` instance - /// Assumes users will check the correct range of the result themselves. - pub fn add_const_unsafe( - circuit_builder: &mut CircuitBuilder, - addend_0: &UInt, - constant: E::BaseField, - carry: &[CellId], - ) -> Result, UtilError> { - let result: UInt = circuit_builder - .create_cells(Self::N_OPERAND_CELLS) - .try_into()?; - - // add constant to the first limb - circuit_builder.add_const(result.values[0], constant); - - // cascade carry - for i in 0..Self::N_OPERAND_CELLS { - let (a, result) = (addend_0.values[i], result.values[i]); - - circuit_builder.add(result, a, E::BaseField::ONE); - Self::handle_carry(result, circuit_builder, i, carry); - } - - Ok(result) - } - - /// Add a constant value to a `UInt` instance - pub fn add_const>( - circuit_builder: &mut CircuitBuilder, - range_chip_handler: &mut H, - addend_0: &UInt, - constant: E::BaseField, - witness: &[CellId], - ) -> Result, UtilError> { - let carry = Self::extract_carry_add_sub(witness); - let range_values = Self::extract_range_values(witness); - let computed_result = Self::add_const_unsafe(circuit_builder, addend_0, constant, carry)?; - range_chip_handler.range_check_uint(circuit_builder, &computed_result, Some(range_values)) - } - - /// Add a constant value to a `UInt` instance - /// Assumes that addition leads to no overflow. - pub fn add_const_no_overflow>( - circuit_builder: &mut CircuitBuilder, - range_chip_handler: &mut H, - addend_0: &UInt, - constant: E::BaseField, - witness: &[CellId], - ) -> Result, UtilError> { - let carry = Self::extract_carry_no_overflow_add_sub(witness); - let range_values = Self::extract_range_values_no_overflow(witness); - let computed_result = Self::add_const_unsafe(circuit_builder, addend_0, constant, carry)?; - range_chip_handler.range_check_uint(circuit_builder, &computed_result, Some(range_values)) - } - - /// Adds a single cell value to a `UInt` instance - /// Assumes users will check the correct range of the result and - pub fn add_cell_unsafe( - circuit_builder: &mut CircuitBuilder, - addend_0: &UInt, - addend_1: CellId, - carry: &[CellId], - ) -> Result, UtilError> { - let result: UInt = circuit_builder - .create_cells(Self::N_OPERAND_CELLS) - .try_into()?; - - // add small_value to the first limb - circuit_builder.add(result.values[0], addend_1, E::BaseField::ONE); - - // cascade carry - for i in 0..Self::N_OPERAND_CELLS { - let (a, result) = (addend_0.values[i], result.values[i]); - - circuit_builder.add(result, a, E::BaseField::ONE); - Self::handle_carry(result, circuit_builder, i, carry); - } - - Ok(result) - } - - /// Adds a single cell value to a `UInt` instance - pub fn add_cell>( - circuit_builder: &mut CircuitBuilder, - range_chip_handler: &mut H, - addend_0: &UInt, - addend_1: CellId, - witness: &[CellId], - ) -> Result, UtilError> { - let carry = Self::extract_carry_add_sub(witness); - let range_values = Self::extract_range_values(witness); - let computed_result = Self::add_cell_unsafe(circuit_builder, addend_0, addend_1, carry)?; - range_chip_handler.range_check_uint(circuit_builder, &computed_result, Some(range_values)) - } - - /// Adds a single cell value to a `UInt` instance - /// Assumes that addition lead to no overflow. - pub fn add_cell_no_overflow>( - circuit_builder: &mut CircuitBuilder, - range_chip_handler: &mut H, - addend_0: &UInt, - addend_1: CellId, - witness: &[CellId], - ) -> Result, UtilError> { - let carry = Self::extract_carry_no_overflow_add_sub(witness); - let range_values = Self::extract_range_values_no_overflow(witness); - let computed_result = Self::add_cell_unsafe(circuit_builder, addend_0, addend_1, carry)?; - range_chip_handler.range_check_uint(circuit_builder, &computed_result, Some(range_values)) - } - - /// Little endian subtraction - /// Assumes users will check the correct range of the result themselves. - pub fn sub_unsafe( - circuit_builder: &mut CircuitBuilder, - minuend: &UInt, - subtrahend: &UInt, - borrow: &[CellId], - ) -> Result, UtilError> { - let result: UInt = circuit_builder - .create_cells(Self::N_OPERAND_CELLS) - .try_into()?; - - for i in 0..Self::N_OPERAND_CELLS { - let (minuend, subtrahend, result) = - (minuend.values[i], subtrahend.values[i], result.values[i]); - - circuit_builder.add(result, minuend, E::BaseField::ONE); - circuit_builder.add(result, subtrahend, -E::BaseField::ONE); - - Self::handle_borrow(result, circuit_builder, i, borrow); - } - - Ok(result) - } - - /// Little endian subtraction - pub fn sub>( - circuit_builder: &mut CircuitBuilder, - range_chip_handler: &mut H, - minuend: &UInt, - subtrahend: &UInt, - witness: &[CellId], - ) -> Result, UtilError> { - let borrow = Self::extract_borrow_add_sub(witness); - let range_values = Self::extract_range_values(witness); - let computed_result = Self::sub_unsafe(circuit_builder, minuend, subtrahend, borrow)?; - range_chip_handler.range_check_uint(circuit_builder, &computed_result, Some(range_values)) - } - - /// Modify addition result based on carry instructions - fn handle_carry( - result_cell_id: CellId, - circuit_builder: &mut CircuitBuilder, - limb_index: usize, - carry: &[CellId], - ) { - // overflow carry - // represents the portion of the result that should move to the next operation - // inorder to keep the value <= C bits - // carry[i] = (addend_0[i] + addend_1[i]) % 2^C - - // last carry - // represents the carry that was passed from the previous operation - // this carry should be added to the current result - // carry[i - 1] = (addend_0[i - 1] + addend_1[i - 1]) % 2^C - - if limb_index > carry.len() { - return; - } - - // handle overflow carry - // we need to subtract the carry value from the current result - if limb_index < carry.len() { - circuit_builder.add( - result_cell_id, - carry[limb_index], - -E::BaseField::from(1 << C), - ); - } - - // handle last operation carry - // we need to add this to the current result - if limb_index > 0 { - circuit_builder.add(result_cell_id, carry[limb_index - 1], E::BaseField::ONE); - } - } - - /// Modify subtraction result based on borrow instructions - fn handle_borrow( - result_cell_id: CellId, - circuit_builder: &mut CircuitBuilder, - limb_index: usize, - borrow: &[CellId], - ) { - // borrow - // represents the portion of the result that should move from the - // next operation to the current operation i.e. reduce the result - // of the operation to come - // this should be added to the current result - // = borrow[i] - - // last borrow - // represents the portion of the current result that was moved during - // the previous computation - // this should be removed from the current result - - if limb_index > borrow.len() { - return; - } - - // handle borrow - // we need to add borrow units of C to the result - if limb_index < borrow.len() { - circuit_builder.add( - result_cell_id, - borrow[limb_index], - E::BaseField::from(1 << C), - ); - } - - // handle last borrow - // we need to remove this from the current result - if limb_index > 0 { - circuit_builder.add(result_cell_id, borrow[limb_index - 1], -E::BaseField::ONE); - } - } -} - -#[cfg(test)] -mod tests { - use crate::uint::constants::AddSubConstants; - use crate::uint::UInt; - use gkr::structs::{Circuit, CircuitWitness}; - use goldilocks::{Goldilocks, GoldilocksExt2}; - use itertools::Itertools; - use simple_frontend::structs::CircuitBuilder; - - #[test] - fn test_add_unsafe() { - // UInt<20, 5> (4 limbs) - - // A (big-endian representation) - // 01001 | 10100 | 11010 | 11110 - - // B (big-endian representation) - // 00101 | 01010 | 10110 | 10000 - - // A + B - // big endian and represented as field elements - // 9 | 20 | 26 | 30 - // 5 | 10 | 22 | 16 - // result 14 | 31 | 17 | 14 - // carry 0 | 0 | 1 | 1 - - // build the circuit - type UInt20 = UInt<20, 5>; - let mut circuit_builder = CircuitBuilder::::new(); - - // input wires - // addend_0, addend_1, carry - let (addend_0_id, addend_0_cells) = - circuit_builder.create_witness_in(UInt20::N_OPERAND_CELLS); - let (addend_1_id, addend_1_cells) = - circuit_builder.create_witness_in(UInt20::N_OPERAND_CELLS); - let (carry_id, carry_cells) = - circuit_builder.create_witness_in(AddSubConstants::::N_CARRY_CELLS); - - let addend_0 = UInt20::try_from(addend_0_cells).expect("should build uint"); - let addend_1 = UInt20::try_from(addend_1_cells).expect("should build uint"); - - // update circuit builder with circuit instructions - let result = - UInt20::add_unsafe(&mut circuit_builder, &addend_0, &addend_1, &carry_cells).unwrap(); - circuit_builder.configure(); - let circuit = Circuit::new(&circuit_builder); - - // generate witness - // calling rev() to make things little endian representation - let addend_0_witness = vec![9, 20, 26, 30] - .into_iter() - .rev() - .map(|v| Goldilocks::from(v)) - .collect_vec(); - let addend_1_witness = vec![5, 10, 22, 16] - .into_iter() - .rev() - .map(|v| Goldilocks::from(v)) - .collect_vec(); - let carry_witness = vec![0, 0, 1, 1] - .into_iter() - .rev() - .map(|v| Goldilocks::from(v)) - .collect_vec(); - - let mut wires_in = vec![vec![]; circuit.n_witness_in]; - wires_in[addend_0_id as usize] = addend_0_witness; - wires_in[addend_1_id as usize] = addend_1_witness; - wires_in[carry_id as usize] = carry_witness; - - let circuit_witness = { - let challenges = vec![GoldilocksExt2::from(2)]; - let mut circuit_witness = CircuitWitness::new(&circuit, challenges); - circuit_witness.add_instance(&circuit, wires_in); - circuit_witness - }; - - circuit_witness.check_correctness(&circuit); - - // check the result correctness - let result_values = circuit_witness.output_layer_witness_ref().instances[0].to_vec(); - assert_eq!( - result_values, - [14, 17, 31, 14] - .into_iter() - .map(|v| Goldilocks::from(v)) - .collect_vec() - ); - } - - #[test] - fn test_add_constant_unsafe() { - // UInt<20, 5> (4 limbs) - - // A + constant - // A = 14 | 31 | 28 | 14 - // constant = 200 - // big endian and represented as field elements - // 14 | 31 | 28 | 14 - // | | | 200 - // result 15 | 0 | 2 | 22 - // carry 0 | 1 | 1 | 6 - - type UInt20 = UInt<20, 5>; - let mut circuit_builder = CircuitBuilder::::new(); - - // input wires - // addend_0, carry, constant - let (addend_0_id, addend_0_cells) = - circuit_builder.create_witness_in(UInt20::N_OPERAND_CELLS); - let (carry_id, carry_cells) = - circuit_builder.create_witness_in(AddSubConstants::::N_CARRY_CELLS); - - let addend_0 = UInt20::try_from(addend_0_cells).expect("should build uint"); - - // update circuit builder - let result = UInt20::add_const_unsafe( - &mut circuit_builder, - &addend_0, - Goldilocks::from(200), - &carry_cells, - ) - .unwrap(); - circuit_builder.configure(); - let circuit = Circuit::new(&circuit_builder); - - // generate witness - // calling rev() to make things little endian representation - let addend_0_witness = vec![14, 31, 28, 14] - .into_iter() - .rev() - .map(|v| Goldilocks::from(v)) - .collect_vec(); - let carry_witness = vec![0, 1, 1, 6] - .into_iter() - .rev() - .map(|v| Goldilocks::from(v)) - .collect_vec(); - - let mut wires_in = vec![vec![]; circuit.n_witness_in]; - wires_in[addend_0_id as usize] = addend_0_witness; - wires_in[carry_id as usize] = carry_witness; - - let circuit_witness = { - let challenges = vec![GoldilocksExt2::from(2)]; - let mut circuit_witness = CircuitWitness::new(&circuit, challenges); - circuit_witness.add_instance(&circuit, wires_in); - circuit_witness - }; - - circuit_witness.check_correctness(&circuit); - - // check the result correctness - let result_values = circuit_witness.output_layer_witness_ref().instances[0].to_vec(); - assert_eq!( - result_values, - [22, 2, 0, 15] - .into_iter() - .map(|v| Goldilocks::from(v)) - .collect_vec() - ); - } - - #[test] - fn test_add_small_unsafe() { - // UInt<20, 5> (4 limbs) - - // A + constant - // A = 14 | 31 | 28 | 14 - // small = 200 // TODO: fix this should be < 32 - // big endian and represented as field elements - // 14 | 31 | 28 | 14 - // | | | 200 - // result 15 | 0 | 2 | 22 - // carry 0 | 1 | 1 | 6 - - type UInt20 = UInt<20, 5>; - let mut circuit_builder = CircuitBuilder::::new(); - - // input wires - // addend_0, carry, constant - let (addend_0_id, addend_0_cells) = - circuit_builder.create_witness_in(UInt20::N_OPERAND_CELLS); - let (small_value_id, small_value_cell) = circuit_builder.create_witness_in(1); - let (carry_id, carry_cells) = - circuit_builder.create_witness_in(AddSubConstants::::N_CARRY_CELLS); - - let addend_0 = UInt20::try_from(addend_0_cells).expect("should build uint"); - - // update circuit builder - let result = UInt20::add_cell_unsafe( - &mut circuit_builder, - &addend_0, - small_value_cell[0], - &carry_cells, - ) - .unwrap(); - circuit_builder.configure(); - let circuit = Circuit::new(&circuit_builder); - - // generate witness - // calling rev() to make things little endian representation - let addend_0_witness = vec![14, 31, 28, 14] - .into_iter() - .rev() - .map(|v| Goldilocks::from(v)) - .collect_vec(); - let small_value_witness = vec![200] - .into_iter() - .map(|v| Goldilocks::from(v)) - .collect_vec(); - let carry_witness = vec![0, 1, 1, 6] - .into_iter() - .rev() - .map(|v| Goldilocks::from(v)) - .collect_vec(); - - let mut wires_in = vec![vec![]; circuit.n_witness_in]; - wires_in[addend_0_id as usize] = addend_0_witness; - wires_in[small_value_id as usize] = small_value_witness; - wires_in[carry_id as usize] = carry_witness; - - let circuit_witness = { - let challenges = vec![GoldilocksExt2::from(2)]; - let mut circuit_witness = CircuitWitness::new(&circuit, challenges); - circuit_witness.add_instance(&circuit, wires_in); - circuit_witness - }; - - circuit_witness.check_correctness(&circuit); - - // check the result correctness - let result_values = circuit_witness.output_layer_witness_ref().instances[0].to_vec(); - assert_eq!( - result_values, - [22, 2, 0, 15] - .into_iter() - .map(|v| Goldilocks::from(v)) - .collect_vec() - ); - } - - #[test] - fn test_sub_unsafe() { - // A - B - // big endian and represented as field elements - // 9 | 20 | 26 | 30 - // 5 | 30 | 28 | 10 - // result 3 | 21 | 30 | 20 - // borrow 0 | 1 | 1 | 0 - - // build the circuit - type UInt20 = UInt<20, 5>; - let mut circuit_builder = CircuitBuilder::::new(); - - // input wires - // minuend, subtrahend, borrow - let (minuend_id, minuend_cells) = - circuit_builder.create_witness_in(UInt20::N_OPERAND_CELLS); - let (subtrahend_id, subtrahend_cells) = - circuit_builder.create_witness_in(UInt20::N_OPERAND_CELLS); - // |Carry| == |Borrow| - let (borrow_id, borrow_cells) = - circuit_builder.create_witness_in(AddSubConstants::::N_CARRY_CELLS); - - let minuend = UInt20::try_from(minuend_cells).expect("should build uint"); - let subtrahend = UInt20::try_from(subtrahend_cells).expect("should build uint"); - - // update the circuit builder - let result = - UInt20::sub_unsafe(&mut circuit_builder, &minuend, &subtrahend, &borrow_cells).unwrap(); - circuit_builder.configure(); - let circuit = Circuit::new(&circuit_builder); - - // generate witness - // calling rev() to make things little endian representation - let minuend_witness = vec![9, 20, 26, 30] - .into_iter() - .rev() - .map(|v| Goldilocks::from(v)) - .collect_vec(); - let subtrahend_witness = vec![5, 30, 28, 10] - .into_iter() - .rev() - .map(|v| Goldilocks::from(v)) - .collect(); - let borrow_witness = vec![0, 1, 1, 0] - .into_iter() - .rev() - .map(|v| Goldilocks::from(v)) - .collect_vec(); - - let mut wires_in = vec![vec![]; circuit.n_witness_in]; - wires_in[minuend_id as usize] = minuend_witness; - wires_in[subtrahend_id as usize] = subtrahend_witness; - wires_in[borrow_id as usize] = borrow_witness; - - let circuit_witness = { - let challenges = vec![GoldilocksExt2::from(2)]; - let mut circuit_witness = CircuitWitness::new(&circuit, challenges); - circuit_witness.add_instance(&circuit, wires_in); - circuit_witness - }; - - circuit_witness.check_correctness(&circuit); - - // check the result correctness - let result_values = circuit_witness.output_layer_witness_ref().instances[0].to_vec(); - assert_eq!( - result_values, - [20, 30, 21, 3] - .into_iter() - .map(|v| Goldilocks::from(v)) - .collect_vec() - ); - } -} diff --git a/singer-utils/src/uint/cmp.rs b/singer-utils/src/uint/cmp.rs index ebfb7734f..2a2ba0058 100644 --- a/singer-utils/src/uint/cmp.rs +++ b/singer-utils/src/uint/cmp.rs @@ -1,122 +1,185 @@ -use crate::chip_handler::RangeChipOperations; -use crate::error::UtilError; -use crate::uint::constants::AddSubConstants; -use crate::uint::uint::UInt; use ff::Field; use ff_ext::ExtensionField; use simple_frontend::structs::{CellId, CircuitBuilder, MixedCell}; -impl UInt { - /// Generates the required information for asserting lt and leq - pub fn lt>( - circuit_builder: &mut CircuitBuilder, +use crate::{chip_handler::RangeChipOperations, error::UtilError, structs::UInt}; + +use super::{UIntAddSub, UIntCmp}; + +impl UIntCmp> { + pub const N_NO_OVERFLOW_WITNESS_CELLS: usize = + UIntAddSub::>::N_NO_OVERFLOW_WITNESS_CELLS; + + pub const N_WITNESS_CELLS: usize = UIntAddSub::>::N_WITNESS_CELLS; + + pub fn extract_range_values(witness: &[CellId]) -> &[CellId] { + &witness[..UInt::::N_RANGE_CHECK_CELLS] + } + + pub fn extract_borrow(witness: &[CellId]) -> &[CellId] { + &UIntAddSub::>::extract_carry(witness) + } + + pub fn extract_unsafe_borrow(witness: &[CellId]) -> &[CellId] { + &UIntAddSub::>::extract_unsafe_carry(witness) + } + + /// Greater than implemented by little-endian subtraction. + pub fn lt>( + circuit_builder: &mut CircuitBuilder, range_chip_handler: &mut H, - operand_0: &UInt, - operand_1: &UInt, + oprand_0: &UInt, + oprand_1: &UInt, witness: &[CellId], ) -> Result<(CellId, UInt), UtilError> { - let borrow = Self::extract_borrow_add_sub(witness); + let borrow = Self::extract_borrow(witness); let range_values = Self::extract_range_values(witness); - let computed_diff = Self::sub_unsafe(circuit_builder, operand_0, operand_1, borrow)?; - + let computed_diff = + UIntAddSub::>::sub_unsafe(circuit_builder, oprand_0, oprand_1, borrow)?; let diff = range_chip_handler.range_check_uint( circuit_builder, &computed_diff, Some(&range_values), )?; - - // if operand_0 < operand_1, the last borrow should equal 1 - if borrow.len() == AddSubConstants::::N_CARRY_CELLS { - Ok((borrow[AddSubConstants::::N_CARRY_CELLS - 1], diff)) + if borrow.len() == UInt::::N_CARRY_CELLS { + Ok((borrow[UInt::::N_CARRY_CELLS - 1], diff)) } else { Ok((circuit_builder.create_cell(), diff)) } } - /// Asserts that operand_0 < operand_1 - pub fn assert_lt>( - circuit_builder: &mut CircuitBuilder, + pub fn assert_lt>( + circuit_builder: &mut CircuitBuilder, range_chip_handler: &mut H, - operand_0: &UInt, - operand_1: &UInt, + oprand_0: &UInt, + oprand_1: &UInt, witness: &[CellId], ) -> Result<(), UtilError> { let (borrow, _) = Self::lt( circuit_builder, range_chip_handler, - operand_0, - operand_1, + oprand_0, + oprand_1, witness, )?; circuit_builder.assert_const(borrow, 1); Ok(()) } - /// Asserts that operand_0 <= operand_1 - pub fn assert_leq>( - circuit_builder: &mut CircuitBuilder, + /// Greater or equal than implemented by little-endian subtraction. + pub fn assert_leq>( + circuit_builder: &mut CircuitBuilder, range_chip_handler: &mut H, - operand_0: &UInt, - operand_1: &UInt, + oprand_0: &UInt, + oprand_1: &UInt, witness: &[CellId], ) -> Result<(), UtilError> { let (borrow, diff) = Self::lt( circuit_builder, range_chip_handler, - operand_0, - operand_1, + oprand_0, + oprand_1, witness, )?; - - // we have two scenarios - // 1. eq - // in this case, borrow = 0 and diff = [0, ..., 0] - // 2. lt - // in this case, borrow = 1 and diff = [..field_elements..] - // we check for both cases with the following - // if borrow == 0 return diff else return 0 - // then assert that the returned item = 0 - let diff_values = diff.values(); for d in diff_values.iter() { let s = circuit_builder.create_cell(); + // assert_zero({borrow ? 0 : diff}) circuit_builder.sel_mixed( s, (*d).into(), - MixedCell::Constant(E::BaseField::ZERO), + MixedCell::Constant(Ext::BaseField::ZERO), borrow, ); circuit_builder.assert_const(s, 0); } - Ok(()) } - /// Asserts that two `UInt` instances represent equal value - pub fn assert_eq( - circuit_builder: &mut CircuitBuilder, - operand_0: &UInt, - operand_1: &UInt, + pub fn assert_eq( + circuit_builder: &mut CircuitBuilder, + oprand_0: &UInt, + oprand_1: &UInt, ) -> Result<(), UtilError> { - let diff = circuit_builder.create_cells(Self::N_OPERAND_CELLS); - let operand_0_cells = operand_0.values(); - let operand_1_cells = operand_1.values(); - for i in 0..Self::N_OPERAND_CELLS { - circuit_builder.add(diff[i], operand_0_cells[i], E::BaseField::ONE); - circuit_builder.add(diff[i], operand_1_cells[i], -E::BaseField::ONE); + let diff = circuit_builder.create_cells(oprand_0.values().len()); + let opr_0 = oprand_0.values(); + let opr_1 = oprand_1.values(); + for i in 0..diff.len() { + circuit_builder.add(diff[i], opr_0[i], Ext::BaseField::ONE); + circuit_builder.add(diff[i], opr_1[i], -Ext::BaseField::ONE); circuit_builder.assert_const(diff[i], 0); } Ok(()) } +} - /// Asserts that a `UInt` instance and a set of range cells represent equal value - pub fn assert_eq_range_values( - circuit_builder: &mut CircuitBuilder, - operand_0: &UInt, - operand_1: &[CellId], - ) -> Result<(), UtilError> { - // TODO: really need to test this, different from reference implementation - let range_as_uint = UInt::from_range_values(circuit_builder, operand_1)?; - Self::assert_eq(circuit_builder, &operand_0, &range_as_uint) +#[cfg(test)] +mod test { + use crate::structs::{ChipChallenges, ROMHandler}; + + use super::{UInt, UIntCmp}; + use goldilocks::{Goldilocks, GoldilocksExt2}; + use simple_frontend::structs::CircuitBuilder; + + use gkr::structs::{Circuit, CircuitWitness}; + + #[test] + fn test_lt() { + type Uint256_8 = UInt<256, 8>; + assert_eq!(Uint256_8::N_OPRAND_CELLS, 32); + // build the circuit for lt + let mut circuit_builder = CircuitBuilder::::new(); + let (operand_0_wire_in_id, operand_0_wire_in_cells) = + circuit_builder.create_witness_in(Uint256_8::N_OPRAND_CELLS); + let (operand_1_wire_in_id, operand_1_wire_in_cells) = + circuit_builder.create_witness_in(Uint256_8::N_OPRAND_CELLS); + let (witness_wire_in_id, witness_wire_in_cells) = circuit_builder + .create_witness_in(Uint256_8::N_RANGE_CHECK_CELLS + Uint256_8::N_CARRY_CELLS); + let operand_0 = Uint256_8::try_from(operand_0_wire_in_cells); + let operand_1 = Uint256_8::try_from(operand_1_wire_in_cells); + let mut range_chip_handler = ROMHandler::::new(&ChipChallenges::default()); + let result = UIntCmp::::lt( + &mut circuit_builder, + &mut range_chip_handler, + &operand_0.unwrap(), + &operand_1.unwrap(), + &witness_wire_in_cells, + ); + assert_eq!( + result.unwrap().0, + 2 * Uint256_8::N_OPRAND_CELLS + + Uint256_8::N_RANGE_CHECK_CELLS + + Uint256_8::N_CARRY_CELLS + - 1 + ); + circuit_builder.configure(); + let circuit = Circuit::new(&circuit_builder); + // fill in witnesses + let n_witness_in = circuit.n_witness_in; + let mut wires_in = vec![vec![]; n_witness_in]; + wires_in[operand_0_wire_in_id as usize] = + vec![Goldilocks::from(1u64), Goldilocks::from(1u64)]; + wires_in[operand_0_wire_in_id as usize] + .extend(vec![Goldilocks::from(0u64); Uint256_8::N_OPRAND_CELLS - 2]); + wires_in[operand_1_wire_in_id as usize] = + vec![Goldilocks::from(255u64), Goldilocks::from(254u64)]; + wires_in[operand_1_wire_in_id as usize] + .extend(vec![Goldilocks::from(0u64); Uint256_8::N_OPRAND_CELLS - 2]); + wires_in[witness_wire_in_id as usize] = + vec![Goldilocks::from(2u64), Goldilocks::from(2u64)]; + wires_in[witness_wire_in_id as usize].extend(vec![ + Goldilocks::from(255u64); + Uint256_8::N_RANGE_CHECK_CELLS - 2 + ]); + wires_in[witness_wire_in_id as usize] + .extend(vec![Goldilocks::from(1u64); Uint256_8::N_CARRY_CELLS]); + let circuit_witness = { + let challenges = vec![GoldilocksExt2::from(2), GoldilocksExt2::from(2)]; + let mut circuit_witness = CircuitWitness::new(&circuit, challenges); + circuit_witness.add_instance(&circuit, wires_in); + circuit_witness + }; + //println!("{:?}", circuit_witness); + circuit_witness.check_correctness(&circuit); } } diff --git a/singer-utils/src/uint/constants.rs b/singer-utils/src/uint/constants.rs deleted file mode 100644 index 6f2345bcd..000000000 --- a/singer-utils/src/uint/constants.rs +++ /dev/null @@ -1,66 +0,0 @@ -use super::uint::UInt; -use crate::constants::RANGE_CHIP_BIT_WIDTH; -use crate::uint::util::const_min; -use std::marker::PhantomData; - -impl UInt { - /// Determines the maximum number of bits that should be represented in each cell - /// independent of the cell capacity `C`. - /// If M < C i.e. total bit < cell capacity, the maximum_usable_cell_capacity - /// is actually M. - /// but if M >= C then maximum_usable_cell_capacity = C - pub const MAX_CELL_BIT_WIDTH: usize = const_min(M, C); - - /// `N_OPERAND_CELLS` represent the minimum number of cells each of size `C` needed - /// to hold `M` total bits - pub const N_OPERAND_CELLS: usize = (M + C - 1) / C; - - /// The number of `RANGE_CHIP_BIT_WIDTH` cells needed to represent one cell of size `C` - const N_RANGE_CELLS_PER_CELL: usize = (C + RANGE_CHIP_BIT_WIDTH - 1) / RANGE_CHIP_BIT_WIDTH; - - /// The number of `RANGE_CHIP_BIT_WIDTH` cells needed to represent the entire `UInt` - pub const N_RANGE_CELLS: usize = Self::N_OPERAND_CELLS * Self::N_RANGE_CELLS_PER_CELL; -} - -/// Holds addition specific constants -pub struct AddSubConstants { - _marker: PhantomData, -} - -impl AddSubConstants> { - /// Number of cells required to track carry information for the addition operation. - /// operand_0 = a b c - /// operand_1 = e f g - /// ---------- - /// result = h i j - /// carry = k l m - - /// |Carry| = |Cells| - pub const N_CARRY_CELLS: usize = UInt::::N_OPERAND_CELLS; - - /// Number of cells required to track carry information if we assume the addition - /// operation cannot lead to overflow. - /// operand_0 = a b c - /// operand_1 = e f g - /// ---------- - /// result = h i j - /// carry = l m - - /// |Carry| = |Cells - 1| - const N_CARRY_CELLS_NO_OVERFLOW: usize = Self::N_CARRY_CELLS - 1; - - /// The size of the witness - pub const N_WITNESS_CELLS: usize = UInt::::N_RANGE_CELLS + Self::N_CARRY_CELLS; - - /// The size of the witness assuming carry has no overflow - /// |Range_values| + |Carry - 1| - pub const N_WITNESS_CELLS_NO_CARRY_OVERFLOW: usize = - UInt::::N_RANGE_CELLS + Self::N_CARRY_CELLS_NO_OVERFLOW; - - pub const N_NO_OVERFLOW_WITNESS_UNSAFE_CELLS: usize = Self::N_CARRY_CELLS_NO_OVERFLOW; - - /// The number of `RANGE_CHIP_BIT_WIDTH` cells needed to represent the carry cells, assuming - /// no overflow. - // TODO: if guaranteed no overflow, then we don't need to range check the highest limb - // hence this can be (N_OPERANDS - 1) * N_RANGE_CELLS_PER_CELL - // update this once, range check logic doesn't assume all limbs - pub const N_RANGE_CELLS_NO_OVERFLOW: usize = UInt::::N_RANGE_CELLS; -} diff --git a/singer-utils/src/uint/uint.rs b/singer-utils/src/uint/uint.rs deleted file mode 100644 index 3872359c4..000000000 --- a/singer-utils/src/uint/uint.rs +++ /dev/null @@ -1,260 +0,0 @@ -use crate::constants::{BYTE_BIT_WIDTH, RANGE_CHIP_BIT_WIDTH}; -use crate::error::UtilError; -use crate::uint::util::{add_one_to_big_num, convert_decomp, pad_cells}; -use ff_ext::ExtensionField; -use goldilocks::SmallField; -use itertools::Itertools; -use simple_frontend::structs::{CellId, CircuitBuilder}; -use sumcheck::util::ceil_log2; - -#[derive(Clone)] -/// Unsigned integer with `M` total bits. `C` denotes the cell bit width. -/// Represented in little endian form. -pub struct UInt { - // TODO: the size of C should not be more than the size of the underlying field - // TODO: should this be private? - pub values: Vec, -} - -impl UInt { - /// Return the `UInt` underlying cell id's - pub fn values(&self) -> &[CellId] { - &self.values - } - - /// Builds a `UInt` instance from a set of cells that represent `RANGE_VALUES` - /// assumes range_values are represented in little endian form - pub fn from_range_values( - circuit_builder: &mut CircuitBuilder, - range_values: &[CellId], - ) -> Result { - Self::from_different_sized_cell_values( - circuit_builder, - range_values, - RANGE_CHIP_BIT_WIDTH, - true, - ) - } - - /// Builds a `UInt` instance from a set of cells that represent big-endian `BYTE_VALUES` - pub fn from_bytes_big_endian( - circuit_builder: &mut CircuitBuilder, - bytes: &[CellId], - ) -> Result { - Self::from_bytes(circuit_builder, bytes, false) - } - - /// Builds a `UInt` instance from a set of cells that represent little-endian `BYTE_VALUES` - pub fn from_bytes_little_endian( - circuit_builder: &mut CircuitBuilder, - bytes: &[CellId], - ) -> Result { - Self::from_bytes(circuit_builder, bytes, true) - } - - /// Builds a `UInt` instance from a set of cells that represent `BYTE_VALUES` - pub fn from_bytes( - circuit_builder: &mut CircuitBuilder, - bytes: &[CellId], - is_little_endian: bool, - ) -> Result { - Self::from_different_sized_cell_values( - circuit_builder, - bytes, - BYTE_BIT_WIDTH, - is_little_endian, - ) - } - - /// Builds a `UInt` instance from a set of cell values of a certain `CELL_WIDTH` - fn from_different_sized_cell_values( - circuit_builder: &mut CircuitBuilder, - cell_values: &[CellId], - cell_width: usize, - is_little_endian: bool, - ) -> Result { - let mut values = convert_decomp( - circuit_builder, - cell_values, - cell_width, - Self::MAX_CELL_BIT_WIDTH, - is_little_endian, - )?; - // TODO: is this safe, do we need to ensure that the padded cells are always 0? - pad_cells(circuit_builder, &mut values, Self::N_OPERAND_CELLS); - values.try_into() - } - - /// Generate ((0)_{2^C}, (1)_{2^C}, ..., (size - 1)_{2^C}) - pub fn counter_vector(size: usize) -> Vec> { - let num_vars = ceil_log2(size); - let number_of_limbs = (num_vars + C - 1) / C; - let cell_modulo = F::from(1 << C); - - let mut res = vec![vec![F::ZERO; number_of_limbs]]; - - for i in 1..size { - res.push(add_one_to_big_num(cell_modulo, &res[i - 1])); - } - - res - } -} - -/// Construct `UInt` from `Vec` -impl TryFrom> for UInt { - type Error = UtilError; - - fn try_from(values: Vec) -> Result { - if values.len() != Self::N_OPERAND_CELLS { - return Err(UtilError::UIntError(format!( - "cannot construct UInt<{}, {}> from {} cells, requires {} cells", - M, - C, - values.len(), - Self::N_OPERAND_CELLS - ))); - } - - Ok(Self { values }) - } -} - -/// Construct `UInt` from `$[CellId]` -impl TryFrom<&[CellId]> for UInt { - type Error = UtilError; - - fn try_from(values: &[CellId]) -> Result { - values.to_vec().try_into() - } -} - -#[cfg(test)] -mod tests { - use crate::uint::uint::UInt; - use gkr::structs::{Circuit, CircuitWitness}; - use goldilocks::{Goldilocks, GoldilocksExt2}; - use itertools::Itertools; - use simple_frontend::structs::CircuitBuilder; - - #[test] - fn test_uint_from_cell_ids() { - // 33 total bits and each cells holds just 4 bits - // to hold all 33 bits without truncations, we'd need 9 cells - // 9 * 4 = 36 > 33 - type UInt33 = UInt<33, 4>; - assert!(UInt33::try_from(vec![1, 2, 3, 4, 5, 6, 7, 8, 9]).is_ok()); - assert!(UInt33::try_from(vec![1, 2, 3]).is_err()); - assert!(UInt33::try_from(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).is_err()); - } - - #[test] - fn test_uint_from_different_sized_cell_values() { - // build circuit - let mut circuit_builder = CircuitBuilder::::new(); - let (_, small_values) = circuit_builder.create_witness_in(8); - type UInt30 = UInt<30, 6>; - let uint_instance = - UInt30::from_different_sized_cell_values(&mut circuit_builder, &small_values, 2, true) - .unwrap(); - circuit_builder.configure(); - let circuit = Circuit::new(&circuit_builder); - - // input - // we start with cells of bit width 2 (8 of them) - // 11 00 10 11 01 10 01 01 (bit representation) - // 3 0 2 3 1 2 1 1 (field representation) - // - // repacking into cells of bit width 6 - // 110010 110110 010100 - // since total bit = 30 then expect 5 cells ( 30 / 6) - // since we have 3 cells, we need to pad with 2 more - // hence expected output: - // 110010 110110 010100 000000 000000(bit representation) - // 50 54 20 0 0 - - let witness_values = vec![3, 0, 2, 3, 1, 2, 1, 1] - .into_iter() - .map(|v| Goldilocks::from(v)) - .collect_vec(); - let circuit_witness = { - let challenges = vec![GoldilocksExt2::from(2)]; - let mut circuit_witness = CircuitWitness::new(&circuit, challenges); - circuit_witness.add_instance(&circuit, vec![witness_values]); - circuit_witness - }; - circuit_witness.check_correctness(&circuit); - - let output = circuit_witness.output_layer_witness_ref().instances[0].to_vec(); - assert_eq!( - &output[..5], - vec![50, 54, 20, 0, 0] - .into_iter() - .map(|v| Goldilocks::from(v)) - .collect_vec() - ); - - // padding to power of 2 - assert_eq!( - &output[5..], - vec![0, 0, 0] - .into_iter() - .map(|v| Goldilocks::from(v)) - .collect_vec() - ); - } - - #[test] - fn test_counter_vector() { - // each limb has 5 bits so all number from 0..3 should require only 1 limb - type UInt30 = UInt<30, 5>; - let res = UInt30::counter_vector::(3); - assert_eq!( - res, - vec![ - vec![Goldilocks::from(0)], - vec![Goldilocks::from(1)], - vec![Goldilocks::from(2)] - ] - ); - - // each limb has a single bit, number from 0..5 should require 3 limbs each - type UInt50 = UInt<50, 1>; - let res = UInt50::counter_vector::(5); - assert_eq!( - res, - vec![ - // 0 - vec![ - Goldilocks::from(0), - Goldilocks::from(0), - Goldilocks::from(0) - ], - // 1 - vec![ - Goldilocks::from(1), - Goldilocks::from(0), - Goldilocks::from(0) - ], - // 2 - vec![ - Goldilocks::from(0), - Goldilocks::from(1), - Goldilocks::from(0) - ], - // 3 - vec![ - Goldilocks::from(1), - Goldilocks::from(1), - Goldilocks::from(0) - ], - // 4 - vec![ - Goldilocks::from(0), - Goldilocks::from(0), - Goldilocks::from(1) - ], - ] - ); - } -} diff --git a/singer-utils/src/uint/util.rs b/singer-utils/src/uint/util.rs deleted file mode 100644 index 6e39396cd..000000000 --- a/singer-utils/src/uint/util.rs +++ /dev/null @@ -1,330 +0,0 @@ -use crate::error::UtilError; -use ff_ext::ExtensionField; -use goldilocks::SmallField; -use itertools::Itertools; -use simple_frontend::structs::{CellId, CircuitBuilder}; - -/// Given some data represented by n small cells of size s -/// this function represents the same data in m big cells of size b -/// where b >= s -/// e.g. -/// information = 1100 -/// represented with 2 small cells of size 2 each -/// small -> 11 | 00 -/// we can pack this into a single big cell of size 4 -/// big -> 1100 -pub fn convert_decomp( - circuit_builder: &mut CircuitBuilder, - small_cells: &[CellId], - small_cell_bit_width: usize, - big_cell_bit_width: usize, - is_little_endian: bool, -) -> Result, UtilError> { - // TODO: technically there is a limit on the bit width (based on the field size), - // we should handle this edge case - // not sure this should (or can) be handled here tho - if small_cell_bit_width > big_cell_bit_width { - return Err(UtilError::UIntError( - "cannot pack bigger width cells into smaller width cells".to_string(), - )); - } - - if small_cell_bit_width == big_cell_bit_width { - return Ok(small_cells.to_vec()); - } - - // ensure the small cell values are in little endian form - let small_cells = if !is_little_endian { - small_cells.to_vec().into_iter().rev().collect() - } else { - small_cells.to_vec() - }; - - // compute the number of small cells that can fit into each big cell - let small_cell_count_per_big_cell = big_cell_bit_width / small_cell_bit_width; - - let mut new_cell_ids = vec![]; - - // iteratively take and pack n small cells into 1 big cell - for values in small_cells.chunks(small_cell_count_per_big_cell) { - let big_cell = circuit_builder.create_cell(); - for (small_chunk_index, small_bit_cell) in values.iter().enumerate() { - let shift_size = - (small_cell_count_per_big_cell - small_chunk_index - 1) * small_cell_bit_width; - circuit_builder.add( - big_cell, - *small_bit_cell, - E::BaseField::from(1 << shift_size), - ); - } - new_cell_ids.push(big_cell); - } - - Ok(new_cell_ids) -} - -/// Pads a `Vec` with new cells to reach some given size n -pub fn pad_cells( - circuit_builder: &mut CircuitBuilder, - cells: &mut Vec, - size: usize, -) { - if cells.len() < size { - cells.extend(circuit_builder.create_cells(size - cells.len())) - } -} - -/// Compile time evaluated minimum function -/// returns min(a, b) -pub const fn const_min(a: usize, b: usize) -> usize { - if a <= b { - a - } else { - b - } -} - -/// Assumes each limb < max_value -/// adds 1 to the big value, while preserving the above constraint -pub fn add_one_to_big_num(limb_modulo: F, limbs: &[F]) -> Vec { - let mut should_add_one = true; - let mut result = vec![]; - - for limb in limbs { - let mut new_limb_value = limb.clone(); - if should_add_one { - new_limb_value += F::ONE; - if new_limb_value == limb_modulo { - new_limb_value = F::ZERO; - } else { - should_add_one = false; - } - } - result.push(new_limb_value); - } - - result -} - -#[cfg(test)] -mod tests { - use crate::uint::util::{add_one_to_big_num, const_min, convert_decomp, pad_cells}; - use gkr::structs::{Circuit, CircuitWitness}; - use goldilocks::{Goldilocks, GoldilocksExt2}; - use itertools::Itertools; - use simple_frontend::structs::CircuitBuilder; - - #[test] - #[should_panic] - fn test_pack_big_cells_into_small_cells() { - let mut circuit_builder = CircuitBuilder::::new(); - let (_, big_values) = circuit_builder.create_witness_in(5); - let big_bit_width = 5; - let small_bit_width = 2; - let cell_packing_result = convert_decomp( - &mut circuit_builder, - &big_values, - big_bit_width, - small_bit_width, - true, - ) - .unwrap(); - } - - #[test] - fn test_pack_same_size_cells() { - let mut circuit_builder = CircuitBuilder::::new(); - let (_, initial_values) = circuit_builder.create_witness_in(5); - let small_bit_width = 2; - let big_bit_width = 2; - let new_values = convert_decomp( - &mut circuit_builder, - &initial_values, - small_bit_width, - big_bit_width, - true, - ) - .unwrap(); - assert_eq!(initial_values, new_values); - } - - #[test] - fn test_pack_small_cells_into_big_cells() { - let mut circuit_builder = CircuitBuilder::::new(); - let (_, small_values) = circuit_builder.create_witness_in(9); - let small_bit_width = 2; - let big_bit_width = 5; - let big_values = convert_decomp( - &mut circuit_builder, - &small_values, - small_bit_width, - big_bit_width, - true, - ) - .unwrap(); - assert_eq!(big_values.len(), 5); - - // verify construction against concrete witness values - circuit_builder.configure(); - let circuit = Circuit::new(&circuit_builder); - - // input - // we start with cells of bit width 2 (9 of them) - // 11 00 10 11 01 10 01 01 11 (bit representation) - // 3 0 2 3 1 2 1 1 3 (field representation) - // - // expected output - // repacking into cells of bit width 5 - // we can only fit two 2-bit cells into a 5 bit cell - // 1100 1011 0110 0101 1100 (bit representation) - // 12 11 6 5 12 (field representation) - - let witness_values = vec![3, 0, 2, 3, 1, 2, 1, 1, 3] - .into_iter() - .map(|v| Goldilocks::from(v)) - .collect::>(); - let circuit_witness = { - let challenges = vec![GoldilocksExt2::from(2)]; - let mut circuit_witness = CircuitWitness::new(&circuit, challenges); - circuit_witness.add_instance(&circuit, vec![witness_values]); - circuit_witness - }; - - circuit_witness.check_correctness(&circuit); - - let output = circuit_witness.output_layer_witness_ref().instances[0].to_vec(); - - assert_eq!( - &output[..5], - vec![12, 11, 6, 5, 12] - .into_iter() - .map(|v| Goldilocks::from(v)) - .collect::>() - ); - - // padding to power of 2 - assert_eq!( - &output[5..], - vec![0, 0, 0] - .into_iter() - .map(|v| Goldilocks::from(v)) - .collect_vec() - ); - } - - #[test] - fn test_pad_cells() { - let mut circuit_builder = CircuitBuilder::::new(); - let (_, mut small_values) = circuit_builder.create_witness_in(3); - // assert before padding - assert_eq!(small_values, vec![0, 1, 2]); - // pad - pad_cells(&mut circuit_builder, &mut small_values, 5); - // assert after padding - assert_eq!(small_values, vec![0, 1, 2, 3, 4]); - } - - #[test] - fn test_min_function() { - assert_eq!(const_min(2, 3), 2); - assert_eq!(const_min(3, 3), 3); - assert_eq!(const_min(5, 3), 3); - } - - #[test] - fn test_add_one_big_num() { - let limb_modulo = Goldilocks::from(2); - - // 000 - let initial_limbs = vec![Goldilocks::from(0); 3]; - - // 100 - let updated_limbs = add_one_to_big_num(limb_modulo, &initial_limbs); - assert_eq!( - updated_limbs, - vec![ - Goldilocks::from(1), - Goldilocks::from(0), - Goldilocks::from(0) - ] - ); - - // 010 - let updated_limbs = add_one_to_big_num(limb_modulo, &updated_limbs); - assert_eq!( - updated_limbs, - vec![ - Goldilocks::from(0), - Goldilocks::from(1), - Goldilocks::from(0) - ] - ); - - // 110 - let updated_limbs = add_one_to_big_num(limb_modulo, &updated_limbs); - assert_eq!( - updated_limbs, - vec![ - Goldilocks::from(1), - Goldilocks::from(1), - Goldilocks::from(0) - ] - ); - - // 001 - let updated_limbs = add_one_to_big_num(limb_modulo, &updated_limbs); - assert_eq!( - updated_limbs, - vec![ - Goldilocks::from(0), - Goldilocks::from(0), - Goldilocks::from(1) - ] - ); - - // 101 - let updated_limbs = add_one_to_big_num(limb_modulo, &updated_limbs); - assert_eq!( - updated_limbs, - vec![ - Goldilocks::from(1), - Goldilocks::from(0), - Goldilocks::from(1) - ] - ); - - // 011 - let updated_limbs = add_one_to_big_num(limb_modulo, &updated_limbs); - assert_eq!( - updated_limbs, - vec![ - Goldilocks::from(0), - Goldilocks::from(1), - Goldilocks::from(1) - ] - ); - - // 111 - let updated_limbs = add_one_to_big_num(limb_modulo, &updated_limbs); - assert_eq!( - updated_limbs, - vec![ - Goldilocks::from(1), - Goldilocks::from(1), - Goldilocks::from(1) - ] - ); - - // restart cycle - // 000 - let updated_limbs = add_one_to_big_num(limb_modulo, &updated_limbs); - assert_eq!( - updated_limbs, - vec![ - Goldilocks::from(0), - Goldilocks::from(0), - Goldilocks::from(0) - ] - ); - } -} diff --git a/singer-utils/src/uint/witness_extractors.rs b/singer-utils/src/uint/witness_extractors.rs deleted file mode 100644 index 258281e1c..000000000 --- a/singer-utils/src/uint/witness_extractors.rs +++ /dev/null @@ -1,40 +0,0 @@ -use crate::uint::constants::AddSubConstants; -use crate::uint::uint::UInt; -use simple_frontend::structs::CellId; - -// TODO: split this into different impls, constrained by specific contexts -// e.g add_sub, mul, ... -impl UInt { - // witness_structure - // [...range_values..., ...carry_witness...] - - pub fn extract_carry_add_sub(witness: &[CellId]) -> &[CellId] { - &witness[Self::N_RANGE_CELLS..] - } - - pub fn extract_carry_no_overflow_add_sub(witness: &[CellId]) -> &[CellId] { - &witness[AddSubConstants::::N_RANGE_CELLS_IN_CARRY_NO_OVERFLOW..] - } - - // TODO: why do we need this - pub fn extract_unsafe_carry_add_sub(witness: &[CellId]) -> &[CellId] { - witness - } - - pub fn extract_borrow_add_sub(witness: &[CellId]) -> &[CellId] { - &witness[Self::N_RANGE_CELLS..] - } - - // TODO: why do we need this - pub fn extract_unsafe_borrow_add_sub(witness: &[CellId]) -> &[CellId] { - witness - } - - pub fn extract_range_values(witness: &[CellId]) -> &[CellId] { - &witness[..Self::N_RANGE_CELLS] - } - - pub fn extract_range_values_no_overflow(witness: &[CellId]) -> &[CellId] { - &witness[..AddSubConstants::::N_RANGE_CELLS_IN_CARRY_NO_OVERFLOW] - } -} diff --git a/singer/src/instructions/add.rs b/singer/src/instructions/add.rs index b9c29da49..f03c9fc85 100644 --- a/singer/src/instructions/add.rs +++ b/singer/src/instructions/add.rs @@ -3,7 +3,6 @@ use ff_ext::ExtensionField; use gkr::structs::Circuit; use paste::paste; use simple_frontend::structs::{CircuitBuilder, MixedCell}; -use singer_utils::uint::constants::AddSubConstants; use singer_utils::{ chip_handler::{ BytecodeChipOperations, GlobalStateChipOperations, OAMOperations, ROMOperations, @@ -12,6 +11,7 @@ use singer_utils::{ constants::OpcodeType, register_witness, structs::{PCUInt, RAMHandler, ROMHandler, StackUInt, TSUInt}, + uint::{UIntAddSub, UIntCmp}, }; use std::sync::Arc; @@ -28,23 +28,23 @@ impl InstructionGraph for AddInstruction { register_witness!( AddInstruction, phase0 { - pc => PCUInt::N_OPERAND_CELLS, - stack_ts => TSUInt::N_OPERAND_CELLS, - memory_ts => TSUInt::N_OPERAND_CELLS, + pc => PCUInt::N_OPRAND_CELLS, + stack_ts => TSUInt::N_OPRAND_CELLS, + memory_ts => TSUInt::N_OPRAND_CELLS, stack_top => 1, clk => 1, - pc_add => AddSubConstants::::N_NO_OVERFLOW_WITNESS_UNSAFE_CELLS, - stack_ts_add => AddSubConstants::::N_WITNESS_CELLS_NO_CARRY_OVERFLOW, + pc_add => UIntAddSub::::N_NO_OVERFLOW_WITNESS_UNSAFE_CELLS, + stack_ts_add => UIntAddSub::::N_NO_OVERFLOW_WITNESS_CELLS, - old_stack_ts0 => TSUInt::N_OPERAND_CELLS, - old_stack_ts_lt0 => AddSubConstants::::N_WITNESS_CELLS_NO_CARRY_OVERFLOW, - old_stack_ts1 => TSUInt::N_OPERAND_CELLS, - old_stack_ts_lt1 => AddSubConstants::::N_WITNESS_CELLS_NO_CARRY_OVERFLOW, + old_stack_ts0 => TSUInt::N_OPRAND_CELLS, + old_stack_ts_lt0 => UIntCmp::::N_WITNESS_CELLS, + old_stack_ts1 => TSUInt::N_OPRAND_CELLS, + old_stack_ts_lt1 => UIntCmp::::N_WITNESS_CELLS, - addend_0 => StackUInt::N_OPERAND_CELLS, - addend_1 => StackUInt::N_OPERAND_CELLS, - instruction_add => AddSubConstants::::N_WITNESS_CELLS + addend_0 => StackUInt::N_OPRAND_CELLS, + addend_1 => StackUInt::N_OPRAND_CELLS, + instruction_add => UIntAddSub::::N_WITNESS_CELLS } ); @@ -100,7 +100,7 @@ impl Instruction for AddInstruction { "addInstCircuit::phase0_instruction_add: {:?}", Self::phase0_instruction_add() ); - let result = StackUInt::add( + let result = UIntAddSub::::add( &mut circuit_builder, &mut rom_handler, &addend_0, @@ -116,7 +116,7 @@ impl Instruction for AddInstruction { // Pop two values from stack let old_stack_ts0 = (&phase0[Self::phase0_old_stack_ts0()]).try_into()?; - TSUInt::assert_lt( + UIntCmp::::assert_lt( &mut circuit_builder, &mut rom_handler, &old_stack_ts0, @@ -131,7 +131,7 @@ impl Instruction for AddInstruction { ); let old_stack_ts1 = (&phase0[Self::phase0_old_stack_ts1()]).try_into()?; - TSUInt::assert_lt( + UIntCmp::::assert_lt( &mut circuit_builder, &mut rom_handler, &old_stack_ts1, @@ -189,7 +189,6 @@ mod test { use simple_frontend::structs::CellId; use singer_utils::constants::RANGE_CHIP_BIT_WIDTH; use singer_utils::structs::{StackUInt, TSUInt}; - use singer_utils::uint::constants::AddSubConstants; use std::collections::BTreeMap; use std::time::Instant; use transcript::Transcript; @@ -277,7 +276,7 @@ mod test { phase0_values_map.insert( "phase0_stack_ts_add".to_string(), vec![ - Goldilocks::from(4u64), // first TSUInt::N_RANGE_CELLS = 1*(56/16) = 4 cells are range values, stack_ts + 1 = 4 + Goldilocks::from(4u64), // first TSUInt::N_RANGE_CHECK_CELLS = 1*(56/16) = 4 cells are range values, stack_ts + 1 = 4 Goldilocks::from(0u64), Goldilocks::from(0u64), Goldilocks::from(0u64), @@ -289,7 +288,7 @@ mod test { vec![Goldilocks::from(2u64)], ); let m: u64 = (1 << get_uint_params::().1) - 1; - let range_values = u2vec::<{ TSUInt::N_RANGE_CELLS }, RANGE_CHIP_BIT_WIDTH>(m); + let range_values = u2vec::<{ TSUInt::N_RANGE_CHECK_CELLS }, RANGE_CHIP_BIT_WIDTH>(m); phase0_values_map.insert( "phase0_old_stack_ts_lt0".to_string(), vec![ @@ -305,7 +304,7 @@ mod test { vec![Goldilocks::from(1u64)], ); let m: u64 = (1 << get_uint_params::().1) - 2; - let range_values = u2vec::<{ TSUInt::N_RANGE_CELLS }, RANGE_CHIP_BIT_WIDTH>(m); + let range_values = u2vec::<{ TSUInt::N_RANGE_CHECK_CELLS }, RANGE_CHIP_BIT_WIDTH>(m); phase0_values_map.insert( "phase0_old_stack_ts_lt1".to_string(), vec![ @@ -319,7 +318,7 @@ mod test { let m: u64 = (1 << get_uint_params::().1) - 1; phase0_values_map.insert("phase0_addend_0".to_string(), vec![Goldilocks::from(m)]); phase0_values_map.insert("phase0_addend_1".to_string(), vec![Goldilocks::from(1u64)]); - let range_values = u2vec::<{ StackUInt::N_RANGE_CELLS }, RANGE_CHIP_BIT_WIDTH>(m + 1); + let range_values = u2vec::<{ StackUInt::N_RANGE_CHECK_CELLS }, RANGE_CHIP_BIT_WIDTH>(m + 1); let mut wit_phase0_instruction_add: Vec = vec![]; for i in 0..16 { wit_phase0_instruction_add.push(Goldilocks::from(range_values[i])) diff --git a/singer/src/instructions/calldataload.rs b/singer/src/instructions/calldataload.rs index 9bb0e4fa2..de1ee19d5 100644 --- a/singer/src/instructions/calldataload.rs +++ b/singer/src/instructions/calldataload.rs @@ -3,7 +3,6 @@ use ff_ext::ExtensionField; use gkr::structs::Circuit; use paste::paste; use simple_frontend::structs::{CircuitBuilder, MixedCell}; -use singer_utils::uint::constants::AddSubConstants; use singer_utils::{ chip_handler::{ BytecodeChipOperations, CalldataChipOperations, GlobalStateChipOperations, OAMOperations, @@ -12,6 +11,7 @@ use singer_utils::{ constants::OpcodeType, register_witness, structs::{PCUInt, RAMHandler, ROMHandler, StackUInt, TSUInt, UInt64}, + uint::{UIntAddSub, UIntCmp}, }; use std::sync::Arc; @@ -28,20 +28,20 @@ pub struct CalldataloadInstruction; register_witness!( CalldataloadInstruction, phase0 { - pc => PCUInt::N_OPERAND_CELLS, - stack_ts => TSUInt::N_OPERAND_CELLS, - memory_ts => TSUInt::N_OPERAND_CELLS, - ts => TSUInt::N_OPERAND_CELLS, + pc => PCUInt::N_OPRAND_CELLS, + stack_ts => TSUInt::N_OPRAND_CELLS, + memory_ts => TSUInt::N_OPRAND_CELLS, + ts => TSUInt::N_OPRAND_CELLS, stack_top => 1, clk => 1, - pc_add => AddSubConstants::::N_NO_OVERFLOW_WITNESS_UNSAFE_CELLS, - stack_ts_add => AddSubConstants::::N_WITNESS_CELLS_NO_CARRY_OVERFLOW, + pc_add => UIntAddSub::::N_NO_OVERFLOW_WITNESS_UNSAFE_CELLS, + stack_ts_add => UIntAddSub::::N_NO_OVERFLOW_WITNESS_CELLS, - data => StackUInt::N_OPERAND_CELLS, - offset => UInt64::N_OPERAND_CELLS, - old_stack_ts => TSUInt::N_OPERAND_CELLS, - old_stack_ts_lt => AddSubConstants::::N_WITNESS_CELLS + data => StackUInt::N_OPRAND_CELLS, + offset => UInt64::N_OPRAND_CELLS, + old_stack_ts => TSUInt::N_OPRAND_CELLS, + old_stack_ts_lt => UIntCmp::::N_WITNESS_CELLS } ); @@ -104,7 +104,7 @@ impl Instruction for CalldataloadInstruction { old_stack_ts.values(), offset, ); - TSUInt::assert_lt( + UIntCmp::::assert_lt( &mut circuit_builder, &mut rom_handler, &old_stack_ts, @@ -239,7 +239,7 @@ mod test { phase0_values_map.insert( "phase0_stack_ts_add".to_string(), vec![ - Goldilocks::from(4u64), // first TSUInt::N_RANGE_CELLS = 1*(56/16) = 4 cells are range values, stack_ts + 1 = 4 + Goldilocks::from(4u64), // first TSUInt::N_RANGE_CHECK_CELLS = 1*(56/16) = 4 cells are range values, stack_ts + 1 = 4 Goldilocks::from(0u64), Goldilocks::from(0u64), Goldilocks::from(0u64), @@ -251,7 +251,7 @@ mod test { vec![Goldilocks::from(2u64)], ); let m: u64 = (1 << get_uint_params::().1) - 1; - let range_values = u2vec::<{ TSUInt::N_RANGE_CELLS }, RANGE_CHIP_BIT_WIDTH>(m); + let range_values = u2vec::<{ TSUInt::N_RANGE_CHECK_CELLS }, RANGE_CHIP_BIT_WIDTH>(m); phase0_values_map.insert( "phase0_old_stack_ts_lt".to_string(), vec![ diff --git a/singer/src/instructions/dup.rs b/singer/src/instructions/dup.rs index 5835b1f2d..6f4dc7e92 100644 --- a/singer/src/instructions/dup.rs +++ b/singer/src/instructions/dup.rs @@ -3,7 +3,6 @@ use ff_ext::ExtensionField; use gkr::structs::Circuit; use paste::paste; use simple_frontend::structs::{CircuitBuilder, MixedCell}; -use singer_utils::uint::constants::AddSubConstants; use singer_utils::{ chip_handler::{ BytecodeChipOperations, GlobalStateChipOperations, OAMOperations, ROMOperations, @@ -12,6 +11,7 @@ use singer_utils::{ constants::OpcodeType, register_witness, structs::{PCUInt, RAMHandler, ROMHandler, StackUInt, TSUInt}, + uint::{UIntAddSub, UIntCmp}, }; use std::sync::Arc; @@ -28,18 +28,18 @@ impl InstructionGraph for DupInstruction, phase0 { - pc => PCUInt::N_OPERAND_CELLS, - stack_ts => TSUInt::N_OPERAND_CELLS, - memory_ts => TSUInt::N_OPERAND_CELLS, + pc => PCUInt::N_OPRAND_CELLS, + stack_ts => TSUInt::N_OPRAND_CELLS, + memory_ts => TSUInt::N_OPRAND_CELLS, stack_top => 1, clk => 1, - pc_add => AddSubConstants::::N_NO_OVERFLOW_WITNESS_UNSAFE_CELLS, - stack_ts_add => AddSubConstants::::N_WITNESS_CELLS_NO_CARRY_OVERFLOW, + pc_add => UIntAddSub::::N_NO_OVERFLOW_WITNESS_UNSAFE_CELLS, + stack_ts_add => UIntAddSub::::N_NO_OVERFLOW_WITNESS_CELLS, - stack_values => StackUInt::N_OPERAND_CELLS, - old_stack_ts => TSUInt::N_OPERAND_CELLS, - old_stack_ts_lt => AddSubConstants::::N_WITNESS_CELLS + stack_values => StackUInt::N_OPRAND_CELLS, + old_stack_ts => TSUInt::N_OPRAND_CELLS, + old_stack_ts_lt => UIntCmp::::N_WITNESS_CELLS } ); @@ -103,7 +103,7 @@ impl Instruction for DupInstruction { // Pop rlc of stack[top - N] from stack let old_stack_ts = (&phase0[Self::phase0_old_stack_ts()]).try_into()?; - TSUInt::assert_lt( + UIntCmp::::assert_lt( &mut circuit_builder, &mut rom_handler, &old_stack_ts, @@ -247,7 +247,7 @@ mod test { phase0_values_map.insert( "phase0_stack_ts_add".to_string(), vec![ - Goldilocks::from(3u64), // first TSUInt::N_RANGE_CELLS = 1*(56/16) = 4 cells are range values, stack_ts + 1 = 4 + Goldilocks::from(3u64), // first TSUInt::N_RANGE_CHECK_CELLS = 1*(56/16) = 4 cells are range values, stack_ts + 1 = 4 Goldilocks::from(0u64), Goldilocks::from(0u64), Goldilocks::from(0u64), @@ -272,7 +272,7 @@ mod test { vec![Goldilocks::from(1u64)], ); let m: u64 = (1 << get_uint_params::().1) - 1; - let range_values = u2vec::<{ TSUInt::N_RANGE_CELLS }, RANGE_CHIP_BIT_WIDTH>(m); + let range_values = u2vec::<{ TSUInt::N_RANGE_CHECK_CELLS }, RANGE_CHIP_BIT_WIDTH>(m); phase0_values_map.insert( "phase0_old_stack_ts_lt".to_string(), vec![ diff --git a/singer/src/instructions/gt.rs b/singer/src/instructions/gt.rs index b510ceba9..2b0165531 100644 --- a/singer/src/instructions/gt.rs +++ b/singer/src/instructions/gt.rs @@ -3,7 +3,6 @@ use ff_ext::ExtensionField; use gkr::structs::Circuit; use paste::paste; use simple_frontend::structs::{CircuitBuilder, MixedCell}; -use singer_utils::uint::constants::AddSubConstants; use singer_utils::{ chip_handler::{ BytecodeChipOperations, GlobalStateChipOperations, OAMOperations, ROMOperations, @@ -12,6 +11,7 @@ use singer_utils::{ constants::OpcodeType, register_witness, structs::{PCUInt, RAMHandler, ROMHandler, StackUInt, TSUInt}, + uint::{UIntAddSub, UIntCmp}, }; use std::sync::Arc; @@ -28,23 +28,23 @@ impl InstructionGraph for GtInstruction { register_witness!( GtInstruction, phase0 { - pc => PCUInt::N_OPERAND_CELLS, - stack_ts => TSUInt::N_OPERAND_CELLS, - memory_ts => TSUInt::N_OPERAND_CELLS, + pc => PCUInt::N_OPRAND_CELLS, + stack_ts => TSUInt::N_OPRAND_CELLS, + memory_ts => TSUInt::N_OPRAND_CELLS, stack_top => 1, clk => 1, - pc_add => AddSubConstants::::N_NO_OVERFLOW_WITNESS_UNSAFE_CELLS, - stack_ts_add => AddSubConstants::::N_WITNESS_CELLS_NO_CARRY_OVERFLOW, + pc_add => UIntAddSub::::N_NO_OVERFLOW_WITNESS_UNSAFE_CELLS, + stack_ts_add => UIntAddSub::::N_NO_OVERFLOW_WITNESS_CELLS, - old_stack_ts0 => TSUInt::N_OPERAND_CELLS, - old_stack_ts_lt0 => AddSubConstants::::N_WITNESS_CELLS, - old_stack_ts1 => TSUInt::N_OPERAND_CELLS, - old_stack_ts_lt1 => AddSubConstants::::N_WITNESS_CELLS, + old_stack_ts0 => TSUInt::N_OPRAND_CELLS, + old_stack_ts_lt0 => UIntCmp::::N_WITNESS_CELLS, + old_stack_ts1 => TSUInt::N_OPRAND_CELLS, + old_stack_ts_lt1 => UIntCmp::::N_WITNESS_CELLS, - oprand_0 => StackUInt::N_OPERAND_CELLS, - oprand_1 => StackUInt::N_OPERAND_CELLS, - instruction_gt => AddSubConstants::::N_WITNESS_CELLS + oprand_0 => StackUInt::N_OPRAND_CELLS, + oprand_1 => StackUInt::N_OPRAND_CELLS, + instruction_gt => UIntCmp::::N_WITNESS_CELLS } ); @@ -95,7 +95,7 @@ impl Instruction for GtInstruction { // Execution result = addend0 + addend1, with carry. let oprand_0 = (&phase0[Self::phase0_oprand_0()]).try_into()?; let oprand_1 = (&phase0[Self::phase0_oprand_1()]).try_into()?; - let (result, _) = StackUInt::lt( + let (result, _) = UIntCmp::::lt( &mut circuit_builder, &mut rom_handler, &oprand_1, @@ -111,7 +111,7 @@ impl Instruction for GtInstruction { // Pop two values from stack let old_stack_ts0 = (&phase0[Self::phase0_old_stack_ts0()]).try_into()?; - TSUInt::assert_lt( + UIntCmp::::assert_lt( &mut circuit_builder, &mut rom_handler, &old_stack_ts0, @@ -126,7 +126,7 @@ impl Instruction for GtInstruction { ); let old_stack_ts1 = (&phase0[Self::phase0_old_stack_ts1()]).try_into()?; - TSUInt::assert_lt( + UIntCmp::::assert_lt( &mut circuit_builder, &mut rom_handler, &old_stack_ts1, @@ -272,7 +272,7 @@ mod test { phase0_values_map.insert( "phase0_stack_ts_add".to_string(), vec![ - Goldilocks::from(4u64), // first TSUInt::N_RANGE_CELLS = 1*(56/16) = 4 cells are range values, stack_ts + 1 = 4 + Goldilocks::from(4u64), // first TSUInt::N_RANGE_CHECK_CELLS = 1*(56/16) = 4 cells are range values, stack_ts + 1 = 4 Goldilocks::from(0u64), Goldilocks::from(0u64), Goldilocks::from(0u64), @@ -284,7 +284,7 @@ mod test { vec![Goldilocks::from(2u64)], ); let m: u64 = (1 << get_uint_params::().1) - 1; - let range_values = u2vec::<{ TSUInt::N_RANGE_CELLS }, RANGE_CHIP_BIT_WIDTH>(m); + let range_values = u2vec::<{ TSUInt::N_RANGE_CHECK_CELLS }, RANGE_CHIP_BIT_WIDTH>(m); phase0_values_map.insert( "phase0_old_stack_ts_lt0".to_string(), vec![ @@ -300,7 +300,7 @@ mod test { vec![Goldilocks::from(1u64)], ); let m: u64 = (1 << get_uint_params::().1) - 2; - let range_values = u2vec::<{ TSUInt::N_RANGE_CELLS }, RANGE_CHIP_BIT_WIDTH>(m); + let range_values = u2vec::<{ TSUInt::N_RANGE_CHECK_CELLS }, RANGE_CHIP_BIT_WIDTH>(m); phase0_values_map.insert( "phase0_old_stack_ts_lt1".to_string(), vec![ diff --git a/singer/src/instructions/jump.rs b/singer/src/instructions/jump.rs index fd89d0554..35c1175a4 100644 --- a/singer/src/instructions/jump.rs +++ b/singer/src/instructions/jump.rs @@ -5,7 +5,6 @@ use ff_ext::ExtensionField; use gkr::structs::Circuit; use paste::paste; use simple_frontend::structs::{CircuitBuilder, MixedCell}; -use singer_utils::uint::constants::AddSubConstants; use singer_utils::{ chip_handler::{ BytecodeChipOperations, GlobalStateChipOperations, OAMOperations, ROMOperations, @@ -14,6 +13,7 @@ use singer_utils::{ constants::OpcodeType, register_witness, structs::{PCUInt, RAMHandler, ROMHandler, TSUInt}, + uint::UIntCmp, }; use crate::error::ZKVMError; @@ -29,16 +29,16 @@ impl InstructionGraph for JumpInstruction { register_witness!( JumpInstruction, phase0 { - pc => PCUInt::N_OPERAND_CELLS, - stack_ts => TSUInt::N_OPERAND_CELLS, - memory_ts => TSUInt::N_OPERAND_CELLS, + pc => PCUInt::N_OPRAND_CELLS, + stack_ts => TSUInt::N_OPRAND_CELLS, + memory_ts => TSUInt::N_OPRAND_CELLS, stack_top => 1, clk => 1, - next_pc => PCUInt::N_OPERAND_CELLS, + next_pc => PCUInt::N_OPRAND_CELLS, - old_stack_ts => TSUInt::N_OPERAND_CELLS, - old_stack_ts_lt => AddSubConstants::::N_WITNESS_CELLS + old_stack_ts => TSUInt::N_OPRAND_CELLS, + old_stack_ts_lt => UIntCmp::::N_WITNESS_CELLS } ); @@ -74,7 +74,7 @@ impl Instruction for JumpInstruction { let next_pc = &phase0[Self::phase0_next_pc()]; let old_stack_ts = (&phase0[Self::phase0_old_stack_ts()]).try_into()?; - TSUInt::assert_lt( + UIntCmp::::assert_lt( &mut circuit_builder, &mut rom_handler, &old_stack_ts, @@ -205,7 +205,7 @@ mod test { vec![Goldilocks::from(1u64)], ); let m: u64 = (1 << get_uint_params::().1) - 1; - let range_values = u2vec::<{ TSUInt::N_RANGE_CELLS }, RANGE_CHIP_BIT_WIDTH>(m); + let range_values = u2vec::<{ TSUInt::N_RANGE_CHECK_CELLS }, RANGE_CHIP_BIT_WIDTH>(m); phase0_values_map.insert( "phase0_old_stack_ts_lt".to_string(), vec![ diff --git a/singer/src/instructions/jumpdest.rs b/singer/src/instructions/jumpdest.rs index f21874575..99cd73343 100644 --- a/singer/src/instructions/jumpdest.rs +++ b/singer/src/instructions/jumpdest.rs @@ -3,7 +3,6 @@ use ff_ext::ExtensionField; use gkr::structs::Circuit; use paste::paste; use simple_frontend::structs::{CircuitBuilder, MixedCell}; -use singer_utils::uint::constants::AddSubConstants; use singer_utils::{ chip_handler::{ BytecodeChipOperations, GlobalStateChipOperations, OAMOperations, ROMOperations, @@ -11,6 +10,7 @@ use singer_utils::{ constants::OpcodeType, register_witness, structs::{PCUInt, RAMHandler, ROMHandler, TSUInt}, + uint::UIntAddSub, }; use std::sync::Arc; @@ -27,13 +27,13 @@ impl InstructionGraph for JumpdestInstruction { register_witness!( JumpdestInstruction, phase0 { - pc => PCUInt::N_OPERAND_CELLS , - stack_ts=> TSUInt::N_OPERAND_CELLS, - memory_ts => TSUInt::N_OPERAND_CELLS, + pc => PCUInt::N_OPRAND_CELLS , + stack_ts=> TSUInt::N_OPRAND_CELLS, + memory_ts => TSUInt::N_OPRAND_CELLS, stack_top => 1, clk => 1, - pc_add => AddSubConstants::::N_NO_OVERFLOW_WITNESS_UNSAFE_CELLS + pc_add => UIntAddSub::::N_NO_OVERFLOW_WITNESS_UNSAFE_CELLS } ); diff --git a/singer/src/instructions/jumpi.rs b/singer/src/instructions/jumpi.rs index f1197f81f..d3d4c4103 100644 --- a/singer/src/instructions/jumpi.rs +++ b/singer/src/instructions/jumpi.rs @@ -4,7 +4,6 @@ use gkr::structs::Circuit; use itertools::izip; use paste::paste; use simple_frontend::structs::{CircuitBuilder, MixedCell}; -use singer_utils::uint::constants::AddSubConstants; use singer_utils::{ chip_handler::{ BytecodeChipOperations, GlobalStateChipOperations, OAMOperations, ROMOperations, @@ -13,6 +12,7 @@ use singer_utils::{ constants::OpcodeType, register_witness, structs::{PCUInt, RAMHandler, ROMHandler, StackUInt, TSUInt}, + uint::{UIntAddSub, UIntCmp}, }; use std::sync::Arc; @@ -29,23 +29,23 @@ impl InstructionGraph for JumpiInstruction { register_witness!( JumpiInstruction, phase0 { - pc => PCUInt::N_OPERAND_CELLS , - stack_ts => TSUInt::N_OPERAND_CELLS, - memory_ts => TSUInt::N_OPERAND_CELLS, + pc => PCUInt::N_OPRAND_CELLS , + stack_ts => TSUInt::N_OPRAND_CELLS, + memory_ts => TSUInt::N_OPRAND_CELLS, stack_top => 1, clk => 1, - old_stack_ts_dest => TSUInt::N_OPERAND_CELLS, - old_stack_ts_dest_lt => AddSubConstants::::N_WITNESS_CELLS_NO_CARRY_OVERFLOW, - old_stack_ts_cond => TSUInt::N_OPERAND_CELLS, - old_stack_ts_cond_lt => AddSubConstants::::N_WITNESS_CELLS_NO_CARRY_OVERFLOW, + old_stack_ts_dest => TSUInt::N_OPRAND_CELLS, + old_stack_ts_dest_lt => UIntCmp::::N_NO_OVERFLOW_WITNESS_CELLS, + old_stack_ts_cond => TSUInt::N_OPRAND_CELLS, + old_stack_ts_cond_lt => UIntCmp::::N_NO_OVERFLOW_WITNESS_CELLS, - dest_values => StackUInt::N_OPERAND_CELLS, - cond_values => StackUInt::N_OPERAND_CELLS, - cond_values_inv => StackUInt::N_OPERAND_CELLS, + dest_values => StackUInt::N_OPRAND_CELLS, + cond_values => StackUInt::N_OPRAND_CELLS, + cond_values_inv => StackUInt::N_OPRAND_CELLS, cond_non_zero_or_inv => 1, - pc_add => AddSubConstants::::N_NO_OVERFLOW_WITNESS_UNSAFE_CELLS, + pc_add => UIntAddSub::::N_NO_OVERFLOW_WITNESS_UNSAFE_CELLS, pc_plus_1_opcode => 1 } ); @@ -87,7 +87,7 @@ impl Instruction for JumpiInstruction { let dest_stack_addr = stack_top_expr.sub(E::BaseField::ONE); let old_stack_ts_dest = (&phase0[Self::phase0_old_stack_ts_dest()]).try_into()?; - TSUInt::assert_lt( + UIntCmp::::assert_lt( &mut circuit_builder, &mut rom_handler, &old_stack_ts_dest, @@ -104,7 +104,7 @@ impl Instruction for JumpiInstruction { // Pop the condition from stack. let cond_values = &phase0[Self::phase0_cond_values()]; let old_stack_ts_cond = (&phase0[Self::phase0_old_stack_ts_cond()]).try_into()?; - TSUInt::assert_lt( + UIntCmp::::assert_lt( &mut circuit_builder, &mut rom_handler, &old_stack_ts_cond, @@ -138,8 +138,8 @@ impl Instruction for JumpiInstruction { let pc_add_1 = &phase0[Self::phase0_pc_add()]; let pc_plus_1 = ROMHandler::add_pc_const(&mut circuit_builder, &pc, 1, pc_add_1)?; let pc_plus_1 = pc_plus_1.values(); - let next_pc = circuit_builder.create_cells(PCUInt::N_OPERAND_CELLS); - for i in 0..PCUInt::N_OPERAND_CELLS { + let next_pc = circuit_builder.create_cells(PCUInt::N_OPRAND_CELLS); + for i in 0..PCUInt::N_OPRAND_CELLS { circuit_builder.select(next_pc[i], pc_plus_1[i], dest_values[i], cond_non_zero); } diff --git a/singer/src/instructions/mstore.rs b/singer/src/instructions/mstore.rs index a96835a89..7185454d9 100644 --- a/singer/src/instructions/mstore.rs +++ b/singer/src/instructions/mstore.rs @@ -4,7 +4,6 @@ use gkr::structs::Circuit; use gkr_graph::structs::{CircuitGraphBuilder, NodeOutputType, PredType}; use paste::paste; use simple_frontend::structs::{CircuitBuilder, MixedCell}; -use singer_utils::uint::constants::AddSubConstants; use singer_utils::{ chip_handler::{ BytecodeChipOperations, GlobalStateChipOperations, MemoryChipOperations, OAMOperations, @@ -14,6 +13,7 @@ use singer_utils::{ constants::{OpcodeType, EVM_STACK_BYTE_WIDTH}, register_witness, structs::{PCUInt, RAMHandler, ROMHandler, StackUInt, TSUInt}, + uint::{UIntAddSub, UIntCmp}, }; use std::{mem, sync::Arc}; @@ -140,21 +140,21 @@ impl InstructionGraph for MstoreInstruction { register_witness!( MstoreInstruction, phase0 { - pc => PCUInt::N_OPERAND_CELLS, - stack_ts => TSUInt::N_OPERAND_CELLS, - memory_ts => TSUInt::N_OPERAND_CELLS, + pc => PCUInt::N_OPRAND_CELLS, + stack_ts => TSUInt::N_OPRAND_CELLS, + memory_ts => TSUInt::N_OPRAND_CELLS, stack_top => 1, clk => 1, - pc_add => AddSubConstants::::N_NO_OVERFLOW_WITNESS_UNSAFE_CELLS, - memory_ts_add => AddSubConstants::::N_WITNESS_CELLS_NO_CARRY_OVERFLOW, + pc_add => UIntAddSub::::N_NO_OVERFLOW_WITNESS_UNSAFE_CELLS, + memory_ts_add => UIntAddSub::::N_NO_OVERFLOW_WITNESS_CELLS, - offset => StackUInt::N_OPERAND_CELLS, + offset => StackUInt::N_OPRAND_CELLS, mem_bytes => EVM_STACK_BYTE_WIDTH, - old_stack_ts_offset => TSUInt::N_OPERAND_CELLS, - old_stack_ts_lt_offset => AddSubConstants::::N_WITNESS_CELLS, - old_stack_ts_value => TSUInt::N_OPERAND_CELLS, - old_stack_ts_lt_value => AddSubConstants::::N_WITNESS_CELLS + old_stack_ts_offset => TSUInt::N_OPRAND_CELLS, + old_stack_ts_lt_offset => UIntCmp::::N_WITNESS_CELLS, + old_stack_ts_value => TSUInt::N_OPRAND_CELLS, + old_stack_ts_lt_value => UIntCmp::::N_WITNESS_CELLS } ); @@ -209,7 +209,7 @@ impl Instruction for MstoreInstruction { // Pop offset from stack let offset = StackUInt::try_from(&phase0[Self::phase0_offset()])?; let old_stack_ts_offset = TSUInt::try_from(&phase0[Self::phase0_old_stack_ts_offset()])?; - TSUInt::assert_lt( + UIntCmp::::assert_lt( &mut circuit_builder, &mut rom_handler, &old_stack_ts_offset, @@ -227,9 +227,9 @@ impl Instruction for MstoreInstruction { let mem_bytes = &phase0[Self::phase0_mem_bytes()]; rom_handler.range_check_bytes(&mut circuit_builder, mem_bytes)?; - let mem_value = StackUInt::from_bytes_big_endian(&mut circuit_builder, &mem_bytes)?; + let mem_value = StackUInt::from_bytes_big_endien(&mut circuit_builder, &mem_bytes)?; let old_stack_ts_value = TSUInt::try_from(&phase0[Self::phase0_old_stack_ts_value()])?; - TSUInt::assert_lt( + UIntCmp::::assert_lt( &mut circuit_builder, &mut rom_handler, &old_stack_ts_value, @@ -292,17 +292,17 @@ pub struct MstoreAccessory; register_witness!( MstoreAccessory, pred_dup { - memory_ts => TSUInt::N_OPERAND_CELLS, - offset => StackUInt::N_OPERAND_CELLS + memory_ts => TSUInt::N_OPRAND_CELLS, + offset => StackUInt::N_OPRAND_CELLS }, pred_ooo { mem_bytes => 1 }, phase0 { - old_memory_ts => TSUInt::N_OPERAND_CELLS, - old_memory_ts_lt => AddSubConstants::::N_WITNESS_CELLS_NO_CARRY_OVERFLOW, + old_memory_ts => TSUInt::N_OPRAND_CELLS, + old_memory_ts_lt => UIntCmp::::N_NO_OVERFLOW_WITNESS_CELLS, - offset_add_delta => AddSubConstants::::N_WITNESS_CELLS, + offset_add_delta => UIntAddSub::::N_WITNESS_CELLS, prev_mem_bytes => 1 } ); @@ -331,14 +331,14 @@ impl MstoreAccessory { let offset = StackUInt::try_from(&pred_dup[Self::pred_dup_offset()])?; let offset_add_delta = &phase0[Self::phase0_offset_add_delta()]; let delta = circuit_builder.create_counter_in(0)[0]; - let offset_plus_delta = StackUInt::add_cell( + let offset_plus_delta = UIntAddSub::::add_small( &mut circuit_builder, &mut rom_handler, &offset, delta, offset_add_delta, )?; - TSUInt::assert_lt( + UIntCmp::::assert_lt( &mut circuit_builder, &mut rom_handler, &old_memory_ts, @@ -478,7 +478,7 @@ mod test { phase0_values_map.insert( "phase0_memory_ts_add".to_string(), vec![ - Goldilocks::from(4u64), // first TSUInt::N_RANGE_CELLS = 1*(56/16) = 4 cells are range values, memory_ts + 1 = 4 + Goldilocks::from(4u64), // first TSUInt::N_RANGE_CHECK_CELLS = 1*(56/16) = 4 cells are range values, memory_ts + 1 = 4 Goldilocks::from(0u64), Goldilocks::from(0u64), Goldilocks::from(0u64), @@ -491,7 +491,7 @@ mod test { vec![Goldilocks::from(2u64)], ); let m: u64 = (1 << get_uint_params::().1) - 1; - let range_values = u2vec::<{ TSUInt::N_RANGE_CELLS }, RANGE_CHIP_BIT_WIDTH>(m); + let range_values = u2vec::<{ TSUInt::N_RANGE_CHECK_CELLS }, RANGE_CHIP_BIT_WIDTH>(m); phase0_values_map.insert( "phase0_old_stack_ts_lt_offset".to_string(), vec![ @@ -511,7 +511,7 @@ mod test { vec![Goldilocks::from(1u64)], ); let m: u64 = (1 << get_uint_params::().1) - 2; - let range_values = u2vec::<{ TSUInt::N_RANGE_CELLS }, RANGE_CHIP_BIT_WIDTH>(m); + let range_values = u2vec::<{ TSUInt::N_RANGE_CHECK_CELLS }, RANGE_CHIP_BIT_WIDTH>(m); phase0_values_map.insert( "phase0_old_stack_ts_lt_value".to_string(), vec![ diff --git a/singer/src/instructions/pop.rs b/singer/src/instructions/pop.rs index 3d07b8abd..32f083671 100644 --- a/singer/src/instructions/pop.rs +++ b/singer/src/instructions/pop.rs @@ -3,7 +3,6 @@ use ff_ext::ExtensionField; use gkr::structs::Circuit; use paste::paste; use simple_frontend::structs::{CircuitBuilder, MixedCell}; -use singer_utils::uint::constants::AddSubConstants; use singer_utils::{ chip_handler::{ BytecodeChipOperations, GlobalStateChipOperations, OAMOperations, ROMOperations, @@ -12,6 +11,7 @@ use singer_utils::{ constants::OpcodeType, register_witness, structs::{PCUInt, RAMHandler, ROMHandler, StackUInt, TSUInt}, + uint::{UIntAddSub, UIntCmp}, }; use std::sync::Arc; @@ -27,17 +27,17 @@ impl InstructionGraph for PopInstruction { register_witness!( PopInstruction, phase0 { - pc => PCUInt::N_OPERAND_CELLS, - stack_ts => TSUInt::N_OPERAND_CELLS, - memory_ts => TSUInt::N_OPERAND_CELLS, + pc => PCUInt::N_OPRAND_CELLS, + stack_ts => TSUInt::N_OPRAND_CELLS, + memory_ts => TSUInt::N_OPRAND_CELLS, stack_top => 1, clk => 1, - pc_add => AddSubConstants::::N_NO_OVERFLOW_WITNESS_UNSAFE_CELLS, + pc_add => UIntAddSub::::N_NO_OVERFLOW_WITNESS_UNSAFE_CELLS, - old_stack_ts => TSUInt::N_OPERAND_CELLS, - old_stack_ts_lt => AddSubConstants::::N_WITNESS_CELLS, - stack_values => StackUInt::N_OPERAND_CELLS + old_stack_ts => TSUInt::N_OPRAND_CELLS, + old_stack_ts_lt => UIntCmp::::N_WITNESS_CELLS, + stack_values => StackUInt::N_OPRAND_CELLS } ); @@ -84,7 +84,7 @@ impl Instruction for PopInstruction { // Pop rlc from stack let old_stack_ts = (&phase0[Self::phase0_old_stack_ts()]).try_into()?; - TSUInt::assert_lt( + UIntCmp::::assert_lt( &mut circuit_builder, &mut rom_handler, &old_stack_ts, @@ -210,7 +210,7 @@ mod test { vec![Goldilocks::from(1u64)], ); let m: u64 = (1 << get_uint_params::().1) - 1; - let range_values = u2vec::<{ TSUInt::N_RANGE_CELLS }, RANGE_CHIP_BIT_WIDTH>(m); + let range_values = u2vec::<{ TSUInt::N_RANGE_CHECK_CELLS }, RANGE_CHIP_BIT_WIDTH>(m); phase0_values_map.insert( "phase0_old_stack_ts_lt".to_string(), vec![ diff --git a/singer/src/instructions/push.rs b/singer/src/instructions/push.rs index e42661b5a..6dfe7084f 100644 --- a/singer/src/instructions/push.rs +++ b/singer/src/instructions/push.rs @@ -3,7 +3,6 @@ use ff_ext::ExtensionField; use gkr::structs::Circuit; use paste::paste; use simple_frontend::structs::{CircuitBuilder, MixedCell}; -use singer_utils::uint::constants::AddSubConstants; use singer_utils::{ chip_handler::{ BytecodeChipOperations, GlobalStateChipOperations, OAMOperations, ROMOperations, @@ -12,6 +11,7 @@ use singer_utils::{ constants::OpcodeType, register_witness, structs::{PCUInt, RAMHandler, ROMHandler, StackUInt, TSUInt}, + uint::UIntAddSub, }; use std::sync::Arc; @@ -28,14 +28,14 @@ impl InstructionGraph for PushInstruction< register_witness!( PushInstruction, phase0 { - pc => PCUInt::N_OPERAND_CELLS, - stack_ts => TSUInt::N_OPERAND_CELLS, - memory_ts => TSUInt::N_OPERAND_CELLS, + pc => PCUInt::N_OPRAND_CELLS, + stack_ts => TSUInt::N_OPRAND_CELLS, + memory_ts => TSUInt::N_OPRAND_CELLS, stack_top => 1, clk => 1, - pc_add_i_plus_1 => N * AddSubConstants::::N_NO_OVERFLOW_WITNESS_UNSAFE_CELLS, - stack_ts_add => AddSubConstants::::N_WITNESS_CELLS_NO_CARRY_OVERFLOW, + pc_add_i_plus_1 => N * UIntAddSub::::N_NO_OVERFLOW_WITNESS_UNSAFE_CELLS, + stack_ts_add => UIntAddSub::::N_NO_OVERFLOW_WITNESS_CELLS, stack_bytes => N } @@ -98,7 +98,7 @@ impl Instruction for PushInstruction { rom_handler.range_check_stack_top(&mut circuit_builder, stack_top_expr)?; let stack_bytes = &phase0[Self::phase0_stack_bytes()]; - let stack_values = StackUInt::from_bytes_big_endian(&mut circuit_builder, stack_bytes)?; + let stack_values = StackUInt::from_bytes_big_endien(&mut circuit_builder, stack_bytes)?; // Push value to stack ram_handler.stack_push( &mut circuit_builder, @@ -114,7 +114,7 @@ impl Instruction for PushInstruction { >::OPCODE, ); for (i, pc_add_i_plus_1) in phase0[Self::phase0_pc_add_i_plus_1()] - .chunks(AddSubConstants::::N_NO_OVERFLOW_WITNESS_UNSAFE_CELLS) + .chunks(UIntAddSub::::N_NO_OVERFLOW_WITNESS_UNSAFE_CELLS) .enumerate() { let next_pc = @@ -221,7 +221,7 @@ mod test { phase0_values_map.insert( "phase0_stack_ts_add".to_string(), vec![ - Goldilocks::from(2u64), // first TSUInt::N_RANGE_CELLS = 1*(56/16) = 4 cells are range values, stack_ts + 1 = 4 + Goldilocks::from(2u64), // first TSUInt::N_RANGE_CHECK_CELLS = 1*(56/16) = 4 cells are range values, stack_ts + 1 = 4 Goldilocks::from(0u64), Goldilocks::from(0u64), Goldilocks::from(0u64), diff --git a/singer/src/instructions/ret.rs b/singer/src/instructions/ret.rs index 4a160031f..ac24c2efa 100644 --- a/singer/src/instructions/ret.rs +++ b/singer/src/instructions/ret.rs @@ -4,7 +4,6 @@ use gkr::structs::Circuit; use gkr_graph::structs::{CircuitGraphBuilder, NodeOutputType, PredType}; use paste::paste; use simple_frontend::structs::{CircuitBuilder, MixedCell}; -use singer_utils::uint::constants::AddSubConstants; use singer_utils::{ chip_handler::{ BytecodeChipOperations, GlobalStateChipOperations, OAMOperations, ROMOperations, @@ -14,6 +13,7 @@ use singer_utils::{ constants::OpcodeType, register_witness, structs::{PCUInt, RAMHandler, ROMHandler, StackUInt, TSUInt}, + uint::UIntAddSub, }; use std::{mem, sync::Arc}; @@ -262,17 +262,17 @@ impl InstructionGraph for ReturnInstruction { register_witness!( ReturnInstruction, phase0 { - pc => PCUInt::N_OPERAND_CELLS, - stack_ts => TSUInt::N_OPERAND_CELLS, - memory_ts => TSUInt::N_OPERAND_CELLS, + pc => PCUInt::N_OPRAND_CELLS, + stack_ts => TSUInt::N_OPRAND_CELLS, + memory_ts => TSUInt::N_OPRAND_CELLS, stack_top => 1, clk => 1, - old_stack_ts0 => TSUInt::N_OPERAND_CELLS, - old_stack_ts1 => TSUInt::N_OPERAND_CELLS, + old_stack_ts0 => TSUInt::N_OPRAND_CELLS, + old_stack_ts1 => TSUInt::N_OPRAND_CELLS, - offset => StackUInt::N_OPERAND_CELLS, - mem_length => StackUInt::N_OPERAND_CELLS + offset => StackUInt::N_OPRAND_CELLS, + mem_length => StackUInt::N_OPRAND_CELLS } ); @@ -341,7 +341,7 @@ impl Instruction for ReturnInstruction { // Copy length to the target wire. let (target_wire_id, target) = - circuit_builder.create_witness_out(StackUInt::N_OPERAND_CELLS); + circuit_builder.create_witness_out(StackUInt::N_OPRAND_CELLS); let length = length.values(); for i in 1..length.len() { circuit_builder.assert_const(length[i], 0); @@ -377,15 +377,15 @@ impl Instruction for ReturnInstruction { register_witness!( ReturnPublicOutLoad, pred { - offset => StackUInt::N_OPERAND_CELLS + offset => StackUInt::N_OPRAND_CELLS }, public_io { byte => 1 }, phase0 { - old_memory_ts => TSUInt::N_OPERAND_CELLS, + old_memory_ts => TSUInt::N_OPRAND_CELLS, - offset_add => AddSubConstants::::N_WITNESS_CELLS + offset_add => UIntAddSub::::N_WITNESS_CELLS } ); @@ -403,7 +403,7 @@ impl ReturnPublicOutLoad { let delta = circuit_builder.create_counter_in(0); let offset = StackUInt::try_from(&pred[Self::pred_offset()])?; let offset_add_delta_witness = &phase0[Self::phase0_offset_add()]; - let new_offset = StackUInt::add_cell( + let new_offset = UIntAddSub::::add_small( &mut circuit_builder, &mut rom_handler, &offset, @@ -447,8 +447,8 @@ register_witness!( ReturnRestMemLoad, phase0 { mem_byte => 1, - offset => StackUInt::N_OPERAND_CELLS, - old_memory_ts => TSUInt::N_OPERAND_CELLS + offset => StackUInt::N_OPRAND_CELLS, + old_memory_ts => TSUInt::N_OPRAND_CELLS } ); @@ -495,7 +495,7 @@ register_witness!( ReturnRestMemStore, phase0 { mem_byte => 1, - offset => StackUInt::N_OPERAND_CELLS + offset => StackUInt::N_OPRAND_CELLS } ); @@ -510,7 +510,7 @@ impl ReturnRestMemStore { // Load from memory let offset = &phase0[Self::phase0_offset()]; let mem_byte = phase0[Self::phase0_mem_byte().start]; - let memory_ts = circuit_builder.create_cells(StackUInt::N_OPERAND_CELLS); + let memory_ts = circuit_builder.create_cells(StackUInt::N_OPRAND_CELLS); ram_handler.oam_store(&mut circuit_builder, offset, &memory_ts, &[mem_byte]); let (ram_load_id, ram_store_id) = ram_handler.finalize(&mut circuit_builder); @@ -538,8 +538,8 @@ pub struct ReturnRestStackPop; register_witness!( ReturnRestStackPop, phase0 { - old_stack_ts => TSUInt::N_OPERAND_CELLS, - stack_values => StackUInt::N_OPERAND_CELLS + old_stack_ts => TSUInt::N_OPRAND_CELLS, + stack_values => StackUInt::N_OPRAND_CELLS } ); diff --git a/singer/src/instructions/swap.rs b/singer/src/instructions/swap.rs index ea8f0f126..5c944652a 100644 --- a/singer/src/instructions/swap.rs +++ b/singer/src/instructions/swap.rs @@ -3,7 +3,6 @@ use ff_ext::ExtensionField; use gkr::structs::Circuit; use paste::paste; use simple_frontend::structs::{CircuitBuilder, MixedCell}; -use singer_utils::uint::constants::AddSubConstants; use singer_utils::{ chip_handler::{ BytecodeChipOperations, GlobalStateChipOperations, OAMOperations, ROMOperations, @@ -12,6 +11,7 @@ use singer_utils::{ constants::OpcodeType, register_witness, structs::{PCUInt, RAMHandler, ROMHandler, StackUInt, TSUInt}, + uint::{UIntAddSub, UIntCmp}, }; use std::sync::Arc; @@ -27,21 +27,21 @@ impl InstructionGraph for SwapInstruction< register_witness!( SwapInstruction, phase0 { - pc => PCUInt::N_OPERAND_CELLS, - stack_ts => TSUInt::N_OPERAND_CELLS, - memory_ts => TSUInt::N_OPERAND_CELLS, + pc => PCUInt::N_OPRAND_CELLS, + stack_ts => TSUInt::N_OPRAND_CELLS, + memory_ts => TSUInt::N_OPRAND_CELLS, stack_top => 1, clk => 1, - pc_add => AddSubConstants::::N_NO_OVERFLOW_WITNESS_UNSAFE_CELLS, - stack_ts_add => AddSubConstants::::N_WITNESS_CELLS_NO_CARRY_OVERFLOW, + pc_add => UIntAddSub::::N_NO_OVERFLOW_WITNESS_UNSAFE_CELLS, + stack_ts_add => UIntAddSub::::N_NO_OVERFLOW_WITNESS_CELLS, - old_stack_ts_1 => TSUInt::N_OPERAND_CELLS, - old_stack_ts_lt_1 => AddSubConstants::::N_WITNESS_CELLS, - old_stack_ts_n_plus_1 => TSUInt::N_OPERAND_CELLS, - old_stack_ts_lt_n_plus_1 => AddSubConstants::::N_WITNESS_CELLS, - stack_values_1 => StackUInt::N_OPERAND_CELLS, - stack_values_n_plus_1 => StackUInt::N_OPERAND_CELLS + old_stack_ts_1 => TSUInt::N_OPRAND_CELLS, + old_stack_ts_lt_1 => UIntCmp::::N_WITNESS_CELLS, + old_stack_ts_n_plus_1 => TSUInt::N_OPRAND_CELLS, + old_stack_ts_lt_n_plus_1 => UIntCmp::::N_WITNESS_CELLS, + stack_values_1 => StackUInt::N_OPRAND_CELLS, + stack_values_n_plus_1 => StackUInt::N_OPRAND_CELLS } ); @@ -107,7 +107,7 @@ impl Instruction for SwapInstruction { // Pop rlc of stack[top - (N + 1)] from stack let old_stack_ts_n_plus_1 = (&phase0[Self::phase0_old_stack_ts_n_plus_1()]).try_into()?; - TSUInt::assert_lt( + UIntCmp::::assert_lt( &mut circuit_builder, &mut rom_handler, &old_stack_ts_n_plus_1, @@ -124,7 +124,7 @@ impl Instruction for SwapInstruction { // Pop rlc of stack[top - 1] from stack let old_stack_ts_1 = (&phase0[Self::phase0_old_stack_ts_1()]).try_into()?; - TSUInt::assert_lt( + UIntCmp::::assert_lt( &mut circuit_builder, &mut rom_handler, &old_stack_ts_1, @@ -279,7 +279,7 @@ mod test { phase0_values_map.insert( "phase0_stack_ts_add".to_string(), vec![ - Goldilocks::from(5u64), // first TSUInt::N_RANGE_CELLS = 1*(56/16) = 4 cells are range values, stack_ts + 1 = 4 + Goldilocks::from(5u64), // first TSUInt::N_RANGE_CHECK_CELLS = 1*(56/16) = 4 cells are range values, stack_ts + 1 = 4 Goldilocks::from(0u64), Goldilocks::from(0u64), Goldilocks::from(0u64), @@ -291,7 +291,7 @@ mod test { vec![Goldilocks::from(3u64)], ); let m: u64 = (1 << get_uint_params::().1) - 1; - let range_values = u2vec::<{ TSUInt::N_RANGE_CELLS }, RANGE_CHIP_BIT_WIDTH>(m); + let range_values = u2vec::<{ TSUInt::N_RANGE_CHECK_CELLS }, RANGE_CHIP_BIT_WIDTH>(m); phase0_values_map.insert( "phase0_old_stack_ts_lt_1".to_string(), vec![ @@ -307,7 +307,7 @@ mod test { vec![Goldilocks::from(1u64)], ); let m: u64 = (1 << get_uint_params::().1) - 3; - let range_values = u2vec::<{ TSUInt::N_RANGE_CELLS }, RANGE_CHIP_BIT_WIDTH>(m); + let range_values = u2vec::<{ TSUInt::N_RANGE_CHECK_CELLS }, RANGE_CHIP_BIT_WIDTH>(m); phase0_values_map.insert( "phase0_old_stack_ts_lt_n_plus_1".to_string(), vec![ diff --git a/singer/src/test.rs b/singer/src/test.rs index 5d38804d3..849189379 100644 --- a/singer/src/test.rs +++ b/singer/src/test.rs @@ -7,7 +7,7 @@ use gkr::utils::MultilinearExtensionFromVectors; use goldilocks::SmallField; use itertools::Itertools; use simple_frontend::structs::CellId; -use singer_utils::uint::UInt; +use singer_utils::structs::UInt; use std::collections::BTreeMap; use crate::instructions::InstCircuit;