diff --git a/Makefile b/Makefile index 9954a52f..467040f7 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ CAIRO_VM_CLI:=cairo-vm/target/release/cairo-vm-cli $(CAIRO_VM_CLI): - git clone --depth 1 -b v0.8.5 https://github.com/lambdaclass/cairo-vm + git clone --depth 1 -b v0.8.7 https://github.com/lambdaclass/cairo-vm cd cairo-vm; cargo b --release --bin cairo-vm-cli # Create proof mode programs. diff --git a/cairo_programs/div_mod_n.cairo b/cairo_programs/div_mod_n.cairo new file mode 100644 index 00000000..4dbe3c82 --- /dev/null +++ b/cairo_programs/div_mod_n.cairo @@ -0,0 +1,129 @@ +%builtins range_check + +from starkware.cairo.common.cairo_secp.bigint import BigInt3, nondet_bigint3, BASE, bigint_mul +from starkware.cairo.common.cairo_secp.constants import BETA, N0, N1, N2 + +// Source: https://github.com/myBraavos/efficient-secp256r1/blob/73cca4d53730cb8b2dcf34e36c7b8f34b96b3230/src/secp256r1/signature.cairo + +// Computes a * b^(-1) modulo the size of the elliptic curve (N). +// +// Prover assumptions: +// * All the limbs of a are in the range (-2 ** 210.99, 2 ** 210.99). +// * All the limbs of b are in the range (-2 ** 124.99, 2 ** 124.99). +// * b is in the range [0, 2 ** 256). +// +// Soundness assumptions: +// * The limbs of a are in the range (-2 ** 249, 2 ** 249). +// * The limbs of b are in the range (-2 ** 159.83, 2 ** 159.83). +func div_mod_n{range_check_ptr}(a: BigInt3, b: BigInt3) -> (res: BigInt3) { + %{ + from starkware.cairo.common.cairo_secp.secp_utils import N, pack + from starkware.python.math_utils import div_mod, safe_div + + a = pack(ids.a, PRIME) + b = pack(ids.b, PRIME) + value = res = div_mod(a, b, N) + %} + let (res) = nondet_bigint3(); + + %{ value = k_plus_one = safe_div(res * b - a, N) + 1 %} + let (k_plus_one) = nondet_bigint3(); + let k = BigInt3(d0=k_plus_one.d0 - 1, d1=k_plus_one.d1, d2=k_plus_one.d2); + + let (res_b) = bigint_mul(res, b); + let n = BigInt3(N0, N1, N2); + let (k_n) = bigint_mul(k, n); + + // We should now have res_b = k_n + a. Since the numbers are in unreduced form, + // we should handle the carry. + + tempvar carry1 = (res_b.d0 - k_n.d0 - a.d0) / BASE; + assert [range_check_ptr + 0] = carry1 + 2 ** 127; + + tempvar carry2 = (res_b.d1 - k_n.d1 - a.d1 + carry1) / BASE; + assert [range_check_ptr + 1] = carry2 + 2 ** 127; + + tempvar carry3 = (res_b.d2 - k_n.d2 - a.d2 + carry2) / BASE; + assert [range_check_ptr + 2] = carry3 + 2 ** 127; + + tempvar carry4 = (res_b.d3 - k_n.d3 + carry3) / BASE; + assert [range_check_ptr + 3] = carry4 + 2 ** 127; + + assert res_b.d4 - k_n.d4 + carry4 = 0; + + let range_check_ptr = range_check_ptr + 4; + + return (res=res); +} + +func div_mod_n_alt{range_check_ptr}(a: BigInt3, b: BigInt3) -> (res: BigInt3) { + // just used to import N + %{ + from starkware.cairo.common.cairo_secp.secp_utils import N, pack + from starkware.python.math_utils import div_mod, safe_div + + a = pack(ids.a, PRIME) + b = pack(ids.b, PRIME) + value = res = div_mod(a, b, N) + %} + + %{ + from starkware.cairo.common.cairo_secp.secp_utils import pack + from starkware.python.math_utils import div_mod, safe_div + + a = pack(ids.a, PRIME) + b = pack(ids.b, PRIME) + value = res = div_mod(a, b, N) + %} + let (res) = nondet_bigint3(); + + %{ value = k_plus_one = safe_div(res * b - a, N) + 1 %} + let (k_plus_one) = nondet_bigint3(); + let k = BigInt3(d0=k_plus_one.d0 - 1, d1=k_plus_one.d1, d2=k_plus_one.d2); + + let (res_b) = bigint_mul(res, b); + let n = BigInt3(N0, N1, N2); + let (k_n) = bigint_mul(k, n); + + tempvar carry1 = (res_b.d0 - k_n.d0 - a.d0) / BASE; + assert [range_check_ptr + 0] = carry1 + 2 ** 127; + + tempvar carry2 = (res_b.d1 - k_n.d1 - a.d1 + carry1) / BASE; + assert [range_check_ptr + 1] = carry2 + 2 ** 127; + + tempvar carry3 = (res_b.d2 - k_n.d2 - a.d2 + carry2) / BASE; + assert [range_check_ptr + 2] = carry3 + 2 ** 127; + + tempvar carry4 = (res_b.d3 - k_n.d3 + carry3) / BASE; + assert [range_check_ptr + 3] = carry4 + 2 ** 127; + + assert res_b.d4 - k_n.d4 + carry4 = 0; + + let range_check_ptr = range_check_ptr + 4; + + return (res=res); +} + +func test_div_mod_n{range_check_ptr: felt}() { + let a: BigInt3 = BigInt3(100, 99, 98); + let b: BigInt3 = BigInt3(10, 9, 8); + + let (res) = div_mod_n(a, b); + + assert res = BigInt3( + 3413472211745629263979533, 17305268010345238170172332, 11991751872105858217578135 + ); + + // test alternative hint + let (res_alt) = div_mod_n_alt(a, b); + + assert res_alt = res; + + return (); +} + +func main{range_check_ptr: felt}() { + test_div_mod_n(); + + return (); +} diff --git a/cairo_programs/reduce.cairo b/cairo_programs/reduce.cairo new file mode 100644 index 00000000..486e8b22 --- /dev/null +++ b/cairo_programs/reduce.cairo @@ -0,0 +1,127 @@ +%builtins range_check + +from starkware.cairo.common.cairo_secp.bigint import BigInt3, UnreducedBigInt3, nondet_bigint3 + +const BASE = 2 ** 86; +const SECP_REM = 19; + +func verify_zero{range_check_ptr}(val: UnreducedBigInt3) { + let q = [ap]; + %{ + from starkware.cairo.common.cairo_secp.secp_utils import pack + SECP_P = 2**255-19 + to_assert = pack(ids.val, PRIME) + q, r = divmod(pack(ids.val, PRIME), SECP_P) + assert r == 0, f"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}." + ids.q = q % PRIME + %} + let q_biased = [ap + 1]; + q_biased = q + 2 ** 127, ap++; + [range_check_ptr] = q_biased, ap++; + // This implies that q is in the range [-2**127, 2**127). + + tempvar r1 = (val.d0 + q * SECP_REM) / BASE; + assert [range_check_ptr + 1] = r1 + 2 ** 127; + // This implies that r1 is in the range [-2**127, 2**127). + // Therefore, r1 * BASE is in the range [-2**213, 2**213). + // By the soundness assumption, val.d0 is in the range (-2**250, 2**250). + // This implies that r1 * BASE = val.d0 + q * SECP_REM (as integers). + + tempvar r2 = (val.d1 + r1) / BASE; + assert [range_check_ptr + 2] = r2 + 2 ** 127; + // Similarly, this implies that r2 * BASE = val.d1 + r1 (as integers). + // Therefore, r2 * BASE**2 = val.d1 * BASE + r1 * BASE. + + assert val.d2 = q * (BASE / 8) - r2; + // Similarly, this implies that q * BASE / 4 = val.d2 + r2 (as integers). + // Therefore, + // q * BASE**3 / 4 = val.d2 * BASE**2 + r2 * BASE ** 2 = + // val.d2 * BASE**2 + val.d1 * BASE + r1 * BASE = + // val.d2 * BASE**2 + val.d1 * BASE + val.d0 + q * SECP_REM = + // val + q * SECP_REM. + // Hence, val = q * (BASE**3 / 4 - SECP_REM) = q * (2**256 - SECP_REM) = q * secp256k1_prime. + + let range_check_ptr = range_check_ptr + 3; + return (); +} + +// Receives an unreduced number, and returns a number that is equal to the original number mod +// Ed25519 prime and in reduced form (meaning every limb is in the range [0, BASE)). +// +// Completeness assumption: x's limbs are in the range (-2**210.99, 2**210.99). +// Soundness assumption: x's limbs are in the range (-2**249.99, 2**249.99). +func reduce_ed25519{range_check_ptr}(x: UnreducedBigInt3) -> (reduced_x: BigInt3) { + %{ + from starkware.cairo.common.cairo_secp.secp_utils import pack + SECP_P=2**255-19 + + value = pack(ids.x, PRIME) % SECP_P + %} + let (reduced_x: BigInt3) = nondet_bigint3(); + + verify_zero( + UnreducedBigInt3(d0=x.d0 - reduced_x.d0, d1=x.d1 - reduced_x.d1, d2=x.d2 - reduced_x.d2) + ); + return (reduced_x=reduced_x); +} + +func test_reduce_ed25519{range_check_ptr}() { + let x = UnreducedBigInt3(0, 0, 0); + let (res) = reduce_ed25519(x); + assert res = BigInt3(0, 0, 0); + + let x = UnreducedBigInt3( + 1113660525233188137217661511617697775365785011829423399545361443, + 1243997169368861650657124871657865626433458458266748922940703512, + 1484456708474143440067316914074363277495967516029110959982060577, + ); + let (res) = reduce_ed25519(x); + assert res = BigInt3( + 42193159084937489098474581, 19864776835133205750023223, 916662843592479469328893 + ); + + return (); +} + +func reduce_v2{range_check_ptr}(x: UnreducedBigInt3) -> (reduced_x: BigInt3) { + let orig_x = x; + %{ from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P as SECP_P %} + %{ + from starkware.cairo.common.cairo_secp.secp_utils import pack + value = pack(ids.x, PRIME) % SECP_P + %} + let (reduced_x: BigInt3) = nondet_bigint3(); + + verify_zero( + UnreducedBigInt3( + d0=orig_x.d0 - reduced_x.d0, + d1=orig_x.d1 - reduced_x.d1, + d2=orig_x.d2 - reduced_x.d2 + ) + ); + return (reduced_x=reduced_x); +} + +func main{range_check_ptr}() { + test_reduce_ed25519(); + + // reduce_v2 tests + let x = UnreducedBigInt3(0, 0, 0); + let (reduce_v2_a) = reduce_v2(x); + assert reduce_v2_a = BigInt3( + 0, 0, 0 + ); + + let y = UnreducedBigInt3(12354, 745634534, 81298789312879123); + let (reduce_v2_b) = reduce_v2(y); + assert reduce_v2_b = BigInt3( + 12354, 745634534, 81298789312879123 + ); + + let z = UnreducedBigInt3(12354812987893128791212331231233, 7453123123123123312634534, 8129224990312325879); + let (reduce_v2_c) = reduce_v2(z); + assert reduce_v2_c = BigInt3( + 16653320122975184709085185, 7453123123123123312794216, 8129224990312325879 + ); + return (); +} diff --git a/cairo_programs/secp.cairo b/cairo_programs/secp.cairo new file mode 100644 index 00000000..747d8c74 --- /dev/null +++ b/cairo_programs/secp.cairo @@ -0,0 +1,60 @@ +%builtins range_check +from starkware.cairo.common.cairo_secp.bigint import nondet_bigint3, BigInt3, bigint_to_uint256 + +from starkware.cairo.common.cairo_secp.field import verify_zero, UnreducedBigInt3, reduce, is_zero + +func main{range_check_ptr: felt}() { + // Bigint to uint + let big_int = BigInt3(d0=9, d1=9, d2=9); + + let (uint256) = bigint_to_uint256(big_int); + + assert uint256.low = 696341272098026404630757385; + assert uint256.high = 158329674399744; + + // verify_zero + let zero: UnreducedBigInt3 = UnreducedBigInt3(0, 0, 0); + verify_zero(zero); + + let x: UnreducedBigInt3 = UnreducedBigInt3(132181232131231239112312312313213083892150, 10, 10); + + // reduce + let (y: BigInt3) = reduce(x); + assert y = BigInt3(48537904510172037887998390, 1708402383786350, 10); + + let m: BigInt3 = nondet_bigint3(); + // Since the scope variable 'value' remains the same, m == y + assert m = y; + + let n: BigInt3 = reduce(UnreducedBigInt3(1321812083892150, 11230, 103321)); + assert n = BigInt3(1321812083892150, 11230, 103321); + + let p: BigInt3 = reduce(UnreducedBigInt3(0, 0, 0)); + assert p = BigInt3(0, 0, 0); + + let q: BigInt3 = reduce(UnreducedBigInt3(-10, 0, 0)); + assert q = BigInt3( + 77371252455336262886226981, 77371252455336267181195263, 19342813113834066795298815 + ); + + let r: BigInt3 = reduce(UnreducedBigInt3(-10, -56, -111)); + assert r = BigInt3( + 77371252455336262886226981, 77371252455336267181195207, 19342813113834066795298704 + ); + + // is_zero + let (u) = is_zero(BigInt3(0, 0, 0)); + assert u = 1; + let (v) = is_zero( + BigInt3(232113757366008801543585, 232113757366008801543585, 232113757366008801543585) + ); + assert v = 0; + + let (w) = is_zero(BigInt3(-10, -10, -10)); + assert w = 0; + + let (z) = is_zero(BigInt3(1833312543, 67523423, 8790312)); + assert z = 0; + + return (); +} diff --git a/cairo_programs/signature.cairo b/cairo_programs/signature.cairo new file mode 100644 index 00000000..b6f4a0d4 --- /dev/null +++ b/cairo_programs/signature.cairo @@ -0,0 +1,24 @@ +%builtins range_check + +from starkware.cairo.common.cairo_secp.signature import div_mod_n, get_point_from_x +from starkware.cairo.common.cairo_secp.bigint import BigInt3 + +func main{range_check_ptr: felt}() { + let a: BigInt3 = BigInt3(100, 99, 98); + let b: BigInt3 = BigInt3(10, 9, 8); + let (res) = div_mod_n(a, b); + assert res.d0 = 3413472211745629263979533; + assert res.d1 = 17305268010345238170172332; + assert res.d2 = 11991751872105858217578135; + + let x: BigInt3 = BigInt3(100, 99, 98); + let v: felt = 10; + let (point) = get_point_from_x(x, v); + assert point.x.d0 = 100; + assert point.x.d1 = 99; + assert point.x.d2 = 98; + assert point.y.d0 = 50471654703173585387369794; + assert point.y.d1 = 68898944762041070370364387; + assert point.y.d2 = 16932612780945290933872774; + return (); +} diff --git a/pkg/builtins/ec_op.go b/pkg/builtins/ec_op.go index 0e973a0a..9053c25c 100644 --- a/pkg/builtins/ec_op.go +++ b/pkg/builtins/ec_op.go @@ -5,7 +5,6 @@ import ( "math/big" "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" - "github.com/lambdaclass/cairo-vm.go/pkg/math_utils" "github.com/lambdaclass/cairo-vm.go/pkg/utils" "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" "github.com/pkg/errors" @@ -263,7 +262,7 @@ func LineSlope(point_a PartialSumB, point_b DoublePointB, prime big.Int) (big.In n := new(big.Int).Sub(&point_a.Y, &point_b.Y) m := new(big.Int).Sub(&point_a.X, &point_b.X) - z, err := math_utils.DivMod(n, m, &prime) + z, err := utils.DivMod(n, m, &prime) if err != nil { return big.Int{}, err } @@ -299,7 +298,7 @@ func EcDoubleSlope(point DoublePointB, alpha big.Int, prime big.Int) (big.Int, e n.Add(n, &alpha) m := new(big.Int).Mul(&point.Y, big.NewInt(2)) - z, err := math_utils.DivMod(n, m, &prime) + z, err := utils.DivMod(n, m, &prime) if err != nil { return big.Int{}, err diff --git a/pkg/hints/hint_codes/secp_hint_codes.go b/pkg/hints/hint_codes/secp_hint_codes.go new file mode 100644 index 00000000..77bc3237 --- /dev/null +++ b/pkg/hints/hint_codes/secp_hint_codes.go @@ -0,0 +1,57 @@ +package hint_codes + +const IMPORT_SECP256R1_ALPHA = "from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_ALPHA as ALPHA" + +const IMPORT_SECP256R1_N = "from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_N as N" + +const IMPORT_SECP256R1_P = "from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P as SECP_P" + +const VERIFY_ZERO_EXTERNAL_SECP = "from starkware.cairo.common.cairo_secp.secp_utils import pack\n\nq, r = divmod(pack(ids.val, PRIME), SECP_P)\nassert r == 0, f\"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}.\"\nids.q = q % PRIME" + +const REDUCE_V1 = `from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack + +value = pack(ids.x, PRIME) % SECP_P` + +const REDUCE_V2 = `from starkware.cairo.common.cairo_secp.secp_utils import pack +value = pack(ids.x, PRIME) % SECP_P` + +const REDUCE_ED25519 = `from starkware.cairo.common.cairo_secp.secp_utils import pack +SECP_P=2**255-19 + +value = pack(ids.x, PRIME) % SECP_P` + +const VERIFY_ZERO_V1 = `from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack + +q, r = divmod(pack(ids.val, PRIME), SECP_P) +assert r == 0, f"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}." +ids.q = q % PRIME` + +const VERIFY_ZERO_V2 = `from starkware.cairo.common.cairo_secp.secp_utils import SECP_P +q, r = divmod(pack(ids.val, PRIME), SECP_P) +assert r == 0, f"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}." +ids.q = q % PRIME` + +const VERIFY_ZERO_V3 = `from starkware.cairo.common.cairo_secp.secp_utils import pack +SECP_P = 2**255-19 +to_assert = pack(ids.val, PRIME) +q, r = divmod(pack(ids.val, PRIME), SECP_P) +assert r == 0, f"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}." +ids.q = q % PRIME` + +const BIGINT_TO_UINT256 = "ids.low = (ids.x.d0 + ids.x.d1 * ids.BASE) & ((1 << 128) - 1)" + +const IS_ZERO_NONDET = "memory[ap] = to_felt_or_relocatable(x == 0)" + +const IS_ZERO_INT = "memory[ap] = int(x == 0)" + +const IS_ZERO_PACK_V1 = `from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack + +x = pack(ids.x, PRIME) % SECP_P` + +const IS_ZERO_PACK_V2 = `from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack +x = pack(ids.x, PRIME) % SECP_P` + +const IS_ZERO_ASSIGN_SCOPE_VARS = `from starkware.cairo.common.cairo_secp.secp_utils import SECP_P +from starkware.python.math_utils import div_mod + +value = x_inv = div_mod(1, x, SECP_P)` diff --git a/pkg/hints/hint_codes/secp_p_hint.go b/pkg/hints/hint_codes/secp_p_hint.go deleted file mode 100644 index 2d6dac14..00000000 --- a/pkg/hints/hint_codes/secp_p_hint.go +++ /dev/null @@ -1,6 +0,0 @@ -package hint_codes - -const IMPORT_SECP256R1_ALPHA = "from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_ALPHA as ALPHA" -const IMPORT_SECP256R1_N = "from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_N as N" -const IMPORT_SECP256R1_P = "from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P as SECP_P" -const VERIFY_ZERO_EXTERNAL_SECP = "from starkware.cairo.common.cairo_secp.secp_utils import pack\n\nq, r = divmod(pack(ids.val, PRIME), SECP_P)\nassert r == 0, f\"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}.\"\nids.q = q % PRIME" diff --git a/pkg/hints/hint_codes/signature_hint_codes.go b/pkg/hints/hint_codes/signature_hint_codes.go new file mode 100644 index 00000000..b1e4e189 --- /dev/null +++ b/pkg/hints/hint_codes/signature_hint_codes.go @@ -0,0 +1,33 @@ +package hint_codes + +const DIV_MOD_N_PACKED_DIVMOD_V1 = `from starkware.cairo.common.cairo_secp.secp_utils import N, pack +from starkware.python.math_utils import div_mod, safe_div + +a = pack(ids.a, PRIME) +b = pack(ids.b, PRIME) +value = res = div_mod(a, b, N)` + +const DIV_MOD_N_PACKED_DIVMOD_EXTERNAL_N = `from starkware.cairo.common.cairo_secp.secp_utils import pack +from starkware.python.math_utils import div_mod, safe_div + +a = pack(ids.a, PRIME) +b = pack(ids.b, PRIME) +value = res = div_mod(a, b, N)` + +const DIV_MOD_N_SAFE_DIV = "value = k = safe_div(res * b - a, N)" + +const DIV_MOD_N_SAFE_DIV_PLUS_ONE = "value = k_plus_one = safe_div(res * b - a, N) + 1" + +const XS_SAFE_DIV = "value = k = safe_div(res * s - x, N)" + +const GET_POINT_FROM_X = `from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack + +x_cube_int = pack(ids.x_cube, PRIME) % SECP_P +y_square_int = (x_cube_int + ids.BETA) % SECP_P +y = pow(y_square_int, (SECP_P + 1) // 4, SECP_P) + +# We need to decide whether to take y or SECP_P - y. +if ids.v % 2 == y % 2: + value = y +else: + value = (-y) % SECP_P` diff --git a/pkg/hints/hint_processor.go b/pkg/hints/hint_processor.go index ccac7bd2..93d6ff17 100644 --- a/pkg/hints/hint_processor.go +++ b/pkg/hints/hint_processor.go @@ -4,6 +4,7 @@ import ( "strings" . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_codes" + "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" "github.com/lambdaclass/cairo-vm.go/pkg/parser" @@ -188,6 +189,18 @@ func (p *CairoVmHintProcessor) ExecuteHint(vm *vm.VirtualMachine, hintData *any, return splitInt(data.Ids, vm) case SPLIT_INT_ASSERT_RANGE: return splitIntAssertRange(data.Ids, vm) + case DIV_MOD_N_PACKED_DIVMOD_V1: + return divModNPackedDivMod(data.Ids, vm, execScopes) + case DIV_MOD_N_PACKED_DIVMOD_EXTERNAL_N: + return divModNPackedDivModExternalN(data.Ids, vm, execScopes) + case XS_SAFE_DIV: + return divModNSafeDiv(data.Ids, execScopes, "x", "s", false) + case DIV_MOD_N_SAFE_DIV: + return divModNSafeDiv(data.Ids, execScopes, "a", "b", false) + case DIV_MOD_N_SAFE_DIV_PLUS_ONE: + return divModNSafeDiv(data.Ids, execScopes, "a", "b", true) + case GET_POINT_FROM_X: + return getPointFromX(data.Ids, vm, execScopes, constants) case VERIFY_ZERO_EXTERNAL_SECP: return verifyZeroWithExternalConst(*vm, *execScopes, data.Ids) case FAST_EC_ADD_ASSIGN_NEW_X: @@ -198,6 +211,24 @@ func (p *CairoVmHintProcessor) ExecuteHint(vm *vm.VirtualMachine, hintData *any, return fastEcAddAssignNewX(data.Ids, vm, execScopes, "pt0", "pt1", SECP_P()) case FAST_EC_ADD_ASSIGN_NEW_Y: return fastEcAddAssignNewY(execScopes) + case REDUCE_V1: + return reduceV1(data.Ids, vm, execScopes) + case REDUCE_V2: + return reduceV2(data.Ids, vm, execScopes) + case REDUCE_ED25519: + return reduceED25519(data.Ids, vm, execScopes) + case VERIFY_ZERO_V1, VERIFY_ZERO_V2: + return verifyZero(data.Ids, vm, execScopes, hint_utils.SECP_P()) + case VERIFY_ZERO_V3: + return verifyZero(data.Ids, vm, execScopes, hint_utils.SECP_P_V2()) + case BIGINT_TO_UINT256: + return bigintToUint256(data.Ids, vm, constants) + case IS_ZERO_NONDET, IS_ZERO_INT: + return isZeroNondet(data.Ids, vm) + case IS_ZERO_PACK_V1, IS_ZERO_PACK_V2: + return isZeroPack(data.Ids, vm, execScopes) + case IS_ZERO_ASSIGN_SCOPE_VARS: + return isZeroAssignScopeVars(execScopes) default: return errors.Errorf("Unknown Hint: %s", data.Code) } diff --git a/pkg/hints/hint_utils/bigint_utils.go b/pkg/hints/hint_utils/bigint_utils.go index 9a900443..2fac8054 100644 --- a/pkg/hints/hint_utils/bigint_utils.go +++ b/pkg/hints/hint_utils/bigint_utils.go @@ -96,15 +96,14 @@ func BigInt3FromBaseAddr(addr Relocatable, name string, vm *VirtualMachine) (Big } func BigInt3FromVarName(name string, ids IdsManager, vm *VirtualMachine) (BigInt3, error) { - bigIntAddr, err := ids.GetAddr(name, vm) - if err != nil { - return BigInt3{}, err - } + limbs, err := limbsFromVarName(3, name, ids, vm) + return BigInt3{Limbs: limbs}, err +} - bigInt, err := BigInt3FromBaseAddr(bigIntAddr, name, vm) - if err != nil { - return BigInt3{}, err - } +// Uint384 + +type Uint384 = BigInt3 - return bigInt, err +func Uint384FromVarName(name string, ids IdsManager, vm *VirtualMachine) (Uint384, error) { + return BigInt3FromVarName(name, ids, vm) } diff --git a/pkg/hints/hint_utils/secp_utils.go b/pkg/hints/hint_utils/secp_utils.go index a125823a..bec3b650 100644 --- a/pkg/hints/hint_utils/secp_utils.go +++ b/pkg/hints/hint_utils/secp_utils.go @@ -46,7 +46,7 @@ func Bigint3Split(integer big.Int) ([]big.Int, error) { for i := 0; i < 3; i++ { canonicalRepr[i] = *new(big.Int).And(&num, BASE_MINUS_ONE()) - num.Rsh(&num, 86) + num = *new(big.Int).Rsh(&num, 86) } if num.Cmp(big.NewInt(0)) != 0 { return nil, errors.New("HintError SecpSplitOutOfRange") diff --git a/pkg/hints/hint_utils/testing_utils.go b/pkg/hints/hint_utils/testing_utils.go index 46403f07..a52ddb0d 100644 --- a/pkg/hints/hint_utils/testing_utils.go +++ b/pkg/hints/hint_utils/testing_utils.go @@ -1,8 +1,12 @@ package hint_utils import ( + "reflect" + "testing" + "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" "github.com/lambdaclass/cairo-vm.go/pkg/parser" + "github.com/lambdaclass/cairo-vm.go/pkg/types" . "github.com/lambdaclass/cairo-vm.go/pkg/vm" "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" ) @@ -56,3 +60,13 @@ func SetupConstantsForTest(new_constants map[string]lambdaworks.Felt, ids *IdsMa } return constants } + +func CheckScopeVar[T any](name string, expectedVal T, scopes *types.ExecutionScopes, t *testing.T) { + val, err := types.FetchScopeVar[T](name, scopes) + if err != nil { + t.Error(err.Error()) + } + if !reflect.DeepEqual(val, expectedVal) { + t.Errorf("Wrong scope var %s.\n Expected: %v, got: %v", name, expectedVal, val) + } +} diff --git a/pkg/hints/math_hints.go b/pkg/hints/math_hints.go index 03b239c3..a577131d 100644 --- a/pkg/hints/math_hints.go +++ b/pkg/hints/math_hints.go @@ -7,8 +7,8 @@ import ( . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" - . "github.com/lambdaclass/cairo-vm.go/pkg/math_utils" . "github.com/lambdaclass/cairo-vm.go/pkg/types" + . "github.com/lambdaclass/cairo-vm.go/pkg/utils" . "github.com/lambdaclass/cairo-vm.go/pkg/vm" . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" "github.com/pkg/errors" diff --git a/pkg/hints/secp_hints.go b/pkg/hints/secp_hints.go new file mode 100644 index 00000000..2ed14744 --- /dev/null +++ b/pkg/hints/secp_hints.go @@ -0,0 +1,125 @@ +package hints + +import ( + "math/big" + + . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" + "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" + . "github.com/lambdaclass/cairo-vm.go/pkg/types" + "github.com/lambdaclass/cairo-vm.go/pkg/utils" + . "github.com/lambdaclass/cairo-vm.go/pkg/vm" + "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" + "github.com/pkg/errors" +) + +func reduceV1(ids IdsManager, vm *VirtualMachine, scopes *ExecutionScopes) error { + secpP := SECP_P() + scopes.AssignOrUpdateVariable("SECP_P", secpP) + value, err := Uint384FromVarName("x", ids, vm) + if err != nil { + return err + } + packedValue := value.Pack86() + scopes.AssignOrUpdateVariable("value", *new(big.Int).Mod(&packedValue, &secpP)) + return nil +} + +func reduceV2(ids IdsManager, vm *VirtualMachine, scopes *ExecutionScopes) error { + secpP, err := FetchScopeVar[big.Int]("SECP_P", scopes) + if err != nil { + return err + } + value, err := Uint384FromVarName("x", ids, vm) + if err != nil { + return err + } + packedValue := value.Pack86() + scopes.AssignOrUpdateVariable("value", *new(big.Int).Mod(&packedValue, &secpP)) + return nil +} + +func reduceED25519(ids IdsManager, vm *VirtualMachine, scopes *ExecutionScopes) error { + secpP := SECP_P_V2() + scopes.AssignOrUpdateVariable("SECP_P", secpP) + value, err := Uint384FromVarName("x", ids, vm) + if err != nil { + return err + } + packedValue := value.Pack86() + scopes.AssignOrUpdateVariable("value", *new(big.Int).Mod(&packedValue, &secpP)) + return nil +} + +func verifyZero(ids IdsManager, vm *VirtualMachine, scopes *ExecutionScopes, secpP big.Int) error { + scopes.AssignOrUpdateVariable("SECP_P", secpP) + valUnpacked, err := Uint384FromVarName("val", ids, vm) + if err != nil { + return err + } + val := valUnpacked.Pack86() + q, r := new(big.Int).DivMod(&val, &secpP, new(big.Int)) + if r.Cmp(big.NewInt(0)) != 0 { + return errors.Errorf("verify_zero: Invalid input %s", val.Text(10)) + } + return ids.Insert("q", memory.NewMaybeRelocatableFelt(lambdaworks.FeltFromBigInt(q)), vm) +} + +// ids.low = (ids.x.d0 + ids.x.d1 * ids.BASE) & ((1 << 128) - 1) +func bigintToUint256(ids IdsManager, vm *VirtualMachine, constants *map[string]lambdaworks.Felt) error { + // Fetch variables + xD0, err := ids.GetStructFieldFelt("x", 0, vm) + if err != nil { + return err + } + xD1, err := ids.GetStructFieldFelt("x", 1, vm) + if err != nil { + return err + } + base, err := ids.GetConst("BASE", constants) + if err != nil { + return err + } + // Hint Logic + low := xD0.Add(xD1.Mul(base)).And((lambdaworks.FeltOne().Shl(128)).Sub(lambdaworks.FeltOne())) + return ids.Insert("low", memory.NewMaybeRelocatableFelt(low), vm) +} + +func isZeroNondet(ids IdsManager, vm *VirtualMachine) error { + x, err := ids.GetFelt("x", vm) + if err != nil { + return err + } + if x.IsZero() { + return vm.Segments.Memory.Insert(vm.RunContext.Ap, memory.NewMaybeRelocatableFelt(lambdaworks.FeltOne())) + } + return vm.Segments.Memory.Insert(vm.RunContext.Ap, memory.NewMaybeRelocatableFelt(lambdaworks.FeltZero())) +} + +func isZeroPack(ids IdsManager, vm *VirtualMachine, scopes *ExecutionScopes) error { + xUnpacked, err := Uint384FromVarName("x", ids, vm) + if err != nil { + return err + } + x := xUnpacked.Pack86() + secpP := SECP_P() + scopes.AssignOrUpdateVariable("SECP_P", secpP) + xModP := x.Mod(&x, &secpP) + scopes.AssignOrUpdateVariable("x", *xModP) + return nil +} + +func isZeroAssignScopeVars(scopes *ExecutionScopes) error { + secpP := SECP_P() + scopes.AssignOrUpdateVariable("SECP_P", secpP) + x, err := FetchScopeVar[big.Int]("x", scopes) + if err != nil { + return err + } + value, err := utils.DivMod(big.NewInt(1), &x, &secpP) + if err != nil { + return err + } + scopes.AssignOrUpdateVariable("value", *value) + scopes.AssignOrUpdateVariable("x_inv", *value) + return nil +} diff --git a/pkg/hints/secp_hints_test.go b/pkg/hints/secp_hints_test.go new file mode 100644 index 00000000..1e8ebc30 --- /dev/null +++ b/pkg/hints/secp_hints_test.go @@ -0,0 +1,372 @@ +package hints_test + +import ( + "math/big" + "testing" + + . "github.com/lambdaclass/cairo-vm.go/pkg/hints" + . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_codes" + . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" + . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" + . "github.com/lambdaclass/cairo-vm.go/pkg/types" + . "github.com/lambdaclass/cairo-vm.go/pkg/vm" + . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" +) + +func TestReduceV1(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "x": { + NewMaybeRelocatableFelt(FeltFromDecString("6")), + NewMaybeRelocatableFelt(FeltFromDecString("6")), + NewMaybeRelocatableFelt(FeltFromDecString("6")), + }, + }, + vm, + ) + scopes := NewExecutionScopes() + + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: REDUCE_V1, + }) + + err := hintProcessor.ExecuteHint(vm, &hintData, nil, scopes) + if err != nil { + t.Errorf("REDUCE_V1 hint failed with error %s", err) + } + // Checked scope variables + CheckScopeVar[big.Int]("SECP_P", SECP_P(), scopes, t) + + valueUnpacked := Uint384{Limbs: []Felt{FeltFromUint(6), FeltFromUint(6), FeltFromUint(6)}} + CheckScopeVar[big.Int]("value", valueUnpacked.Pack86(), scopes, t) +} + +func TestReduceV2(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "x": { + NewMaybeRelocatableFelt(FeltFromDecString("6")), + NewMaybeRelocatableFelt(FeltFromDecString("6")), + NewMaybeRelocatableFelt(FeltFromDecString("6")), + }, + }, + vm, + ) + scopes := NewExecutionScopes() + scopes.AssignOrUpdateVariable("SECP_P", SECP_P()) + + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: REDUCE_V2, + }) + + err := hintProcessor.ExecuteHint(vm, &hintData, nil, scopes) + if err != nil { + t.Errorf("REDUCE_V2 hint failed with error %s", err) + } + + valueUnpacked := Uint384{Limbs: []Felt{FeltFromUint(6), FeltFromUint(6), FeltFromUint(6)}} + CheckScopeVar[big.Int]("value", valueUnpacked.Pack86(), scopes, t) +} + +func TestReduceED(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "x": { + NewMaybeRelocatableFelt(FeltFromDecString("6")), + NewMaybeRelocatableFelt(FeltFromDecString("6")), + NewMaybeRelocatableFelt(FeltFromDecString("6")), + }, + }, + vm, + ) + scopes := NewExecutionScopes() + + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: REDUCE_ED25519, + }) + + err := hintProcessor.ExecuteHint(vm, &hintData, nil, scopes) + if err != nil { + t.Errorf("REDUCE_ED25519 hint failed with error %s", err) + } + // Checked scope variables + CheckScopeVar[big.Int]("SECP_P", SECP_P_V2(), scopes, t) + + valueUnpacked := Uint384{Limbs: []Felt{FeltFromUint(6), FeltFromUint(6), FeltFromUint(6)}} + CheckScopeVar[big.Int]("value", valueUnpacked.Pack86(), scopes, t) +} + +func TestVerifyZeroV1(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "val": { + NewMaybeRelocatableFelt(FeltFromDecString("0")), + NewMaybeRelocatableFelt(FeltFromDecString("0")), + NewMaybeRelocatableFelt(FeltFromDecString("0")), + }, + "q": {nil, nil, nil}, + }, + vm, + ) + scopes := NewExecutionScopes() + + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: VERIFY_ZERO_V1, + }) + + err := hintProcessor.ExecuteHint(vm, &hintData, nil, scopes) + if err != nil { + t.Errorf("VERIFY_ZERO_V1 hint failed with error %s", err) + } + // Check scope variables + CheckScopeVar[big.Int]("SECP_P", SECP_P(), scopes, t) + // Check ids variables + expectedQ := FeltZero() + idsQ, err := idsManager.GetFelt("q", vm) + if err != nil || expectedQ.Cmp(idsQ) != 0 { + t.Error("Wrong/No ids.q") + } +} + +func TestVerifyZeroV2(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "val": { + NewMaybeRelocatableFelt(FeltFromDecString("0")), + NewMaybeRelocatableFelt(FeltFromDecString("0")), + NewMaybeRelocatableFelt(FeltFromDecString("0")), + }, + "q": {nil, nil, nil}, + }, + vm, + ) + scopes := NewExecutionScopes() + + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: VERIFY_ZERO_V2, + }) + + err := hintProcessor.ExecuteHint(vm, &hintData, nil, scopes) + if err != nil { + t.Errorf("VERIFY_ZERO_V2 hint failed with error %s", err) + } + // Check scope variables + CheckScopeVar[big.Int]("SECP_P", SECP_P(), scopes, t) + // Check ids variables + expectedQ := FeltZero() + idsQ, err := idsManager.GetFelt("q", vm) + if err != nil || expectedQ.Cmp(idsQ) != 0 { + t.Error("Wrong/No ids.q") + } +} + +func TestVerifyZeroV3(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "val": { + NewMaybeRelocatableFelt(FeltFromDecString("0")), + NewMaybeRelocatableFelt(FeltFromDecString("0")), + NewMaybeRelocatableFelt(FeltFromDecString("0")), + }, + "q": {nil, nil, nil}, + }, + vm, + ) + scopes := NewExecutionScopes() + + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: VERIFY_ZERO_V3, + }) + + err := hintProcessor.ExecuteHint(vm, &hintData, nil, scopes) + if err != nil { + t.Errorf("VERIFY_ZERO_V3 hint failed with error %s", err) + } + // Check scope variables + CheckScopeVar[big.Int]("SECP_P", SECP_P_V2(), scopes, t) + // Check ids variables + expectedQ := FeltZero() + idsQ, err := idsManager.GetFelt("q", vm) + if err != nil || expectedQ.Cmp(idsQ) != 0 { + t.Error("Wrong/No ids.q") + } +} + +func TestBigIntTo256(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "x": { + NewMaybeRelocatableFelt(FeltFromDecString("1")), + NewMaybeRelocatableFelt(FeltFromDecString("0")), + NewMaybeRelocatableFelt(FeltFromDecString("0")), + }, + "low": {nil}, + }, + vm, + ) + constants := SetupConstantsForTest(map[string]Felt{ + "BASE": FeltFromUint(1).Shl(86), + }, &idsManager) + + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: BIGINT_TO_UINT256, + }) + + err := hintProcessor.ExecuteHint(vm, &hintData, &constants, nil) + if err != nil { + t.Errorf("BIGINT_TO_UINT256 hint failed with error %s", err) + } + // Check ids.low + low, err := idsManager.GetFelt("low", vm) + if err != nil || low != FeltOne() { + t.Error("Wrong/No ids.low") + } +} + +func TestIsZeroTrue(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "x": { + NewMaybeRelocatableFelt(FeltZero()), + }, + }, + vm, + ) + // Advance ap to avoid clashes + vm.RunContext.Ap.Offset += 1 + + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: IS_ZERO_NONDET, + }) + + err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil) + if err != nil { + t.Errorf("IS_ZERO_NONDET hint failed with error %s", err) + } + // Check memory[ap] + val, err := vm.Segments.Memory.GetFelt(vm.RunContext.Ap) + if err != nil || val != FeltOne() { + t.Error("Wrong/No value inserted into ap") + } +} + +func TestIsZeroFalse(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "x": { + NewMaybeRelocatableFelt(FeltOne()), + }, + }, + vm, + ) + // Advance ap to avoid clashes + vm.RunContext.Ap.Offset += 1 + + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: IS_ZERO_NONDET, + }) + + err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil) + if err != nil { + t.Errorf("IS_ZERO_NONDET hint failed with error %s", err) + } + // Check memory[ap] + val, err := vm.Segments.Memory.GetFelt(vm.RunContext.Ap) + if err != nil || val != FeltZero() { + t.Error("Wrong/No value inserted into ap") + } +} + +func TestIsZeroPack(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "x": { + NewMaybeRelocatableFelt(FeltFromUint(6)), + NewMaybeRelocatableFelt(FeltFromUint(6)), + NewMaybeRelocatableFelt(FeltFromUint(6)), + }, + }, + vm, + ) + + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: IS_ZERO_PACK_V1, + }) + scopes := NewExecutionScopes() + + err := hintProcessor.ExecuteHint(vm, &hintData, nil, scopes) + if err != nil { + t.Errorf("IS_ZERO_PACK_V1 hint failed with error %s", err) + } + // Check scope vars + CheckScopeVar[big.Int]("SECP_P", SECP_P(), scopes, t) + + xUnpacked := Uint384{Limbs: []Felt{FeltFromUint(6), FeltFromUint(6), FeltFromUint(6)}} + CheckScopeVar[big.Int]("x", xUnpacked.Pack86(), scopes, t) +} + +func TestIsZeroAssignScopeVars(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + idsManager := SetupIdsForTest(map[string][]*MaybeRelocatable{}, vm) + + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: IS_ZERO_ASSIGN_SCOPE_VARS, + }) + scopes := NewExecutionScopes() + x, _ := new(big.Int).SetString("52621538839140286024584685587354966255185961783273479086367", 10) + scopes.AssignOrUpdateVariable("x", *x) + + err := hintProcessor.ExecuteHint(vm, &hintData, nil, scopes) + if err != nil { + t.Errorf("IS_ZERO_ASSIGN_SCOPE_VARS hint failed with error %s", err) + } + // Check scope vars + CheckScopeVar[big.Int]("SECP_P", SECP_P(), scopes, t) + + value, _ := new(big.Int).SetString("19429627790501903254364315669614485084365347064625983303617500144471999752609", 10) + CheckScopeVar[big.Int]("value", *value, scopes, t) + CheckScopeVar[big.Int]("x_inv", *value, scopes, t) +} diff --git a/pkg/hints/signature_hints.go b/pkg/hints/signature_hints.go new file mode 100644 index 00000000..60340204 --- /dev/null +++ b/pkg/hints/signature_hints.go @@ -0,0 +1,115 @@ +package hints + +import ( + "math/big" + + . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" + . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" + . "github.com/lambdaclass/cairo-vm.go/pkg/types" + "github.com/lambdaclass/cairo-vm.go/pkg/utils" + . "github.com/lambdaclass/cairo-vm.go/pkg/vm" +) + +func divModNPacked(ids IdsManager, vm *VirtualMachine, scopes *ExecutionScopes, n *big.Int) error { + a, err := Uint384FromVarName("a", ids, vm) + if err != nil { + return err + } + b, err := Uint384FromVarName("b", ids, vm) + if err != nil { + return err + } + packedA := a.Pack86() + packedB := b.Pack86() + + val, err := utils.DivMod(&packedA, &packedB, n) + if err != nil { + return err + } + + scopes.AssignOrUpdateVariable("a", packedA) + scopes.AssignOrUpdateVariable("b", packedB) + scopes.AssignOrUpdateVariable("value", *val) + scopes.AssignOrUpdateVariable("res", *val) + + return nil +} + +func divModNPackedDivMod(ids IdsManager, vm *VirtualMachine, scopes *ExecutionScopes) error { + n, _ := new(big.Int).SetString("115792089237316195423570985008687907852837564279074904382605163141518161494337", 10) + scopes.AssignOrUpdateVariable("N", *n) + return divModNPacked(ids, vm, scopes, n) +} + +func divModNPackedDivModExternalN(ids IdsManager, vm *VirtualMachine, scopes *ExecutionScopes) error { + n, err := FetchScopeVar[big.Int]("N", scopes) + if err != nil { + return err + } + return divModNPacked(ids, vm, scopes, &n) +} + +func divModNSafeDiv(ids IdsManager, scopes *ExecutionScopes, aAlias string, bAlias string, addOne bool) error { + // Fetch scope variables + a, err := FetchScopeVar[big.Int](aAlias, scopes) + if err != nil { + return err + } + + b, err := FetchScopeVar[big.Int](bAlias, scopes) + if err != nil { + return err + } + + res, err := FetchScopeVar[big.Int]("res", scopes) + if err != nil { + return err + } + + n, err := FetchScopeVar[big.Int]("N", scopes) + if err != nil { + return err + } + + // Hint logic + value, err := utils.SafeDivBig(new(big.Int).Sub(new(big.Int).Mul(&res, &b), &a), &n) + if err != nil { + return err + } + if addOne { + value = new(big.Int).Add(value, big.NewInt(1)) + } + // Update scope + scopes.AssignOrUpdateVariable("value", *value) + return nil +} + +func getPointFromX(ids IdsManager, vm *VirtualMachine, scopes *ExecutionScopes, constants *map[string]Felt) error { + // Handle scope & ids variables + secpP := SECP_P() + scopes.AssignOrUpdateVariable("SECP_P", secpP) + betaFelt, err := ids.GetConst("BETA", constants) + if err != nil { + return err + } + beta := new(big.Int).Mod(betaFelt.ToBigInt(), &secpP) + xCubeIntUnpacked, err := Uint384FromVarName("x_cube", ids, vm) + if err != nil { + return err + } + xCube := xCubeIntUnpacked.Pack86() + vFelt, err := ids.GetFelt("v", vm) + v := vFelt.ToBigInt() + if err != nil { + return err + } + // Hint logic + yCube := new(big.Int).Mod(new(big.Int).Add(&xCube, beta), &secpP) + // y = (yCube ** ((SECP_P + 1) << 2)) % SECP_P + y := new(big.Int).Exp(yCube, new(big.Int).Rsh(new(big.Int).Add(&secpP, big.NewInt(1)), 2), &secpP) + if utils.IsEven(v) != utils.IsEven(y) { + y = new(big.Int).Sub(&secpP, y) + } + scopes.AssignOrUpdateVariable("value", *y) + return nil +} diff --git a/pkg/hints/signature_hints_test.go b/pkg/hints/signature_hints_test.go new file mode 100644 index 00000000..23c648e4 --- /dev/null +++ b/pkg/hints/signature_hints_test.go @@ -0,0 +1,235 @@ +package hints_test + +import ( + "math/big" + "testing" + + . "github.com/lambdaclass/cairo-vm.go/pkg/hints" + . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_codes" + . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" + . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" + . "github.com/lambdaclass/cairo-vm.go/pkg/types" + . "github.com/lambdaclass/cairo-vm.go/pkg/vm" + . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" +) + +func TestDivModNPackedDivMod(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "a": { + NewMaybeRelocatableFelt(FeltFromUint64(10)), + NewMaybeRelocatableFelt(FeltFromUint64(0)), + NewMaybeRelocatableFelt(FeltFromUint64(0)), + }, + "b": { + NewMaybeRelocatableFelt(FeltFromUint64(2)), + NewMaybeRelocatableFelt(FeltFromUint64(0)), + NewMaybeRelocatableFelt(FeltFromUint64(0)), + }, + }, + vm, + ) + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: DIV_MOD_N_PACKED_DIVMOD_V1, + }) + scopes := NewExecutionScopes() + err := hintProcessor.ExecuteHint(vm, &hintData, nil, scopes) + if err != nil { + t.Errorf("DIV_MOD_N_PACKED_DIVMOD_V1 hint test failed with error %s", err) + } + // Check result in scope + expectedRes := big.NewInt(5) + + res, err := FetchScopeVar[big.Int]("res", scopes) + if err != nil || res.Cmp(expectedRes) != 0 { + t.Error("Wrong/No scope value res") + } + + val, err := FetchScopeVar[big.Int]("value", scopes) + if err != nil || val.Cmp(expectedRes) != 0 { + t.Error("Wrong/No scope var value") + } +} + +func TestDivModNPackedDivModExternalN(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "a": { + NewMaybeRelocatableFelt(FeltFromUint64(20)), + NewMaybeRelocatableFelt(FeltFromUint64(0)), + NewMaybeRelocatableFelt(FeltFromUint64(0)), + }, + "b": { + NewMaybeRelocatableFelt(FeltFromUint64(2)), + NewMaybeRelocatableFelt(FeltFromUint64(0)), + NewMaybeRelocatableFelt(FeltFromUint64(0)), + }, + }, + vm, + ) + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: DIV_MOD_N_PACKED_DIVMOD_EXTERNAL_N, + }) + scopes := NewExecutionScopes() + scopes.AssignOrUpdateVariable("N", *big.NewInt(7)) + err := hintProcessor.ExecuteHint(vm, &hintData, nil, scopes) + if err != nil { + t.Errorf("DIV_MOD_N_PACKED_DIVMOD_EXTERNAL_N hint test failed with error %s", err) + } + // Check result in scope + expectedRes := big.NewInt(3) + + res, err := FetchScopeVar[big.Int]("res", scopes) + if err != nil || res.Cmp(expectedRes) != 0 { + t.Error("Wrong/No scope value res") + } + + val, err := FetchScopeVar[big.Int]("value", scopes) + if err != nil || val.Cmp(expectedRes) != 0 { + t.Error("Wrong/No scope var value") + } +} + +func TestDivModSafeDivOk(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{}, + vm, + ) + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: DIV_MOD_N_SAFE_DIV, + }) + scopes := NewExecutionScopes() + scopes.AssignOrUpdateVariable("N", *big.NewInt(5)) + scopes.AssignOrUpdateVariable("a", *big.NewInt(10)) + scopes.AssignOrUpdateVariable("b", *big.NewInt(30)) + scopes.AssignOrUpdateVariable("res", *big.NewInt(2)) + err := hintProcessor.ExecuteHint(vm, &hintData, nil, scopes) + if err != nil { + t.Errorf("DIV_MOD_N_SAFE_DIV hint test failed with error %s", err) + } + // Check result in scope + expectedValue := big.NewInt(10) // (2 * 30 - 10) / 5 = 10 + + val, err := FetchScopeVar[big.Int]("value", scopes) + if err != nil || val.Cmp(expectedValue) != 0 { + t.Error("Wrong/No scope value val") + } +} + +func TestDivModSafeDivPlusOneOk(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{}, + vm, + ) + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: DIV_MOD_N_SAFE_DIV_PLUS_ONE, + }) + scopes := NewExecutionScopes() + scopes.AssignOrUpdateVariable("N", *big.NewInt(5)) + scopes.AssignOrUpdateVariable("a", *big.NewInt(10)) + scopes.AssignOrUpdateVariable("b", *big.NewInt(30)) + scopes.AssignOrUpdateVariable("res", *big.NewInt(2)) + err := hintProcessor.ExecuteHint(vm, &hintData, nil, scopes) + if err != nil { + t.Errorf("DIV_MOD_N_SAFE_DIV_PLUS_ONE hint test failed with error %s", err) + } + // Check result in scope + expectedValue := big.NewInt(11) // (2 * 30 - 10) / 5 + 1 = 11 + + val, err := FetchScopeVar[big.Int]("value", scopes) + if err != nil || val.Cmp(expectedValue) != 0 { + t.Error("Wrong/No scope value val") + } +} + +func TestGetPointFromXOk(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "v": { + NewMaybeRelocatableFelt(FeltFromUint(18)), + }, + "x_cube": { + NewMaybeRelocatableFelt(FeltFromUint64(2147483647)), + NewMaybeRelocatableFelt(FeltFromUint64(2147483647)), + NewMaybeRelocatableFelt(FeltFromUint64(2147483647)), + }, + }, + vm, + ) + constants := SetupConstantsForTest(map[string]Felt{ + "BETA": FeltFromUint(7), + }, &idsManager) + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: GET_POINT_FROM_X, + }) + scopes := NewExecutionScopes() + err := hintProcessor.ExecuteHint(vm, &hintData, &constants, scopes) + if err != nil { + t.Errorf("GET_POINT_FROM_X hint test failed with error %s", err) + } + // Check result in scope + expectedValue, _ := new(big.Int).SetString("21517397797248348844406833268402983856262903417026833897388175962266357959124", 10) + + value, err := FetchScopeVar[big.Int]("value", scopes) + if err != nil || value.Cmp(expectedValue) != 0 { + t.Errorf("Wrong/No scope var value.\n Expected %v, got: %v", expectedValue, &value) + } +} + +func TestGetPointFromXNegativeY(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "v": { + NewMaybeRelocatableFelt(FeltOne()), + }, + "x_cube": { + NewMaybeRelocatableFelt(FeltFromUint64(2147483647)), + NewMaybeRelocatableFelt(FeltFromUint64(2147483647)), + NewMaybeRelocatableFelt(FeltFromUint64(2147483647)), + }, + }, + vm, + ) + constants := SetupConstantsForTest(map[string]Felt{ + "BETA": FeltFromUint(7), + }, &idsManager) + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: GET_POINT_FROM_X, + }) + scopes := NewExecutionScopes() + err := hintProcessor.ExecuteHint(vm, &hintData, &constants, scopes) + if err != nil { + t.Errorf("GET_POINT_FROM_X hint test failed with error %s", err) + } + // Check result in scope + expectedValue, _ := new(big.Int).SetString("94274691440067846579164151740284923997007081248613730142069408045642476712539", 10) + + value, err := FetchScopeVar[big.Int]("value", scopes) + if err != nil || value.Cmp(expectedValue) != 0 { + t.Errorf("Wrong/No scope var value.\n Expected %v, got: %v", expectedValue, &value) + } +} diff --git a/pkg/math_utils/utils.go b/pkg/math_utils/utils.go deleted file mode 100644 index 282ba4a3..00000000 --- a/pkg/math_utils/utils.go +++ /dev/null @@ -1,27 +0,0 @@ -package math_utils - -import ( - "github.com/pkg/errors" - "math/big" -) - -// Finds a nonnegative integer x < p such that (m * x) % p == n. -func DivMod(n *big.Int, m *big.Int, p *big.Int) (*big.Int, error) { - a := new(big.Int) - gcd := new(big.Int) - gcd.GCD(a, nil, m, p) - - if gcd.Cmp(big.NewInt(1)) != 0 { - return nil, errors.Errorf("gcd(%s, %s) != 1", m, p) - } - - return n.Mul(n, a).Mod(n, p), nil -} - -func ISqrt(x *big.Int) (*big.Int, error) { - if x.Sign() == -1 { - return nil, errors.Errorf("Expected x: %s to be non-negative", x) - } - res := new(big.Int) - return res.Sqrt(x), nil -} diff --git a/pkg/math_utils/utils_test.go b/pkg/math_utils/utils_test.go deleted file mode 100644 index c4eee853..00000000 --- a/pkg/math_utils/utils_test.go +++ /dev/null @@ -1,129 +0,0 @@ -package math_utils_test - -import ( - "math/big" - "testing" - - . "github.com/lambdaclass/cairo-vm.go/pkg/math_utils" -) - -func TestDivModOk(t *testing.T) { - a := new(big.Int) - b := new(big.Int) - prime := new(big.Int) - expected := new(big.Int) - - a.SetString("11260647941622813594563746375280766662237311019551239924981511729608487775604310196863705127454617186486639011517352066501847110680463498585797912894788", 10) - b.SetString("4020711254448367604954374443741161860304516084891705811279711044808359405970", 10) - prime.SetString("800000000000011000000000000000000000000000000000000000000000001", 16) - expected.SetString("2904750555256547440469454488220756360634457312540595732507835416669695939476", 10) - - num, err := DivMod(a, b, prime) - if err != nil { - t.Errorf("DivMod failed with error: %s", err) - } - if num.Cmp(expected) != 0 { - t.Errorf("Expected result: %s to be equal to %s", num, expected) - } -} - -func TestDivModMZeroFail(t *testing.T) { - a := new(big.Int) - b := new(big.Int) - prime := new(big.Int) - - a.SetString("11260647941622813594563746375280766662237311019551239924981511729608487775604310196863705127454617186486639011517352066501847110680463498585797912894788", 10) - prime.SetString("800000000000011000000000000000000000000000000000000000000000001", 16) - - _, err := DivMod(a, b, prime) - if err == nil { - t.Errorf("DivMod expected to failed with gcd != 1") - } -} - -func TestDivModMEqPFail(t *testing.T) { - a := new(big.Int) - b := new(big.Int) - prime := new(big.Int) - - a.SetString("11260647941622813594563746375280766662237311019551239924981511729608487775604310196863705127454617186486639011517352066501847110680463498585797912894788", 10) - b.SetString("800000000000011000000000000000000000000000000000000000000000001", 16) - prime.SetString("800000000000011000000000000000000000000000000000000000000000001", 16) - - _, err := DivMod(a, b, prime) - if err == nil { - t.Errorf("DivMod expected to failed with gcd != 1") - } -} - -func TestIsSqrtOk(t *testing.T) { - x := new(big.Int) - y := new(big.Int) - x.SetString("4573659632505831259480", 10) - y.Mul(x, x) - - sqr_y, err := ISqrt(y) - if err != nil { - t.Errorf("ISqrt failed with error: %s", err) - } - if x.Cmp(sqr_y) != 0 { - t.Errorf("Failed to get square root of x^2, x: %s", x) - } -} - -func TestCalculateIsqrtA(t *testing.T) { - x := new(big.Int) - x.SetString("81", 10) - sqrt, err := ISqrt(x) - if err != nil { - t.Error("ISqrt failed") - } - - expected := new(big.Int) - expected.SetString("9", 10) - - if sqrt.Cmp(expected) != 0 { - t.Errorf("ISqrt failed, expected %d, got %d", expected, sqrt) - } -} - -func TestCalculateIsqrtB(t *testing.T) { - x := new(big.Int) - x.SetString("4573659632505831259480", 10) - square := new(big.Int) - square = square.Mul(x, x) - - sqrt, err := ISqrt(square) - if err != nil { - t.Error("ISqrt failed") - } - - if sqrt.Cmp(x) != 0 { - t.Errorf("ISqrt failed, expected %d, got %d", x, sqrt) - } -} - -func TestCalculateIsqrtC(t *testing.T) { - x := new(big.Int) - x.SetString("3618502788666131213697322783095070105623107215331596699973092056135872020481", 10) - square := new(big.Int) - square = square.Mul(x, x) - - sqrt, err := ISqrt(square) - if err != nil { - t.Error("ISqrt failed") - } - - if sqrt.Cmp(x) != 0 { - t.Errorf("ISqrt failed, expected %d, got %d", x, sqrt) - } -} - -func TestIsSqrtFail(t *testing.T) { - x := big.NewInt(-1) - - _, err := ISqrt(x) - if err == nil { - t.Errorf("expected ISqrt to fail") - } -} diff --git a/pkg/utils/math_utils.go b/pkg/utils/math_utils.go index b1054f70..54ce207e 100644 --- a/pkg/utils/math_utils.go +++ b/pkg/utils/math_utils.go @@ -63,3 +63,54 @@ func SafeDivBig(x *big.Int, y *big.Int) (*big.Int, error) { } return q, nil } + +// Finds a nonnegative integer x < p such that (m * x) % p == n. +func DivMod(n *big.Int, m *big.Int, p *big.Int) (*big.Int, error) { + a, _, c := Igcdex(m, p) + if c.Cmp(big.NewInt(1)) != 0 { + return nil, errors.Errorf("Operation failed: divmod(%s, %s, %s), igcdex(%s, %s) != 1 ", n.Text(10), m.Text(10), p.Text(10), m.Text(10), p.Text(10)) + } + return new(big.Int).Mod(new(big.Int).Mul(n, a), p), nil +} + +func Igcdex(a *big.Int, b *big.Int) (*big.Int, *big.Int, *big.Int) { + zero := big.NewInt(0) + one := big.NewInt(1) + switch true { + case a.Cmp(zero) == 0 && b.Cmp(zero) == 0: + return zero, one, zero + case a.Cmp(zero) == 0: + return zero, big.NewInt(int64(a.Sign())), new(big.Int).Abs(b) + case b.Cmp(zero) == 0: + return big.NewInt(int64(a.Sign())), zero, new(big.Int).Abs(a) + default: + xSign := big.NewInt(int64(a.Sign())) + ySign := big.NewInt(int64(b.Sign())) + a = new(big.Int).Abs(a) + b = new(big.Int).Abs(b) + x, y, r, s := big.NewInt(1), big.NewInt(0), big.NewInt(0), big.NewInt(1) + for b.Cmp(zero) != 0 { + q, c := new(big.Int).DivMod(a, b, new(big.Int)) + x = new(big.Int).Sub(x, new(big.Int).Mul(q, r)) + y = new(big.Int).Sub(y, new(big.Int).Mul(q, s)) + + a, b, r, s, x, y = b, c, x, y, r, s + } + + return new(big.Int).Mul(x, xSign), new(big.Int).Mul(y, ySign), a + + } +} + +func IsEven(n *big.Int) bool { + res := new(big.Int).And(n, big.NewInt(1)) + return res.Cmp(big.NewInt(0)) != 0 +} + +func ISqrt(x *big.Int) (*big.Int, error) { + if x.Sign() == -1 { + return nil, errors.Errorf("Expected x: %s to be non-negative", x) + } + res := new(big.Int) + return res.Sqrt(x), nil +} diff --git a/pkg/utils/math_utils_test.go b/pkg/utils/math_utils_test.go index e3b2a152..3b308322 100644 --- a/pkg/utils/math_utils_test.go +++ b/pkg/utils/math_utils_test.go @@ -44,3 +44,164 @@ func TestSafeDivBigErrZeroDivison(t *testing.T) { t.Error("SafeDivBig should have failed") } } + +func TestIgcdex11(t *testing.T) { + a := big.NewInt(1) + b := big.NewInt(1) + expectedX, expectedY, expectedZ := big.NewInt(0), big.NewInt(1), big.NewInt(1) + x, y, z := Igcdex(a, b) + if x.Cmp(expectedX) != 0 || y.Cmp(expectedY) != 0 || z.Cmp(expectedZ) != 0 { + t.Error("Wrong values returned by Igcdex") + } +} + +func TestIgcdex00(t *testing.T) { + a := big.NewInt(0) + b := big.NewInt(0) + expectedX, expectedY, expectedZ := big.NewInt(0), big.NewInt(1), big.NewInt(0) + x, y, z := Igcdex(a, b) + if x.Cmp(expectedX) != 0 || y.Cmp(expectedY) != 0 || z.Cmp(expectedZ) != 0 { + t.Error("Wrong values returned by Igcdex") + } +} + +func TestIgcdex10(t *testing.T) { + a := big.NewInt(1) + b := big.NewInt(0) + expectedX, expectedY, expectedZ := big.NewInt(1), big.NewInt(0), big.NewInt(1) + x, y, z := Igcdex(a, b) + if x.Cmp(expectedX) != 0 || y.Cmp(expectedY) != 0 || z.Cmp(expectedZ) != 0 { + t.Error("Wrong values returned by Igcdex") + } +} + +func TestIgcdex46(t *testing.T) { + a := big.NewInt(4) + b := big.NewInt(6) + expectedX, expectedY, expectedZ := big.NewInt(-1), big.NewInt(1), big.NewInt(2) + x, y, z := Igcdex(a, b) + if x.Cmp(expectedX) != 0 || y.Cmp(expectedY) != 0 || z.Cmp(expectedZ) != 0 { + t.Error("Wrong values returned by Igcdex") + } +} + +func TestDivModOk(t *testing.T) { + a := new(big.Int) + b := new(big.Int) + prime := new(big.Int) + expected := new(big.Int) + + a.SetString("11260647941622813594563746375280766662237311019551239924981511729608487775604310196863705127454617186486639011517352066501847110680463498585797912894788", 10) + b.SetString("4020711254448367604954374443741161860304516084891705811279711044808359405970", 10) + prime.SetString("800000000000011000000000000000000000000000000000000000000000001", 16) + expected.SetString("2904750555256547440469454488220756360634457312540595732507835416669695939476", 10) + + num, err := DivMod(a, b, prime) + if err != nil { + t.Errorf("DivMod failed with error: %s", err) + } + if num.Cmp(expected) != 0 { + t.Errorf("Expected result: %s to be equal to %s", num, expected) + } +} + +func TestDivModMZeroFail(t *testing.T) { + a := new(big.Int) + b := new(big.Int) + prime := new(big.Int) + + a.SetString("11260647941622813594563746375280766662237311019551239924981511729608487775604310196863705127454617186486639011517352066501847110680463498585797912894788", 10) + prime.SetString("800000000000011000000000000000000000000000000000000000000000001", 16) + + _, err := DivMod(a, b, prime) + if err == nil { + t.Errorf("DivMod expected to failed with gcd != 1") + } +} + +func TestDivModMEqPFail(t *testing.T) { + a := new(big.Int) + b := new(big.Int) + prime := new(big.Int) + + a.SetString("11260647941622813594563746375280766662237311019551239924981511729608487775604310196863705127454617186486639011517352066501847110680463498585797912894788", 10) + b.SetString("800000000000011000000000000000000000000000000000000000000000001", 16) + prime.SetString("800000000000011000000000000000000000000000000000000000000000001", 16) + + _, err := DivMod(a, b, prime) + if err == nil { + t.Errorf("DivMod expected to failed with gcd != 1") + } +} + +func TestIsSqrtOk(t *testing.T) { + x := new(big.Int) + y := new(big.Int) + x.SetString("4573659632505831259480", 10) + y.Mul(x, x) + + sqr_y, err := ISqrt(y) + if err != nil { + t.Errorf("ISqrt failed with error: %s", err) + } + if x.Cmp(sqr_y) != 0 { + t.Errorf("Failed to get square root of x^2, x: %s", x) + } +} + +func TestCalculateIsqrtA(t *testing.T) { + x := new(big.Int) + x.SetString("81", 10) + sqrt, err := ISqrt(x) + if err != nil { + t.Error("ISqrt failed") + } + + expected := new(big.Int) + expected.SetString("9", 10) + + if sqrt.Cmp(expected) != 0 { + t.Errorf("ISqrt failed, expected %d, got %d", expected, sqrt) + } +} + +func TestCalculateIsqrtB(t *testing.T) { + x := new(big.Int) + x.SetString("4573659632505831259480", 10) + square := new(big.Int) + square = square.Mul(x, x) + + sqrt, err := ISqrt(square) + if err != nil { + t.Error("ISqrt failed") + } + + if sqrt.Cmp(x) != 0 { + t.Errorf("ISqrt failed, expected %d, got %d", x, sqrt) + } +} + +func TestCalculateIsqrtC(t *testing.T) { + x := new(big.Int) + x.SetString("3618502788666131213697322783095070105623107215331596699973092056135872020481", 10) + square := new(big.Int) + square = square.Mul(x, x) + + sqrt, err := ISqrt(square) + if err != nil { + t.Error("ISqrt failed") + } + + if sqrt.Cmp(x) != 0 { + t.Errorf("ISqrt failed, expected %d, got %d", x, sqrt) + } +} + +func TestIsSqrtFail(t *testing.T) { + x := big.NewInt(-1) + + _, err := ISqrt(x) + if err == nil { + t.Errorf("expected ISqrt to fail") + } +} diff --git a/pkg/vm/cairo_run/cairo_run_test.go b/pkg/vm/cairo_run/cairo_run_test.go index 845a3076..ab9a4fbe 100644 --- a/pkg/vm/cairo_run/cairo_run_test.go +++ b/pkg/vm/cairo_run/cairo_run_test.go @@ -329,6 +329,14 @@ func TestSplitIntHintProofMode(t *testing.T) { testProgramProof("split_int", t) } +func TestDivModN(t *testing.T) { + testProgram("div_mod_n", t) +} + +func TestSignature(t *testing.T) { + testProgram("signature", t) +} + func TestEcDoubleAssign(t *testing.T) { testProgram("ec_double_assign", t) } @@ -348,3 +356,11 @@ func TestCairoKeccak(t *testing.T) { func TestKeccakAddUint256(t *testing.T) { testProgram("keccak_add_uint256", t) } + +func TestReduce(t *testing.T) { + testProgram("reduce", t) +} + +func TestSecp(t *testing.T) { + testProgram("secp", t) +}