Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions pkg/test/assembly_bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ func Test_AsmBench_Shf(t *testing.T) {
util.CheckWithFields(t, false, "asm/bench/shf", util.ASM_MAX_PADDING, field.BLS12_377, field.KOALABEAR_16)
}

func Test_AsmBench_Mod(t *testing.T) {
util.CheckWithFields(t, false, "asm/bench/mod", util.ASM_MAX_PADDING, field.BLS12_377, field.KOALABEAR_16)
}

func Test_AsmBench_Stp(t *testing.T) {
util.CheckWithFields(t, false, "asm/bench/stp", util.ASM_MAX_PADDING, field.BLS12_377, field.KOALABEAR_16)
}
Expand Down
150 changes: 150 additions & 0 deletions testdata/asm/bench/mod.accepts
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
{"mod": {"ARG_1":[0],"ARG_2":[0],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[0],"INST":[5],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[0],"INST":[6],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[0],"INST":[7],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[1000000000000000000000000000],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[1000000000000000000000000000],"INST":[6],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[100000000000000000000000],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[1000000],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[10000],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[100089000],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[10027337093055173198],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[100500000],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[100600000],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[1063722548954841694],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[1074787952766011976],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[10],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[10],"INST":[6],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[115792089237316195423570985008687907853269984665640564039457584007913129639935],"INST":[5],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[120],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[1223011452902],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[1251942489728280893],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[1461501637330902918203684832716283019655932542976],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[14889399780889809609408117],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[14982633751816419],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[15],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[16777216],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[16],"INST":[6],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[18446744073709551616],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[192],"INST":[6],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[1],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[200000000],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[228127113569201868],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[24],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[256],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[256],"INST":[7],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[281474976710656],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[2],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[2],"INST":[6],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[309485009821345068724781056],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[3281043104505],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[340282366920938463463374607431768211456],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[3],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[40320],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[410127816544206508],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[4294967296],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[455843288657269650],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[45],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[4722366482869645213696],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[47917192688627071376575381163212800],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[4],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[501387261813357055],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[50207077772073100170],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[5040],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[50],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[51069121924991624173],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[576529869730161187],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[63718288891407589],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[6],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[720],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[725984524129222612],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[7592553942],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[79228162514264337593543950336],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[796496997120250491389740],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[8191],"INST":[6],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[849304507514456856026894],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[86400361979650954],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[8],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[8],"INST":[6],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[9070771949],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[9104278865539931101],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[0],"ARG_2":[997668518092716560],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[99],"ARG_2":[32],"INST":[4],"RES":[3]}}
{"mod": {"ARG_1":[9],"ARG_2":[32],"INST":[4],"RES":[0]}}
{"mod": {"ARG_1":[775580],"ARG_2":[4],"INST":[5],"RES":[193895]}}
{"mod": {"ARG_1":[775724],"ARG_2":[4],"INST":[5],"RES":[193931]}}
{"mod": {"ARG_1":[775796],"ARG_2":[4],"INST":[5],"RES":[193949]}}
{"mod": {"ARG_1":[8143506],"ARG_2":[42],"INST":[5],"RES":[193893]}}
{"mod": {"ARG_1":[8388607],"ARG_2":[1],"INST":[5],"RES":[8388607]}}
{"mod": {"ARG_1":[8388607],"ARG_2":[50],"INST":[5],"RES":[167772]}}
{"mod": {"ARG_1":[8388607],"ARG_2":[60],"INST":[5],"RES":[139810]}}
{"mod": {"ARG_1":[9565736],"ARG_2":[256],"INST":[6],"RES":[40]}}
{"mod": {"ARG_1":[9600],"ARG_2":[160],"INST":[6],"RES":[0]}}
{"mod": {"ARG_1":[960],"ARG_2":[160],"INST":[6],"RES":[0]}}
{"mod": {"ARG_1":[960],"ARG_2":[192],"INST":[6],"RES":[0]}}
{"mod": {"ARG_1":[9647952],"ARG_2":[256],"INST":[6],"RES":[80]}}
{"mod": {"ARG_1":[9657512],"ARG_2":[256],"INST":[6],"RES":[168]}}
{"mod": {"ARG_1":[96],"ARG_2":[8],"INST":[6],"RES":[0]}}
{"mod": {"ARG_1":[9760],"ARG_2":[160],"INST":[6],"RES":[0]}}
{"mod": {"ARG_1":[9792],"ARG_2":[288],"INST":[6],"RES":[0]}}
{"mod": {"ARG_1":[9920],"ARG_2":[160],"INST":[6],"RES":[0]}}
{"mod": {"ARG_1":[318715],"ARG_2":[256],"INST":[7],"RES":[251]}}
{"mod": {"ARG_1":[318815],"ARG_2":[1],"INST":[7],"RES":[0]}}
{"mod": {"ARG_1":[318815],"ARG_2":[256],"INST":[7],"RES":[95]}}
{"mod": {"ARG_1":[318915],"ARG_2":[1],"INST":[7],"RES":[0]}}
{"mod": {"ARG_1":[318915],"ARG_2":[256],"INST":[7],"RES":[195]}}
{"mod": {"ARG_1":[319015],"ARG_2":[1],"INST":[7],"RES":[0]}}
{"mod": {"ARG_1":[319015],"ARG_2":[256],"INST":[7],"RES":[39]}}
{"mod": {"ARG_1":[319115],"ARG_2":[1],"INST":[7],"RES":[0]}}
{"mod": {"ARG_1":[319115],"ARG_2":[256],"INST":[7],"RES":[139]}}
{"mod": {"ARG_1":[319215],"ARG_2":[1],"INST":[7],"RES":[0]}}
{"mod": {"ARG_1":[319215],"ARG_2":[256],"INST":[7],"RES":[239]}}
{"mod": {"ARG_1":[319315],"ARG_2":[1],"INST":[7],"RES":[0]}}
{"mod": {"ARG_1":[319315],"ARG_2":[256],"INST":[7],"RES":[83]}}
{"mod": {"ARG_1":[319415],"ARG_2":[1],"INST":[7],"RES":[0]}}
{"mod": {"ARG_1":[319415],"ARG_2":[256],"INST":[7],"RES":[183]}}
{"mod": {"ARG_1":[319515],"ARG_2":[1],"INST":[7],"RES":[0]}}
{"mod": {"ARG_1":[319515],"ARG_2":[256],"INST":[7],"RES":[27]}}
{"mod": {"ARG_1":[319615],"ARG_2":[1],"INST":[7],"RES":[0]}}
{"mod": {"ARG_1":[319615],"ARG_2":[256],"INST":[7],"RES":[127]}}
{"mod": {"ARG_1":[31964],"ARG_2":[256],"INST":[7],"RES":[220]}}
{"mod": {"ARG_1":[31965],"ARG_2":[256],"INST":[7],"RES":[221]}}
{"mod": {"ARG_1":[31966],"ARG_2":[256],"INST":[7],"RES":[222]}}
{"mod": {"ARG_1":[319715],"ARG_2":[1],"INST":[7],"RES":[0]}}
{"mod": {"ARG_1":[319715],"ARG_2":[256],"INST":[7],"RES":[227]}}
{"mod": {"ARG_1":[31972],"ARG_2":[256],"INST":[7],"RES":[228]}}
{"mod": {"ARG_1":[319767],"ARG_2":[256],"INST":[7],"RES":[23]}}
{"mod": {"ARG_1":[319769],"ARG_2":[256],"INST":[7],"RES":[25]}}
{"mod": {"ARG_1":[319771],"ARG_2":[256],"INST":[7],"RES":[27]}}
{"mod": {"ARG_1":[319780],"ARG_2":[256],"INST":[7],"RES":[36]}}
{"mod": {"ARG_1":[319815],"ARG_2":[1],"INST":[7],"RES":[0]}}
{"mod": {"ARG_1":[319815],"ARG_2":[256],"INST":[7],"RES":[71]}}
{"mod": {"ARG_1":[319816],"ARG_2":[256],"INST":[7],"RES":[72]}}
{"mod": {"ARG_1":[319850],"ARG_2":[50],"INST":[7],"RES":[0]}}
{"mod": {"ARG_1":[319859],"ARG_2":[256],"INST":[7],"RES":[115]}}
{"mod": {"ARG_1":[319915],"ARG_2":[1],"INST":[7],"RES":[0]}}
{"mod": {"ARG_1":[319915],"ARG_2":[256],"INST":[7],"RES":[171]}}
{"mod": {"ARG_1":[3231],"ARG_2":[256],"INST":[7],"RES":[159]}}
{"mod": {"ARG_1":[3232],"ARG_2":[256],"INST":[7],"RES":[160]}}
{"mod": {"ARG_1":[3867],"ARG_2":[256],"INST":[7],"RES":[27]}}
{"mod": {"ARG_1":[3876],"ARG_2":[256],"INST":[7],"RES":[36]}}
{"mod": {"ARG_1":[38778],"ARG_2":[256],"INST":[7],"RES":[122]}}
{"mod": {"ARG_1":[38779],"ARG_2":[256],"INST":[7],"RES":[123]}}
{"mod": {"ARG_1":[3877],"ARG_2":[256],"INST":[7],"RES":[37]}}
{"mod": {"ARG_1":[38781],"ARG_2":[256],"INST":[7],"RES":[125]}}
{"mod": {"ARG_1":[3878],"ARG_2":[256],"INST":[7],"RES":[38]}}
{"mod": {"ARG_1":[3879],"ARG_2":[256],"INST":[7],"RES":[39]}}
{"mod": {"ARG_1":[3880],"ARG_2":[256],"INST":[7],"RES":[40]}}
{"mod": {"ARG_1":[3],"ARG_2":[1],"INST":[7],"RES":[0]}}
{"mod": {"ARG_1":[3],"ARG_2":[256],"INST":[7],"RES":[3]}}
{"mod": {"ARG_1":[3],"ARG_2":[2],"INST":[7],"RES":[1]}}
{"mod": {"ARG_1":[3],"ARG_2":[3],"INST":[7],"RES":[0]}}
{"mod": {"ARG_1":[3],"ARG_2":[4],"INST":[7],"RES":[3]}}
{"mod": {"ARG_1":[4],"ARG_2":[1],"INST":[7],"RES":[0]}}
{"mod": {"ARG_1":[4],"ARG_2":[2],"INST":[7],"RES":[0]}}
{"mod": {"ARG_1":[4],"ARG_2":[3],"INST":[7],"RES":[1]}}
{"mod": {"ARG_1":[4],"ARG_2":[4],"INST":[7],"RES":[0]}}
{"mod": {"ARG_1":[581],"ARG_2":[256],"INST":[7],"RES":[69]}}
{"mod": {"ARG_1":[582],"ARG_2":[256],"INST":[7],"RES":[70]}}
{"mod": {"ARG_1":[6396],"ARG_2":[256],"INST":[7],"RES":[252]}}
{"mod": {"ARG_1":[6397],"ARG_2":[256],"INST":[7],"RES":[253]}}
Binary file added testdata/asm/bench/mod.all.bz2
Binary file not shown.
104 changes: 104 additions & 0 deletions testdata/asm/bench/mod.zkasm
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
include "evm.zkasm"
include "../util/bit_xoan.zkasm"

fn mod(INST=0x4 u8, ARG_1 u256, ARG_2=1 u256) -> (RES u256) {
var tmp u256
;;
if INST==EVM_INST_DIV goto div
if INST==EVM_INST_MOD goto mod
if INST==EVM_INST_SDIV goto sdiv
if INST==EVM_INST_SMOD goto smod
fail
div:
RES, tmp = divide(ARG_1, ARG_2)
return
mod:
tmp, RES = divide(ARG_1, ARG_2)
return
sdiv:
RES, tmp = signed_divide(ARG_1, ARG_2)
return
smod:
RES, tmp = signed_divide(ARG_1, ARG_2)
return
Copy link

Choose a reason for hiding this comment

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

Bug: SMOD operation returns quotient instead of remainder

The smod case incorrectly returns the quotient instead of the remainder. The signed_divide function returns (quot, rem), so RES, tmp = signed_divide(...) assigns the quotient to RES. For SMOD (signed modulo), it should be tmp, RES = signed_divide(...) to return the remainder, matching the pattern used for unsigned MOD at line 16.

Fix in Cursor Fix in Web

}

fn signed_divide(num u256, den=1 u256) -> (quot u256, rem u256) {
var num_s, den_s u1
var abs_num, abs_den u256
var abs_quot, abs_rem u256
;;
abs_num, num_s = abs(num)
abs_den, den_s = abs(num)
Copy link

Choose a reason for hiding this comment

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

Bug: Wrong variable passed to abs function

The signed_divide function has a copy-paste error where abs_den, den_s = abs(num) computes the absolute value of the numerator instead of the denominator. It should be abs(den) to get the absolute value of the den parameter for the division operation.

Fix in Cursor Fix in Web

;; unsigned division
abs_quot,abs_rem = divide(abs_num,abs_den)
;; decide if output positive or negative
if num_s != den_s goto negative
;; positive result
quot = abs_quot
rem = abs_rem
return
;;
negative:
;; negative result
quot = negate(abs_quot)
rem = negate(abs_rem)
return
Copy link

Choose a reason for hiding this comment

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

Bug: Remainder sign incorrectly follows quotient sign logic

The signed_divide function applies the same sign logic to both quotient and remainder, but EVM semantics require different rules. The quotient sign depends on num_s XOR den_s (correctly implemented), but the remainder sign must depend only on num_s (the dividend's sign). Currently, both quot and rem are negated when num_s != den_s, which produces incorrect remainder values when the dividend and divisor have opposite signs.

Fix in Cursor Fix in Web

}

;; Compute the absolute value of a u256 word assuming twos complement
;; notation.
fn abs(val u256) -> (abs_val u256, signed u1) {
var tmp u255
;;
signed, tmp = val
;; check if val < 0
if signed != 0 goto negative
;; positive case
abs_val = val
return
;; negative case
negative:
abs_val = negate(val)
return
}

;; Determine the two's complement negation of a given value. This is
;; done following the standard recipe of inverting all bits and then
;; adding one.
fn negate(val u256) -> (neg_val u256) {
var inv_val u256
var c u1
;; invert then add one
inv_val = bit_xoan_u256(BIT_NOT,val,0)
;;
c,neg_val = inv_val + 1
return
}

;; TEMPORARY HACK. This cannot be used as it is seriously expensive.
;; For now, it is being used as temporary scafolding in order to write
;; the remainder of this module.
fn divide(num u256, den=1 u256) -> (quot u256, rem u256) {
var b, c u1
var tmp1, tmp2 u256
;; handle division by 0
if den == 0 goto exit_0
;; check num < den
b,tmp1 = num - den
if b != 0 goto base_case
;;
tmp2, rem = divide(tmp1, den)
;; assert c == 0
c,quot = tmp2 + 1
;;
return
base_case:
quot = 0
rem = num
return
exit_0:
quot = 0
rem = 0
return
}
Loading