From f5f8e0b657731469e77fae359e3bf8d59cdefea3 Mon Sep 17 00:00:00 2001 From: feltroidprime Date: Wed, 18 Dec 2024 14:17:51 +0100 Subject: [PATCH 01/17] Initial commit --- cairo/programs/os.cairo | 4 + cairo/src/precompiles/ec_recover.cairo | 23 +- cairo/src/utils/circuit_basic_field_ops.cairo | 699 ++++++++++++++ cairo/src/utils/circuit_utils.cairo | 261 +++++ cairo/src/utils/ecdsa_circuit.cairo | 898 ++++++++++++++++++ cairo/src/utils/ecdsa_circuit.py | 350 +++++++ cairo/src/utils/signature.cairo | 691 +++++++++++++- cairo/src/utils/transaction.cairo | 12 +- cairo/src/utils/uint256.cairo | 11 + cairo/tests/programs/test_os.py | 2 +- cairo/tests/src/utils/test_signature.cairo | 40 +- pyproject.toml | 2 + uv.lock | 257 ++++- 13 files changed, 3176 insertions(+), 74 deletions(-) create mode 100644 cairo/src/utils/circuit_basic_field_ops.cairo create mode 100644 cairo/src/utils/circuit_utils.cairo create mode 100644 cairo/src/utils/ecdsa_circuit.cairo create mode 100644 cairo/src/utils/ecdsa_circuit.py diff --git a/cairo/programs/os.cairo b/cairo/programs/os.cairo index 194a814a..fcfdf460 100644 --- a/cairo/programs/os.cairo +++ b/cairo/programs/os.cairo @@ -62,6 +62,10 @@ func apply_transactions{ pedersen_ptr: HashBuiltin*, bitwise_ptr: BitwiseBuiltin*, range_check_ptr, + range_check96_ptr: felt*, + add_mod_ptr: ModBuiltin*, + mul_mod_ptr: ModBuiltin*, + poseidon_ptr: PoseidonBuiltin*, keccak_ptr: KeccakBuiltin*, header: model.BlockHeader*, block_hashes: Uint256*, diff --git a/cairo/src/precompiles/ec_recover.cairo b/cairo/src/precompiles/ec_recover.cairo index 036154de..4f9998bd 100644 --- a/cairo/src/precompiles/ec_recover.cairo +++ b/cairo/src/precompiles/ec_recover.cairo @@ -1,5 +1,11 @@ from starkware.cairo.common.alloc import alloc -from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin, KeccakBuiltin +from starkware.cairo.common.cairo_builtins import ( + HashBuiltin, + BitwiseBuiltin, + KeccakBuiltin, + PoseidonBuiltin, + ModBuiltin, +) from starkware.cairo.common.builtin_keccak.keccak import keccak_uint256s_bigend from starkware.cairo.common.bool import FALSE from starkware.cairo.common.math_cmp import RC_BOUND @@ -11,7 +17,7 @@ from starkware.cairo.common.cairo_secp.bigint import bigint_to_uint256, uint256_ from starkware.cairo.common.memset import memset from src.errors import Errors -from src.utils.uint256 import uint256_eq +from src.utils.uint256 import uint256_eq, uint256_to_uint384 from src.utils.utils import Helpers from src.utils.array import slice from src.utils.signature import Signature @@ -38,8 +44,12 @@ namespace PrecompileEcRecover { func run{ pedersen_ptr: HashBuiltin*, range_check_ptr, + range_check96_ptr: felt*, + add_mod_ptr: ModBuiltin*, + mul_mod_ptr: ModBuiltin*, bitwise_ptr: BitwiseBuiltin*, keccak_ptr: KeccakBuiltin*, + poseidon_ptr: PoseidonBuiltin*, }(_address: felt, input_len: felt, input: felt*) -> ( output_len: felt, output: felt*, gas_used: felt, reverted: felt ) { @@ -56,7 +66,8 @@ namespace PrecompileEcRecover { return (0, output, GAS_COST_EC_RECOVER, 0); } - let msg_hash_bigint = Helpers.bytes32_to_bigint(input_padded); + let msg_hash_uint256 = Helpers.bytes32_to_uint256(input_padded); + let msg_hash_uint384 = uint256_to_uint384(msg_hash_uint256); let r = Helpers.bytes_to_uint256(32, input_padded + 32 * 2); let s = Helpers.bytes_to_uint256(32, input_padded + 32 * 3); @@ -77,10 +88,10 @@ namespace PrecompileEcRecover { return (0, output, GAS_COST_EC_RECOVER, 0); } - let (r_bigint) = uint256_to_bigint(r); - let (s_bigint) = uint256_to_bigint(s); + let r_uint384 = uint256_to_uint384(r); + let s_uint384 = uint256_to_uint384(s); let (success, recovered_address) = Signature.try_recover_eth_address( - msg_hash_bigint, r_bigint, s_bigint, v - 27 + msg_hash_uint384, r_uint384, s_uint384, v - 27 ); if (success == 0) { diff --git a/cairo/src/utils/circuit_basic_field_ops.cairo b/cairo/src/utils/circuit_basic_field_ops.cairo new file mode 100644 index 00000000..dd3ed73d --- /dev/null +++ b/cairo/src/utils/circuit_basic_field_ops.cairo @@ -0,0 +1,699 @@ +from starkware.cairo.common.cairo_builtins import UInt384 +from starkware.cairo.common.cairo_builtins import ModBuiltin +from starkware.cairo.common.registers import get_fp_and_pc +from ethereum.utils.numeric import divmod + +const POW_2_32 = 2 ** 32; +const POW_2_64 = 2 ** 64; +const POW_2_96 = 2 ** 96; + +// Compute u512 mod p, where u512 = high * 2^256 + low +// Each high/low limb is 32 bits big and passed in BE +func u512_mod_p{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin*}( + low: (v0: felt, v1: felt, v2: felt, v3: felt, v4: felt, v5: felt, v6: felt, v7: felt), + high: (v0: felt, v1: felt, v2: felt, v3: felt, v4: felt, v5: felt, v6: felt, v7: felt), + p: UInt384, +) -> (result: UInt384) { + let (_, pc) = get_fp_and_pc(); + + pc_labelx: + let add_offsets_ptr = pc + (add_offsets - pc_labelx); + let mul_offsets_ptr = pc + (mul_offsets - pc_labelx); + + // High limbs. + assert [range_check96_ptr] = high.v7 + high.v6 * POW_2_32 + high.v5 * POW_2_64; + assert [range_check96_ptr + 1] = high.v4 + high.v3 * POW_2_32 + high.v2 * POW_2_64; + assert [range_check96_ptr + 2] = high.v1 + high.v0 * POW_2_32; + assert [range_check96_ptr + 3] = 0; + + // Shift Limbs. + assert [range_check96_ptr + 4] = 0; + assert [range_check96_ptr + 5] = 0; + assert [range_check96_ptr + 6] = 0x10000000000000000; + assert [range_check96_ptr + 7] = 0; + + // Low limbs. + assert [range_check96_ptr + 8] = low.v7 + low.v6 * POW_2_32 + low.v5 * POW_2_64; + assert [range_check96_ptr + 9] = low.v4 + low.v3 * POW_2_32 + low.v2 * POW_2_64; + assert [range_check96_ptr + 10] = low.v1 + low.v0 * POW_2_32; + assert [range_check96_ptr + 11] = 0; + + assert add_mod_ptr[0] = ModBuiltin( + p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=add_offsets_ptr, n=1 + ); + assert mul_mod_ptr[0] = ModBuiltin( + p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=mul_offsets_ptr, n=1 + ); + %{ + from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner + assert builtin_runners["add_mod_builtin"].instance_def.batch_size == 1 + assert builtin_runners["mul_mod_builtin"].instance_def.batch_size == 1 + + ModBuiltinRunner.fill_memory( + memory=memory, + add_mod=(ids.add_mod_ptr.address_, builtin_runners["add_mod_builtin"], 1), + mul_mod=(ids.mul_mod_ptr.address_, builtin_runners["mul_mod_builtin"], 1), + ) + %} + let range_check96_ptr = range_check96_ptr + 20; + let add_mod_ptr = add_mod_ptr + ModBuiltin.SIZE; + let mul_mod_ptr = mul_mod_ptr + ModBuiltin.SIZE; + return (result=[cast(range_check96_ptr - 4, UInt384*)]); + + mul_offsets: + // Compute High * Shift + dw 0; // [High] + dw 4; // [Shift] + dw 12; // [High * Shift] + + // Computes [Low + High * Shift] + add_offsets: + dw 8; // Low + dw 12; // [High * Shift] + dw 16; // [Low + High * Shift] +} + +// Compute X + Y mod p. +func add_mod_p{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*}( + x: UInt384, y: UInt384, p: UInt384 +) -> (x_plus_y: UInt384) { + let (_, pc) = get_fp_and_pc(); + + pc_labelx: + let add_offsets_ptr = pc + (add_offsets - pc_labelx); + + // X limbs (offset 0) + assert [range_check96_ptr] = x.d0; + assert [range_check96_ptr + 1] = x.d1; + assert [range_check96_ptr + 2] = x.d2; + assert [range_check96_ptr + 3] = x.d3; + // Y limbs (offset 4) + assert [range_check96_ptr + 4] = y.d0; + assert [range_check96_ptr + 5] = y.d1; + assert [range_check96_ptr + 6] = y.d2; + assert [range_check96_ptr + 7] = y.d3; + + assert add_mod_ptr[0] = ModBuiltin( + p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=add_offsets_ptr, n=1 + ); + %{ + from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner + assert builtin_runners["add_mod_builtin"].instance_def.batch_size == 1 + + ModBuiltinRunner.fill_memory( + memory=memory, + add_mod=(ids.add_mod_ptr.address_, builtin_runners["add_mod_builtin"], 1), + mul_mod=None, + ) + %} + + let range_check96_ptr = range_check96_ptr + 12; + let add_mod_ptr = add_mod_ptr + ModBuiltin.SIZE; + return (x_plus_y=[cast(range_check96_ptr - 4, UInt384*)]); + + add_offsets: + // Instruction : assert 0 + 4 == 8 + dw 0; // X + dw 4; // Y + dw 8; // X+Y +} + +// Compute X - Y mod p. +func sub_mod_p{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*}( + x: UInt384, y: UInt384, p: UInt384 +) -> (x_minus_y: UInt384) { + let (_, pc) = get_fp_and_pc(); + + pc_labelx: + let add_offsets_ptr = pc + (add_offsets - pc_labelx); + + // X limbs (offset 0) + assert [range_check96_ptr] = x.d0; + assert [range_check96_ptr + 1] = x.d1; + assert [range_check96_ptr + 2] = x.d2; + assert [range_check96_ptr + 3] = x.d3; + // Y limbs (offset 4) + assert [range_check96_ptr + 4] = y.d0; + assert [range_check96_ptr + 5] = y.d1; + assert [range_check96_ptr + 6] = y.d2; + assert [range_check96_ptr + 7] = y.d3; + + assert add_mod_ptr[0] = ModBuiltin( + p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=add_offsets_ptr, n=1 + ); + %{ + from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner + assert builtin_runners["add_mod_builtin"].instance_def.batch_size == 1 + + ModBuiltinRunner.fill_memory( + memory=memory, + add_mod=(ids.add_mod_ptr.address_, builtin_runners["add_mod_builtin"], 1), + mul_mod=None, + ) + %} + + let range_check96_ptr = range_check96_ptr + 12; + let add_mod_ptr = add_mod_ptr + ModBuiltin.SIZE; + return (x_minus_y=[cast(range_check96_ptr - 4, UInt384*)]); + + add_offsets: + // Instruction : assert 4 + 8 == 0 + // 8 is unallocated, so the assert is Y + ? == X + // => ? == X - Y, at offset 8. + dw 4; // Y + dw 8; // X-Y + dw 0; +} + +// Compute - Y mod p. +func neg_mod_p{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*}(y: UInt384, p: UInt384) -> ( + neg_y: UInt384 +) { + let (_, pc) = get_fp_and_pc(); + + pc_labelx: + let add_offsets_ptr = pc + (add_offsets - pc_labelx); + + // X limbs (offset 0) + assert [range_check96_ptr] = 0; + assert [range_check96_ptr + 1] = 0; + assert [range_check96_ptr + 2] = 0; + assert [range_check96_ptr + 3] = 0; + // Y limbs (offset 4) + assert [range_check96_ptr + 4] = y.d0; + assert [range_check96_ptr + 5] = y.d1; + assert [range_check96_ptr + 6] = y.d2; + assert [range_check96_ptr + 7] = y.d3; + + assert add_mod_ptr[0] = ModBuiltin( + p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=add_offsets_ptr, n=1 + ); + %{ + from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner + assert builtin_runners["add_mod_builtin"].instance_def.batch_size == 1 + + ModBuiltinRunner.fill_memory( + memory=memory, + add_mod=(ids.add_mod_ptr.address_, builtin_runners["add_mod_builtin"], 1), + mul_mod=None, + ) + %} + + let range_check96_ptr = range_check96_ptr + 12; + let add_mod_ptr = add_mod_ptr + ModBuiltin.SIZE; + return (neg_y=[cast(range_check96_ptr - 4, UInt384*)]); + + add_offsets: + // Instruction : assert 4 + 8 == 0 + // 8 is unallocated, so the assert is Y + ? == 0 + // => ? == -Y, at offset 8. + dw 4; // Y + dw 8; // -Y + dw 0; // 0 +} + +// Compute X / Y mod p. +func div_mod_p{range_check96_ptr: felt*, mul_mod_ptr: ModBuiltin*}( + x: UInt384, y: UInt384, p: UInt384 +) -> (x_div_y: UInt384) { + let (_, pc) = get_fp_and_pc(); + + pc_labelx: + let mul_offsets_ptr = pc + (mul_offsets - pc_labelx); + + // X limbs (offset 0) + assert [range_check96_ptr] = x.d0; + assert [range_check96_ptr + 1] = x.d1; + assert [range_check96_ptr + 2] = x.d2; + assert [range_check96_ptr + 3] = x.d3; + // Y limbs (offset 4) + assert [range_check96_ptr + 4] = y.d0; + assert [range_check96_ptr + 5] = y.d1; + assert [range_check96_ptr + 6] = y.d2; + assert [range_check96_ptr + 7] = y.d3; + + assert mul_mod_ptr[0] = ModBuiltin( + p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=mul_offsets_ptr, n=1 + ); + %{ + from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner + assert builtin_runners["mul_mod_builtin"].instance_def.batch_size == 1 + + ModBuiltinRunner.fill_memory( + memory=memory, + add_mod=None, + mul_mod=(ids.mul_mod_ptr.address_, builtin_runners["mul_mod_builtin"], 1), + ) + %} + + let range_check96_ptr = range_check96_ptr + 12; + let mul_mod_ptr = mul_mod_ptr + ModBuiltin.SIZE; + return (x_div_y=[cast(range_check96_ptr - 4, UInt384*)]); + + mul_offsets: + // Instruction : assert 4 8 == 0 + // 8 is unallocated, so the assert is Y * ? == X + // => ? == X / Y, at offset 8. + dw 4; // Y + dw 8; // X/Y + dw 0; // X +} + +// Assert X == 0 mod p. +func assert_zero_mod_P{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*}(x: UInt384, p: UInt384) { + let (_, pc) = get_fp_and_pc(); + + pc_labelx: + let add_offsets_ptr = pc + (add_offsets - pc_labelx); + + // Const 0. + assert [range_check96_ptr] = 0; + assert [range_check96_ptr + 1] = 0; + assert [range_check96_ptr + 2] = 0; + assert [range_check96_ptr + 3] = 0; + // X limbs. + assert [range_check96_ptr + 4] = x.d0; + assert [range_check96_ptr + 5] = x.d1; + assert [range_check96_ptr + 6] = x.d2; + assert [range_check96_ptr + 7] = x.d3; + + assert add_mod_ptr[0] = ModBuiltin( + p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=add_offsets_ptr, n=1 + ); + %{ + from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner + assert builtin_runners["add_mod_builtin"].instance_def.batch_size == 1 + + ModBuiltinRunner.fill_memory( + memory=memory, + add_mod=(ids.add_mod_ptr.address_, builtin_runners["add_mod_builtin"], 1), + mul_mod=None, + ) + %} + let range_check96_ptr = range_check96_ptr + 8; + let add_mod_ptr = add_mod_ptr + ModBuiltin.SIZE; + return (); + + add_offsets: + // Instruction (offsets) : assert 0 + 4 == 0 + // <=> 0 + X == 0 mod p. => X == 0 mod p. + dw 0; // 0 + dw 4; // X + dw 0; // 0 +} + +// Assert X != 0 mod p. +func assert_not_zero_mod_P{range_check96_ptr: felt*, mul_mod_ptr: ModBuiltin*}( + x: UInt384, p: UInt384 +) { + let (_, pc) = get_fp_and_pc(); + + pc_labelx: + let mul_offsets_ptr = pc + (mul_offsets - pc_labelx); + + // Const 1. (offset 0) + assert [range_check96_ptr] = 1; + assert [range_check96_ptr + 1] = 0; + assert [range_check96_ptr + 2] = 0; + assert [range_check96_ptr + 3] = 0; + // X limbs (offset 4) + assert [range_check96_ptr + 4] = x.d0; + assert [range_check96_ptr + 5] = x.d1; + assert [range_check96_ptr + 6] = x.d2; + assert [range_check96_ptr + 7] = x.d3; + + // X^-1 (offset 8) + let x_inv_d0 = [range_check96_ptr + 8]; + let x_inv_d1 = [range_check96_ptr + 9]; + let x_inv_d2 = [range_check96_ptr + 10]; + let x_inv_d3 = [range_check96_ptr + 11]; + + %{ + from garaga.hints.io import bigint_split, bigint_pack + p = bigint_pack(ids.p, 4, 2**96) + x = bigint_pack(ids.x, 4, 2**96) + x_inv = pow(x, -1, p) + limbs = bigint_split(x_inv) + ids.x_inv_d0 = limbs[0] + ids.x_inv_d1 = limbs[1] + ids.x_inv_d2 = limbs[2] + ids.x_inv_d3 = limbs[3] + %} + + assert mul_mod_ptr[0] = ModBuiltin( + p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=mul_offsets_ptr, n=1 + ); + + %{ + from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner + assert builtin_runners["mul_mod_builtin"].instance_def.batch_size == 1 + + ModBuiltinRunner.fill_memory( + memory=memory, + add_mod=None, + mul_mod=(ids.mul_mod_ptr.address_, builtin_runners["mul_mod_builtin"], 1), + ) + %} + let range_check96_ptr = range_check96_ptr + 12; + let mul_mod_ptr = mul_mod_ptr + ModBuiltin.SIZE; + return (); + + // Assert X*X_inv == 1 (hints will fill X_inv and proof will assert X*X_inv == 1). + // If X_inv does not exists, no valid proof can be generated. + mul_offsets: + // Instruction (offsets) : assert 4 * 8 == 0 + dw 4; // X + dw 8; // X_inv + dw 0; // 0 +} + +// Returns 1 if X == 0 mod p, 0 otherwise. +func is_zero_mod_p{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin*}( + x: UInt384, p: UInt384 +) -> (res: felt) { + %{ + from garaga.hints.io import bigint_pack + x = bigint_pack(ids.x, 4, 2**96) + p = bigint_pack(ids.p, 4, 2**96) + %} + if (nondet %{ x % p == 0 %} != 0) { + assert_zero_mod_P(x, p); + return (res=1); + } else { + assert_not_zero_mod_P(x, p); + return (res=0); + } +} + +// Assert X == Y mod p by asserting Y - X == 0 +func assert_eq_mod_p{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*}( + x: UInt384, y: UInt384, p: UInt384 +) { + let (_, pc) = get_fp_and_pc(); + + pc_labelx: + let add_offsets_ptr = pc + (add_offsets - pc_labelx); + + // Const 0. (offset 0) + assert [range_check96_ptr] = 0; + assert [range_check96_ptr + 1] = 0; + assert [range_check96_ptr + 2] = 0; + assert [range_check96_ptr + 3] = 0; + // X limbs (offset 4) + assert [range_check96_ptr + 4] = x.d0; + assert [range_check96_ptr + 5] = x.d1; + assert [range_check96_ptr + 6] = x.d2; + assert [range_check96_ptr + 7] = x.d3; + // Y limbs (offset 8) + assert [range_check96_ptr + 8] = y.d0; + assert [range_check96_ptr + 9] = y.d1; + assert [range_check96_ptr + 10] = y.d2; + assert [range_check96_ptr + 11] = y.d3; + + // Builtin results : + // (- X) (offset 12) + // (Y - X) (offset 16) + + assert add_mod_ptr[0] = ModBuiltin( + p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=add_offsets_ptr, n=2 + ); + %{ + from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner + assert builtin_runners["add_mod_builtin"].instance_def.batch_size == 1 + + ModBuiltinRunner.fill_memory( + memory=memory, + add_mod=(ids.add_mod_ptr.address_, builtin_runners["add_mod_builtin"], 2), + mul_mod=None, + ) + %} + let range_check96_ptr = range_check96_ptr + 16; + let add_mod_ptr = add_mod_ptr + 2 * ModBuiltin.SIZE; + return (); + + // Compute 0 - X (X + (-X) = 0) + add_offsets: + dw 4; + dw 12; // - X + dw 0; + // Compute - X + Y and assert == 0 + dw 12; // - X + dw 8; // Y + dw 0; +} + +// assert X != Y mod p by asserting (X-Y) != 0 +func assert_neq_mod_p{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin*}( + x: UInt384, y: UInt384, p: UInt384 +) { + let (_, pc) = get_fp_and_pc(); + + pc_labelx: + let add_offsets_ptr = pc + (add_offsets - pc_labelx); + let mul_offsets_ptr = pc + (mul_offsets - pc_labelx); + + // Const 1. (0) + assert [range_check96_ptr] = 1; + assert [range_check96_ptr + 1] = 0; + assert [range_check96_ptr + 2] = 0; + assert [range_check96_ptr + 3] = 0; + // X limbs. (4) + assert [range_check96_ptr + 4] = x.d0; + assert [range_check96_ptr + 5] = x.d1; + assert [range_check96_ptr + 6] = x.d2; + assert [range_check96_ptr + 7] = x.d3; + // Y limbs. (8) + assert [range_check96_ptr + 8] = y.d0; + assert [range_check96_ptr + 9] = y.d1; + assert [range_check96_ptr + 10] = y.d2; + assert [range_check96_ptr + 11] = y.d3; + + // [X-Y] (12) + + // [X-Y]^-1 (16) + let diff_inv_d0 = [range_check96_ptr + 16]; + let diff_inv_d1 = [range_check96_ptr + 17]; + let diff_inv_d2 = [range_check96_ptr + 18]; + let diff_inv_d3 = [range_check96_ptr + 19]; + + %{ + from garaga.hints.io import bigint_split, bigint_pack + p = bigint_pack(ids.p, 4, 2**96) + x = bigint_pack(ids.x, 4, 2**96) + y = bigint_pack(ids.y, 4, 2**96) + diff = (x - y) % p + diff_inv = pow(diff, -1, p) + limbs = bigint_split(diff_inv) + ids.diff_inv_d0 = limbs[0] + ids.diff_inv_d1 = limbs[1] + ids.diff_inv_d2 = limbs[2] + ids.diff_inv_d3 = limbs[3] + %} + + assert add_mod_ptr[0] = ModBuiltin( + p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=add_offsets_ptr, n=1 + ); + assert mul_mod_ptr[0] = ModBuiltin( + p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=mul_offsets_ptr, n=1 + ); + %{ + from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner + assert builtin_runners["add_mod_builtin"].instance_def.batch_size == 1 + assert builtin_runners["mul_mod_builtin"].instance_def.batch_size == 1 + + ModBuiltinRunner.fill_memory( + memory=memory, + add_mod=(ids.add_mod_ptr.address_, builtin_runners["add_mod_builtin"], 1), + mul_mod=(ids.mul_mod_ptr.address_, builtin_runners["mul_mod_builtin"], 1), + ) + %} + let range_check96_ptr = range_check96_ptr + 20; + let add_mod_ptr = add_mod_ptr + ModBuiltin.SIZE; + let mul_mod_ptr = mul_mod_ptr + ModBuiltin.SIZE; + return (); + + // Compute X - Y <=> Y + (X-Y) == X + add_offsets: + dw 8; // Y + dw 12; // X - Y + dw 4; // X + + mul_offsets: + // Assert (X-Y)*(X-Y)^-1 == 1 ==> (X-Y) != 0 + dw 12; // [X-Y] + dw 16; // [X-Y]^-1 + dw 0; +} + +// Returns 1 if X == Y mod p, 0 otherwise. +func is_eq_mod_p{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin*}( + x: UInt384, y: UInt384, p: UInt384 +) -> (res: felt) { + %{ + from garaga.hints.io import bigint_pack + x = bigint_pack(ids.x, 4, 2**96) + y = bigint_pack(ids.y, 4, 2**96) + p = bigint_pack(ids.p, 4, 2**96) + %} + + if (nondet %{ x % p == y % p %} != 0) { + assert_eq_mod_p(x, y, p); + return (res=1); + } else { + assert_neq_mod_p(x, y, p); + return (res=0); + } +} + +// Assert X == - Y mod p by asserting X + Y == 0 +func assert_opposite_mod_p{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*}( + x: UInt384, y: UInt384, p: UInt384 +) { + let (_, pc) = get_fp_and_pc(); + + pc_labelx: + let add_offsets_ptr = pc + (add_offsets - pc_labelx); + + // Const 0. + assert [range_check96_ptr] = 0; + assert [range_check96_ptr + 1] = 0; + assert [range_check96_ptr + 2] = 0; + assert [range_check96_ptr + 3] = 0; + // X limbs. + assert [range_check96_ptr + 4] = x.d0; + assert [range_check96_ptr + 5] = x.d1; + assert [range_check96_ptr + 6] = x.d2; + assert [range_check96_ptr + 7] = x.d3; + // Y limbs. + assert [range_check96_ptr + 8] = y.d0; + assert [range_check96_ptr + 9] = y.d1; + assert [range_check96_ptr + 10] = y.d2; + assert [range_check96_ptr + 11] = y.d3; + + assert add_mod_ptr[0] = ModBuiltin( + p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=add_offsets_ptr, n=1 + ); + %{ + from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner + assert builtin_runners["add_mod_builtin"].instance_def.batch_size == 1 + + ModBuiltinRunner.fill_memory( + memory=memory, + add_mod=(ids.add_mod_ptr.address_, builtin_runners["add_mod_builtin"], 1), + mul_mod=None, + ) + %} + + let range_check96_ptr = range_check96_ptr + 12; + let add_mod_ptr = add_mod_ptr + ModBuiltin.SIZE; + return (); + + // Assert X + Y == 0 <=> X == -Y + add_offsets: + dw 4; // X + dw 8; // Y + dw 0; +} + +// assert X != -Y mod p by asserting X + Y != 0 +func assert_not_opposite_mod_p{ + range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin* +}(x: UInt384, y: UInt384, p: UInt384) { + let (_, pc) = get_fp_and_pc(); + + pc_labelx: + let add_offsets_ptr = pc + (add_offsets - pc_labelx); + let mul_offsets_ptr = pc + (mul_offsets - pc_labelx); + + // Const 1. (0) + assert [range_check96_ptr] = 1; + assert [range_check96_ptr + 1] = 0; + assert [range_check96_ptr + 2] = 0; + assert [range_check96_ptr + 3] = 0; + // X limbs. (4) + assert [range_check96_ptr + 4] = x.d0; + assert [range_check96_ptr + 5] = x.d1; + assert [range_check96_ptr + 6] = x.d2; + assert [range_check96_ptr + 7] = x.d3; + // Y limbs. (8) + assert [range_check96_ptr + 8] = y.d0; + assert [range_check96_ptr + 9] = y.d1; + assert [range_check96_ptr + 10] = y.d2; + assert [range_check96_ptr + 11] = y.d3; + + // [X+Y] (12) + // ... + + // [X+Y]^-1 (16) + let sum_inv_d0 = [range_check96_ptr + 16]; + let sum_inv_d1 = [range_check96_ptr + 17]; + let sum_inv_d2 = [range_check96_ptr + 18]; + let sum_inv_d3 = [range_check96_ptr + 19]; + + %{ + from garaga.hints.io import bigint_split, bigint_pack + p = bigint_pack(ids.p, 4, 2**96) + x = bigint_pack(ids.x, 4, 2**96) + y = bigint_pack(ids.y, 4, 2**96) + _sum = (x + y) % p + sum_inv = pow(_sum, -1, p) + limbs = bigint_split(sum_inv) + ids.sum_inv_d0 = limbs[0] + ids.sum_inv_d1 = limbs[1] + ids.sum_inv_d2 = limbs[2] + ids.sum_inv_d3 = limbs[3] + %} + + assert add_mod_ptr[0] = ModBuiltin( + p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=add_offsets_ptr, n=1 + ); + assert mul_mod_ptr[0] = ModBuiltin( + p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=mul_offsets_ptr, n=1 + ); + %{ + from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner + assert builtin_runners["add_mod_builtin"].instance_def.batch_size == 1 + assert builtin_runners["mul_mod_builtin"].instance_def.batch_size == 1 + + ModBuiltinRunner.fill_memory( + memory=memory, + add_mod=(ids.add_mod_ptr.address_, builtin_runners["add_mod_builtin"], 1), + mul_mod=(ids.mul_mod_ptr.address_, builtin_runners["mul_mod_builtin"], 1), + ) + %} + let range_check96_ptr = range_check96_ptr + 20; + let add_mod_ptr = add_mod_ptr + ModBuiltin.SIZE; + let mul_mod_ptr = mul_mod_ptr + ModBuiltin.SIZE; + return (); + + // Compute X - Y + add_offsets: + dw 4; // X + dw 8; // Y + dw 12; + + mul_offsets: + // Assert (X+Y)*(X+Y)^-1 == 1 ==> (X+Y) != 0 + dw 12; // [X+Y] + dw 16; // [X+Y]^-1 + dw 0; +} + +// Returns 1 if X == -Y mod p, 0 otherwise. +func is_opposite_mod_p{ + range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin* +}(x: UInt384, y: UInt384, p: UInt384) -> (res: felt) { + %{ + from garaga.hints.io import bigint_pack + x = bigint_pack(ids.x, 4, 2**96) + y = bigint_pack(ids.y, 4, 2**96) + p = bigint_pack(ids.p, 4, 2**96) + %} + if (nondet %{ x % p == -y % p %} != 0) { + assert_opposite_mod_p(x, y, p); + return (res=1); + } else { + assert_not_opposite_mod_p(x, y, p); + return (res=0); + } +} diff --git a/cairo/src/utils/circuit_utils.cairo b/cairo/src/utils/circuit_utils.cairo new file mode 100644 index 00000000..26958af4 --- /dev/null +++ b/cairo/src/utils/circuit_utils.cairo @@ -0,0 +1,261 @@ +from starkware.cairo.common.alloc import alloc +from starkware.cairo.common.cairo_builtins import PoseidonBuiltin, UInt384, ModBuiltin +from starkware.cairo.common.poseidon_state import PoseidonBuiltinState +from starkware.cairo.common.uint256 import Uint256 +from starkware.cairo.common.registers import get_fp_and_pc, get_label_location +from starkware.cairo.common.math import assert_le_felt + +const N_LIMBS = 4; +const STARK_MIN_ONE_D2 = 0x800000000000011; + +func hash_full_transcript_and_get_Z_3_LIMBS{poseidon_ptr: PoseidonBuiltin*}( + limbs_ptr: felt*, n: felt +) -> (_s0: felt, _s1: felt, _s2: felt) { + alloc_locals; + local BASE = 2 ** 96; + // %{ + // from garaga.hints.io import pack_bigint_ptr + // to_hash=pack_bigint_ptr(memory, ids.limbs_ptr, ids.N_LIMBS, ids.BASE, ids.n) + // for e in to_hash: + // print(f"Will Hash {hex(e)}") + // %} + + let elements_end = &limbs_ptr[n * N_LIMBS]; + + tempvar elements = limbs_ptr; + tempvar pos_ptr = cast(poseidon_ptr, felt*); + + loop: + if (nondet %{ ids.elements_end - ids.elements >= 6*ids.N_LIMBS %} != 0) { + // %{ + // from garaga.hints.io import pack_bigint_ptr + // to_hash=pack_bigint_ptr(memory, ids.elements, ids.N_LIMBS, ids.BASE, 6) + // for e in to_hash: + // print(f"\t Will Hash {hex(e)}") + // %} + + assert [pos_ptr + 0] = [pos_ptr - 3] + elements[0] + (BASE) * elements[1]; + assert [pos_ptr + 1] = [pos_ptr - 2] + elements[2]; + assert [pos_ptr + 2] = [pos_ptr - 1]; + + assert [pos_ptr + 6] = [pos_ptr + 3] + elements[4] + (BASE) * elements[5]; + assert [pos_ptr + 7] = [pos_ptr + 4] + elements[6]; + assert [pos_ptr + 8] = [pos_ptr + 5]; + + assert [pos_ptr + 12] = [pos_ptr + 9] + elements[8] + (BASE) * elements[9]; + assert [pos_ptr + 13] = [pos_ptr + 10] + elements[10]; + assert [pos_ptr + 14] = [pos_ptr + 11]; + + assert [pos_ptr + 18] = [pos_ptr + 15] + elements[12] + (BASE) * elements[13]; + assert [pos_ptr + 19] = [pos_ptr + 16] + elements[14]; + assert [pos_ptr + 20] = [pos_ptr + 17]; + + assert [pos_ptr + 24] = [pos_ptr + 21] + elements[16] + (BASE) * elements[17]; + assert [pos_ptr + 25] = [pos_ptr + 22] + elements[18]; + assert [pos_ptr + 26] = [pos_ptr + 23]; + + assert [pos_ptr + 30] = [pos_ptr + 27] + elements[20] + (BASE) * elements[21]; + assert [pos_ptr + 31] = [pos_ptr + 28] + elements[22]; + assert [pos_ptr + 32] = [pos_ptr + 29]; + + let pos_ptr = pos_ptr + 6 * PoseidonBuiltin.SIZE; + tempvar elements = &elements[6 * N_LIMBS]; + tempvar pos_ptr = pos_ptr; + jmp loop; + } + + if (nondet %{ ids.elements_end - ids.elements >= ids.N_LIMBS %} != 0) { + // %{ + // from garaga.hints.io import pack_bigint_ptr + // to_hash=pack_bigint_ptr(memory, ids.elements, ids.N_LIMBS, ids.BASE, 1) + // for e in to_hash: + // print(f"\t\t Will Hash {e}") + // %} + assert [pos_ptr + 0] = [pos_ptr - 3] + elements[0] + (BASE) * elements[1]; + assert [pos_ptr + 1] = [pos_ptr - 2] + elements[2]; + assert [pos_ptr + 2] = [pos_ptr - 1]; + + let pos_ptr = pos_ptr + PoseidonBuiltin.SIZE; + + tempvar elements = &elements[N_LIMBS]; + tempvar pos_ptr = pos_ptr; + jmp loop; + } + + assert cast(elements_end, felt) = cast(elements, felt); + + tempvar poseidon_ptr = poseidon_ptr + n * PoseidonBuiltin.SIZE; + let res_ptr = poseidon_ptr - PoseidonBuiltin.SIZE; + tempvar s0 = [res_ptr].output.s0; + tempvar s1 = [res_ptr].output.s1; + tempvar s2 = [res_ptr].output.s2; + return (_s0=s0, _s1=s1, _s2=s2); +} + +// Returns the sign of value: -1 if value < 0, 1 if value > 0. +// value is considered positive if it is in [0, STARK//2[ +// value is considered negative if it is in ]STARK//2, STARK[ +// If value == 0, returned value can be either 0 or 1 (undetermined). +func sign{range_check_ptr}(value) -> felt { + const STARK_DIV_2_PLUS_ONE = (-1) / 2 + 1; // == prime//2 + 1 + const STARK_DIV_2_MIN_ONE = (-1) / 2 - 1; // == prime//2 - 1 + tempvar is_positive: felt; + %{ + from starkware.cairo.common.math_utils import as_int + ids.is_positive = 1 if as_int(ids.value, PRIME) >= 0 else 0 + %} + if (is_positive != 0) { + assert_le_felt(value, STARK_DIV_2_MIN_ONE); + return 1; + } else { + assert_le_felt(STARK_DIV_2_PLUS_ONE, value); + return -1; + } +} + +// From a 128 bit scalar, decomposes it into base (-3) such that +// scalar = sum(digits[i] * (-3)^i for i in [0, 81]) +// scalar = sum_p - sum_n +// Where sum_p = sum(digits[i] * (-3)^i for i in [0, 81] if digits[i]==1) +// And sum_n = sum(digits[i] * (-3)^i for i in [0, 81] if digits[i]==-1) +// Returns (abs(sum_p), abs(sum_n), p_sign, n_sign) +func scalar_to_epns{range_check_ptr}(scalar: felt) -> ( + sum_p: felt, sum_n: felt, p_sign: felt, n_sign: felt +) { + %{ + from garaga.hints.neg_3 import neg_3_base_le, positive_negative_multiplicities + from starkware.cairo.common.math_utils import as_int + assert 0 <= ids.scalar < 2**128 + digits = neg_3_base_le(ids.scalar) + digits = digits + [0] * (82-len(digits)) + i=1 # Loop init + %} + + tempvar d0; + %{ ids.d0 = digits[0] %} + + if (d0 != 0) { + if (d0 == 1) { + tempvar sum_p = 1; + tempvar sum_n = 0; + tempvar pow3 = -3; + } else { + tempvar sum_p = 0; + tempvar sum_n = 1; + tempvar pow3 = -3; + } + } else { + tempvar sum_p = 0; + tempvar sum_n = 0; + tempvar pow3 = -3; + } + + loop: + let pow3 = [ap - 1]; + let sum_n = [ap - 2]; + let sum_p = [ap - 3]; + %{ memory[ap] = 1 if i == 82 else 0 %} + jmp end if [ap] != 0, ap++; + + %{ i+=1 %} + + tempvar di; + %{ ids.di = digits[i-1] %} + if (di != 0) { + if (di == 1) { + tempvar sum_p = sum_p + pow3; + tempvar sum_n = sum_n; + tempvar pow3 = pow3 * (-3); + jmp loop; + } else { + tempvar sum_p = sum_p; + tempvar sum_n = sum_n + pow3; + tempvar pow3 = pow3 * (-3); + jmp loop; + } + } else { + tempvar sum_p = sum_p; + tempvar sum_n = sum_n; + tempvar pow3 = pow3 * (-3); + jmp loop; + } + + end: + let pow3 = [ap - 2]; + let sum_n = [ap - 3]; + let sum_p = [ap - 4]; + assert pow3 = (-3) ** 82; // + + // %{ + // from starkware.cairo.common.math_utils import as_int + // print(f"{as_int(ids.sum_p, PRIME)=}") + // print(f"{as_int(ids.sum_n, PRIME)=}") + // %} + assert scalar = sum_p - sum_n; + + let p_sign = sign(sum_p); + let n_sign = sign(sum_n); + + return (p_sign * sum_p, n_sign * sum_n, p_sign, n_sign); +} + +func felt_to_UInt384{range_check96_ptr: felt*}(x: felt) -> (res: UInt384) { + let d0 = [range_check96_ptr]; + let d1 = [range_check96_ptr + 1]; + let d2 = [range_check96_ptr + 2]; + %{ + from garaga.hints.io import bigint_split + limbs = bigint_split(ids.x, 4, 2 ** 96) + assert limbs[3] == 0 + ids.d0, ids.d1, ids.d2 = limbs[0], limbs[1], limbs[2] + %} + assert [range_check96_ptr + 3] = STARK_MIN_ONE_D2 - d2; + assert x = d0 + d1 * 2 ** 96 + d2 * 2 ** 192; + if (d2 == STARK_MIN_ONE_D2) { + // Take advantage of Cairo prime structure. STARK_MIN_ONE = 0 + 0 * BASE + stark_min_1_d2 * (BASE)**2. + assert d0 = 0; + assert d1 = 0; + tempvar range_check96_ptr = range_check96_ptr + 4; + return (res=UInt384(d0, d1, d2, 0)); + } else { + tempvar range_check96_ptr = range_check96_ptr + 4; + return (res=UInt384(d0, d1, d2, 0)); + } +} + +func run_modulo_circuit_basic{ + range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin* +}( + p: UInt384, + add_offsets_ptr: felt*, + add_n: felt, + mul_offsets_ptr: felt*, + mul_n: felt, + input_len: felt, + n_assert_eq: felt, +) { + assert add_mod_ptr[0] = ModBuiltin( + p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=add_offsets_ptr, n=add_n + ); + + assert mul_mod_ptr[0] = ModBuiltin( + p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=mul_offsets_ptr, n=mul_n + ); + + %{ + from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner + assert builtin_runners["add_mod_builtin"].instance_def.batch_size == 1 + assert builtin_runners["mul_mod_builtin"].instance_def.batch_size == 1 + + ModBuiltinRunner.fill_memory( + memory=memory, + add_mod=(ids.add_mod_ptr.address_, builtin_runners["add_mod_builtin"], ids.add_n), + mul_mod=(ids.mul_mod_ptr.address_, builtin_runners["mul_mod_builtin"], ids.mul_n), + ) + %} + + let range_check96_ptr = range_check96_ptr + (input_len + add_n + mul_n - n_assert_eq) * N_LIMBS; + let add_mod_ptr = &add_mod_ptr[add_n]; + let mul_mod_ptr = &mul_mod_ptr[mul_n]; + return (); +} diff --git a/cairo/src/utils/ecdsa_circuit.cairo b/cairo/src/utils/ecdsa_circuit.cairo new file mode 100644 index 00000000..8c4fbac3 --- /dev/null +++ b/cairo/src/utils/ecdsa_circuit.cairo @@ -0,0 +1,898 @@ +from starkware.cairo.common.registers import get_fp_and_pc, get_label_location + +func get_ADD_EC_POINT_circuit() -> (add_offsets: felt*, mul_offsets: felt*) { + alloc_locals; + // let (__fp__, _) = get_fp_and_pc(); + // let (constants_ptr: felt*) = get_label_location(constants_ptr_loc); + let (add_offsets_ptr: felt*) = get_label_location(add_offsets_ptr_loc); + let (mul_offsets_ptr: felt*) = get_label_location(mul_offsets_ptr_loc); + // let (output_offsets_ptr: felt*) = get_label_location(output_offsets_ptr_loc); + // let constants_ptr_len = 0; + // let input_len = 16; + // let witnesses_len = 0; + // let output_len = 8; + // let continuous_output = 0; + // let add_mod_n = 6; + // let mul_mod_n = 3; + // let n_assert_eq = 0; + // let name = 'add_ec_point'; + // let curve_id = curve_id; + // local circuit: ModuloCircuit = ModuloCircuit( + // constants_ptr, + // add_offsets_ptr, + // mul_offsets_ptr, + // output_offsets_ptr, + // constants_ptr_len, + // input_len, + // witnesses_len, + // output_len, + // continuous_output, + // add_mod_n, + // mul_mod_n, + // n_assert_eq, + // name, + // curve_id, + // ); + // return (&circuit,); + + // constants_ptr_loc: + + return (add_offsets_ptr, mul_offsets_ptr); + + add_offsets_ptr_loc: + dw 12; // None + dw 16; + dw 4; + dw 8; // None + dw 20; + dw 0; + dw 0; // None + dw 32; + dw 28; + dw 8; // None + dw 36; + dw 32; + dw 36; // None + dw 40; + dw 0; + dw 4; // None + dw 48; + dw 44; + + mul_offsets_ptr_loc: + dw 20; // None + dw 24; + dw 16; + dw 24; // None + dw 24; + dw 28; + dw 24; // None + dw 40; + dw 44; + + output_offsets_ptr_loc: + dw 36; + dw 48; +} + +func get_DOUBLE_EC_POINT_circuit() -> (add_offsets: felt*, mul_offsets: felt*) { + // alloc_locals; + // let (__fp__, _) = get_fp_and_pc(); + // let (constants_ptr: felt*) = get_label_location(constants_ptr_loc); + let (add_offsets_ptr: felt*) = get_label_location(add_offsets_ptr_loc); + let (mul_offsets_ptr: felt*) = get_label_location(mul_offsets_ptr_loc); + // let (output_offsets_ptr: felt*) = get_label_location(output_offsets_ptr_loc); + // let constants_ptr_len = 1; + // let input_len = 12; + // let witnesses_len = 0; + // let output_len = 8; + // let continuous_output = 0; + // let add_mod_n = 6; + // let mul_mod_n = 5; + // let n_assert_eq = 0; + // let name = 'double_ec_point'; + // let curve_id = curve_id; + // local circuit: ModuloCircuit = ModuloCircuit( + // constants_ptr, + // add_offsets_ptr, + // mul_offsets_ptr, + // output_offsets_ptr, + // constants_ptr_len, + // input_len, + // witnesses_len, + // output_len, + // continuous_output, + // add_mod_n, + // mul_mod_n, + // n_assert_eq, + // name, + // curve_id, + // ); + // return (&circuit,); + + // constants_ptr_loc: + // dw 3; + // dw 0; + // dw 0; + // dw 0; + + return (add_offsets_ptr, mul_offsets_ptr); + + add_offsets_ptr_loc: + dw 20; // None + dw 12; + dw 24; + dw 8; // None + dw 8; + dw 28; + dw 4; // None + dw 40; + dw 36; + dw 4; // None + dw 44; + dw 40; + dw 44; // None + dw 48; + dw 4; + dw 8; // None + dw 56; + dw 52; + + mul_offsets_ptr_loc: + dw 4; // None + dw 4; + dw 16; + dw 0; // None + dw 16; + dw 20; + dw 28; // None + dw 32; + dw 24; + dw 32; // None + dw 32; + dw 36; + dw 32; // None + dw 48; + dw 52; + + output_offsets_ptr_loc: + dw 44; + dw 56; +} + +func get_full_ecip_2P_circuit() -> (add_offsets: felt*, mul_offsets: felt*) { + // alloc_locals; + // let (__fp__, _) = get_fp_and_pc(); + // let (constants_ptr: felt*) = get_label_location(constants_ptr_loc); + let (add_offsets_ptr: felt*) = get_label_location(add_offsets_ptr_loc); + let (mul_offsets_ptr: felt*) = get_label_location(mul_offsets_ptr_loc); + // let (output_offsets_ptr: felt*) = get_label_location(output_offsets_ptr_loc); + // let constants_ptr_len = 4; + // let input_len = 224; + // let witnesses_len = 0; + // let output_len = 4; + // let continuous_output = 1; + // let add_mod_n = 117; + // let mul_mod_n = 108; + // let n_assert_eq = 1; + // let name = 'full_ecip_2P'; + // let curve_id = curve_id; + // local circuit: ModuloCircuit = ModuloCircuit( + // constants_ptr, + // add_offsets_ptr, + // mul_offsets_ptr, + // output_offsets_ptr, + // constants_ptr_len, + // input_len, + // witnesses_len, + // output_len, + // continuous_output, + // add_mod_n, + // mul_mod_n, + // n_assert_eq, + // name, + // curve_id, + // ); + // return (&circuit,); + + // constants_ptr_loc: + // dw 3; + // dw 0; + // dw 0; + // dw 0; + // dw 0; + // dw 0; + // dw 0; + // dw 0; + // dw 12528508628158887531275213211; + // dw 66632300; + // dw 0; + // dw 0; + // dw 12528508628158887531275213211; + // dw 4361599596; + // dw 0; + // dw 0; + return (add_offsets_ptr, mul_offsets_ptr); + + add_offsets_ptr_loc: + dw 244; // None + dw 232; + dw 248; + dw 228; // None + dw 228; + dw 252; + dw 260; // None + dw 264; + dw 228; + dw 224; // None + dw 224; + dw 272; + dw 272; // None + dw 276; + dw 268; + dw 276; // None + dw 280; + dw 224; + dw 228; // None + dw 288; + dw 284; + dw 288; // None + dw 292; + dw 4; + dw 228; // None + dw 296; + dw 292; + dw 224; // None + dw 300; + dw 276; + dw 292; // None + dw 292; + dw 312; + dw 276; // None + dw 316; + dw 224; + dw 308; // None + dw 308; + dw 332; + dw 332; // None + dw 336; + dw 232; + dw 328; // None + dw 336; + dw 340; + dw 304; // None + dw 304; + dw 348; + dw 344; // None + dw 348; + dw 352; + dw 28; // Eval sumdlogdiv_a_num Horner step: add coefficient_3 + dw 356; + dw 360; + dw 24; // Eval sumdlogdiv_a_num Horner step: add coefficient_2 + dw 364; + dw 368; + dw 20; // Eval sumdlogdiv_a_num Horner step: add coefficient_1 + dw 372; + dw 376; + dw 16; // Eval sumdlogdiv_a_num Horner step: add coefficient_0 + dw 380; + dw 384; + dw 52; // Eval sumdlogdiv_a_den Horner step: add coefficient_4 + dw 388; + dw 392; + dw 48; // Eval sumdlogdiv_a_den Horner step: add coefficient_3 + dw 396; + dw 400; + dw 44; // Eval sumdlogdiv_a_den Horner step: add coefficient_2 + dw 404; + dw 408; + dw 40; // Eval sumdlogdiv_a_den Horner step: add coefficient_1 + dw 412; + dw 416; + dw 36; // Eval sumdlogdiv_a_den Horner step: add coefficient_0 + dw 420; + dw 424; + dw 76; // Eval sumdlogdiv_b_num Horner step: add coefficient_4 + dw 432; + dw 436; + dw 72; // Eval sumdlogdiv_b_num Horner step: add coefficient_3 + dw 440; + dw 444; + dw 68; // Eval sumdlogdiv_b_num Horner step: add coefficient_2 + dw 448; + dw 452; + dw 64; // Eval sumdlogdiv_b_num Horner step: add coefficient_1 + dw 456; + dw 460; + dw 60; // Eval sumdlogdiv_b_num Horner step: add coefficient_0 + dw 464; + dw 468; + dw 112; // Eval sumdlogdiv_b_den Horner step: add coefficient_7 + dw 472; + dw 476; + dw 108; // Eval sumdlogdiv_b_den Horner step: add coefficient_6 + dw 480; + dw 484; + dw 104; // Eval sumdlogdiv_b_den Horner step: add coefficient_5 + dw 488; + dw 492; + dw 100; // Eval sumdlogdiv_b_den Horner step: add coefficient_4 + dw 496; + dw 500; + dw 96; // Eval sumdlogdiv_b_den Horner step: add coefficient_3 + dw 504; + dw 508; + dw 92; // Eval sumdlogdiv_b_den Horner step: add coefficient_2 + dw 512; + dw 516; + dw 88; // Eval sumdlogdiv_b_den Horner step: add coefficient_1 + dw 520; + dw 524; + dw 84; // Eval sumdlogdiv_b_den Horner step: add coefficient_0 + dw 528; + dw 532; + dw 428; // None + dw 540; + dw 544; + dw 28; // Eval sumdlogdiv_a_num Horner step: add coefficient_3 + dw 548; + dw 552; + dw 24; // Eval sumdlogdiv_a_num Horner step: add coefficient_2 + dw 556; + dw 560; + dw 20; // Eval sumdlogdiv_a_num Horner step: add coefficient_1 + dw 564; + dw 568; + dw 16; // Eval sumdlogdiv_a_num Horner step: add coefficient_0 + dw 572; + dw 576; + dw 52; // Eval sumdlogdiv_a_den Horner step: add coefficient_4 + dw 580; + dw 584; + dw 48; // Eval sumdlogdiv_a_den Horner step: add coefficient_3 + dw 588; + dw 592; + dw 44; // Eval sumdlogdiv_a_den Horner step: add coefficient_2 + dw 596; + dw 600; + dw 40; // Eval sumdlogdiv_a_den Horner step: add coefficient_1 + dw 604; + dw 608; + dw 36; // Eval sumdlogdiv_a_den Horner step: add coefficient_0 + dw 612; + dw 616; + dw 76; // Eval sumdlogdiv_b_num Horner step: add coefficient_4 + dw 624; + dw 628; + dw 72; // Eval sumdlogdiv_b_num Horner step: add coefficient_3 + dw 632; + dw 636; + dw 68; // Eval sumdlogdiv_b_num Horner step: add coefficient_2 + dw 640; + dw 644; + dw 64; // Eval sumdlogdiv_b_num Horner step: add coefficient_1 + dw 648; + dw 652; + dw 60; // Eval sumdlogdiv_b_num Horner step: add coefficient_0 + dw 656; + dw 660; + dw 112; // Eval sumdlogdiv_b_den Horner step: add coefficient_7 + dw 664; + dw 668; + dw 108; // Eval sumdlogdiv_b_den Horner step: add coefficient_6 + dw 672; + dw 676; + dw 104; // Eval sumdlogdiv_b_den Horner step: add coefficient_5 + dw 680; + dw 684; + dw 100; // Eval sumdlogdiv_b_den Horner step: add coefficient_4 + dw 688; + dw 692; + dw 96; // Eval sumdlogdiv_b_den Horner step: add coefficient_3 + dw 696; + dw 700; + dw 92; // Eval sumdlogdiv_b_den Horner step: add coefficient_2 + dw 704; + dw 708; + dw 88; // Eval sumdlogdiv_b_den Horner step: add coefficient_1 + dw 712; + dw 716; + dw 84; // Eval sumdlogdiv_b_den Horner step: add coefficient_0 + dw 720; + dw 724; + dw 620; // None + dw 732; + dw 736; + dw 744; // None + dw 748; + dw 740; + dw 120; // None + dw 752; + dw 224; + dw 756; // None + dw 264; + dw 760; + dw 760; // None + dw 764; + dw 124; + dw 124; // None + dw 768; + dw 4; + dw 760; // None + dw 772; + dw 768; + dw 784; // None + dw 796; + dw 800; + dw 4; // None + dw 800; + dw 804; + dw 128; // None + dw 808; + dw 224; + dw 812; // None + dw 264; + dw 816; + dw 816; // None + dw 820; + dw 132; + dw 132; // None + dw 824; + dw 4; + dw 816; // None + dw 828; + dw 824; + dw 840; // None + dw 852; + dw 856; + dw 804; // None + dw 856; + dw 860; + dw 200; // None + dw 864; + dw 224; + dw 868; // None + dw 264; + dw 872; + dw 204; // None + dw 876; + dw 4; + dw 872; // None + dw 880; + dw 876; + dw 860; // None + dw 884; + dw 888; + dw 120; // None + dw 892; + dw 224; + dw 896; // None + dw 264; + dw 900; + dw 900; // None + dw 904; + dw 124; + dw 124; // None + dw 908; + dw 4; + dw 900; // None + dw 912; + dw 908; + dw 924; // None + dw 936; + dw 940; + dw 4; // None + dw 940; + dw 944; + dw 128; // None + dw 948; + dw 224; + dw 952; // None + dw 264; + dw 956; + dw 956; // None + dw 960; + dw 132; + dw 132; // None + dw 964; + dw 4; + dw 956; // None + dw 968; + dw 964; + dw 980; // None + dw 992; + dw 996; + dw 944; // None + dw 996; + dw 1000; + dw 208; // None + dw 1004; + dw 224; + dw 1008; // None + dw 264; + dw 1012; + dw 212; // None + dw 1016; + dw 4; + dw 1012; // None + dw 1020; + dw 1016; + dw 1000; // None + dw 1024; + dw 1028; + dw 208; // None + dw 1032; + dw 224; + dw 1036; // None + dw 264; + dw 1040; + dw 1040; // None + dw 1044; + dw 212; + dw 212; // None + dw 1048; + dw 4; + dw 1040; // None + dw 1052; + dw 1048; + dw 8; // None + dw 1056; + dw 4; + dw 1072; // None + dw 1076; + dw 1064; + dw 216; // None + dw 1080; + dw 224; + dw 1084; // None + dw 264; + dw 1088; + dw 220; // None + dw 1092; + dw 4; + dw 1088; // None + dw 1096; + dw 1092; + dw 1076; // None + dw 1100; + dw 1104; + dw 1116; // Sum of rhs_low * c0, rhs_high * c1, rhs_high_shifted * c2 + dw 1120; + dw 1128; + dw 1128; // Sum of rhs_low * c0, rhs_high * c1, rhs_high_shifted * c2 + dw 1124; + dw 1132; + dw 4; // Assert lhs - rhs = 0 + dw 1132; + dw 748; + + mul_offsets_ptr_loc: + dw 224; // None + dw 224; + dw 240; + dw 0; // None + dw 240; + dw 244; + dw 252; // None + dw 256; + dw 248; + dw 224; // None + dw 256; + dw 260; + dw 256; // None + dw 256; + dw 268; + dw 256; // None + dw 280; + dw 284; + dw 300; // None + dw 304; + dw 296; + dw 304; // None + dw 292; + dw 308; + dw 312; // None + dw 316; + dw 320; + dw 276; // None + dw 276; + dw 324; + dw 0; // None + dw 324; + dw 328; + dw 340; // None + dw 344; + dw 320; + dw 32; // Eval sumdlogdiv_a_num Horner step: multiply by xA0 + dw 224; + dw 356; + dw 360; // Eval sumdlogdiv_a_num Horner step: multiply by xA0 + dw 224; + dw 364; + dw 368; // Eval sumdlogdiv_a_num Horner step: multiply by xA0 + dw 224; + dw 372; + dw 376; // Eval sumdlogdiv_a_num Horner step: multiply by xA0 + dw 224; + dw 380; + dw 56; // Eval sumdlogdiv_a_den Horner step: multiply by xA0 + dw 224; + dw 388; + dw 392; // Eval sumdlogdiv_a_den Horner step: multiply by xA0 + dw 224; + dw 396; + dw 400; // Eval sumdlogdiv_a_den Horner step: multiply by xA0 + dw 224; + dw 404; + dw 408; // Eval sumdlogdiv_a_den Horner step: multiply by xA0 + dw 224; + dw 412; + dw 416; // Eval sumdlogdiv_a_den Horner step: multiply by xA0 + dw 224; + dw 420; + dw 424; // None + dw 428; + dw 384; + dw 80; // Eval sumdlogdiv_b_num Horner step: multiply by xA0 + dw 224; + dw 432; + dw 436; // Eval sumdlogdiv_b_num Horner step: multiply by xA0 + dw 224; + dw 440; + dw 444; // Eval sumdlogdiv_b_num Horner step: multiply by xA0 + dw 224; + dw 448; + dw 452; // Eval sumdlogdiv_b_num Horner step: multiply by xA0 + dw 224; + dw 456; + dw 460; // Eval sumdlogdiv_b_num Horner step: multiply by xA0 + dw 224; + dw 464; + dw 116; // Eval sumdlogdiv_b_den Horner step: multiply by xA0 + dw 224; + dw 472; + dw 476; // Eval sumdlogdiv_b_den Horner step: multiply by xA0 + dw 224; + dw 480; + dw 484; // Eval sumdlogdiv_b_den Horner step: multiply by xA0 + dw 224; + dw 488; + dw 492; // Eval sumdlogdiv_b_den Horner step: multiply by xA0 + dw 224; + dw 496; + dw 500; // Eval sumdlogdiv_b_den Horner step: multiply by xA0 + dw 224; + dw 504; + dw 508; // Eval sumdlogdiv_b_den Horner step: multiply by xA0 + dw 224; + dw 512; + dw 516; // Eval sumdlogdiv_b_den Horner step: multiply by xA0 + dw 224; + dw 520; + dw 524; // Eval sumdlogdiv_b_den Horner step: multiply by xA0 + dw 224; + dw 528; + dw 532; // None + dw 536; + dw 468; + dw 228; // None + dw 536; + dw 540; + dw 32; // Eval sumdlogdiv_a_num Horner step: multiply by xA2 + dw 276; + dw 548; + dw 552; // Eval sumdlogdiv_a_num Horner step: multiply by xA2 + dw 276; + dw 556; + dw 560; // Eval sumdlogdiv_a_num Horner step: multiply by xA2 + dw 276; + dw 564; + dw 568; // Eval sumdlogdiv_a_num Horner step: multiply by xA2 + dw 276; + dw 572; + dw 56; // Eval sumdlogdiv_a_den Horner step: multiply by xA2 + dw 276; + dw 580; + dw 584; // Eval sumdlogdiv_a_den Horner step: multiply by xA2 + dw 276; + dw 588; + dw 592; // Eval sumdlogdiv_a_den Horner step: multiply by xA2 + dw 276; + dw 596; + dw 600; // Eval sumdlogdiv_a_den Horner step: multiply by xA2 + dw 276; + dw 604; + dw 608; // Eval sumdlogdiv_a_den Horner step: multiply by xA2 + dw 276; + dw 612; + dw 616; // None + dw 620; + dw 576; + dw 80; // Eval sumdlogdiv_b_num Horner step: multiply by xA2 + dw 276; + dw 624; + dw 628; // Eval sumdlogdiv_b_num Horner step: multiply by xA2 + dw 276; + dw 632; + dw 636; // Eval sumdlogdiv_b_num Horner step: multiply by xA2 + dw 276; + dw 640; + dw 644; // Eval sumdlogdiv_b_num Horner step: multiply by xA2 + dw 276; + dw 648; + dw 652; // Eval sumdlogdiv_b_num Horner step: multiply by xA2 + dw 276; + dw 656; + dw 116; // Eval sumdlogdiv_b_den Horner step: multiply by xA2 + dw 276; + dw 664; + dw 668; // Eval sumdlogdiv_b_den Horner step: multiply by xA2 + dw 276; + dw 672; + dw 676; // Eval sumdlogdiv_b_den Horner step: multiply by xA2 + dw 276; + dw 680; + dw 684; // Eval sumdlogdiv_b_den Horner step: multiply by xA2 + dw 276; + dw 688; + dw 692; // Eval sumdlogdiv_b_den Horner step: multiply by xA2 + dw 276; + dw 696; + dw 700; // Eval sumdlogdiv_b_den Horner step: multiply by xA2 + dw 276; + dw 704; + dw 708; // Eval sumdlogdiv_b_den Horner step: multiply by xA2 + dw 276; + dw 712; + dw 716; // Eval sumdlogdiv_b_den Horner step: multiply by xA2 + dw 276; + dw 720; + dw 724; // None + dw 728; + dw 660; + dw 292; // None + dw 728; + dw 732; + dw 352; // None + dw 544; + dw 740; + dw 344; // None + dw 736; + dw 744; + dw 256; // None + dw 120; + dw 756; + dw 144; // None + dw 136; + dw 776; + dw 764; // None + dw 780; + dw 752; + dw 776; // None + dw 780; + dw 784; + dw 148; // None + dw 140; + dw 788; + dw 772; // None + dw 792; + dw 752; + dw 788; // None + dw 792; + dw 796; + dw 256; // None + dw 128; + dw 812; + dw 160; // None + dw 152; + dw 832; + dw 820; // None + dw 836; + dw 808; + dw 832; // None + dw 836; + dw 840; + dw 164; // None + dw 156; + dw 844; + dw 828; // None + dw 848; + dw 808; + dw 844; // None + dw 848; + dw 852; + dw 256; // None + dw 200; + dw 868; + dw 880; // None + dw 884; + dw 864; + dw 256; // None + dw 120; + dw 896; + dw 176; // None + dw 168; + dw 916; + dw 904; // None + dw 920; + dw 892; + dw 916; // None + dw 920; + dw 924; + dw 180; // None + dw 172; + dw 928; + dw 912; // None + dw 932; + dw 892; + dw 928; // None + dw 932; + dw 936; + dw 256; // None + dw 128; + dw 952; + dw 192; // None + dw 184; + dw 972; + dw 960; // None + dw 976; + dw 948; + dw 972; // None + dw 976; + dw 980; + dw 196; // None + dw 188; + dw 984; + dw 968; // None + dw 988; + dw 948; + dw 984; // None + dw 988; + dw 992; + dw 256; // None + dw 208; + dw 1008; + dw 1020; // None + dw 1024; + dw 1004; + dw 256; // None + dw 208; + dw 1036; + dw 1044; // None + dw 1060; + dw 1032; + dw 1056; // None + dw 1060; + dw 1064; + dw 1052; // None + dw 1068; + dw 1032; + dw 12; // None + dw 1068; + dw 1072; + dw 256; // None + dw 216; + dw 1084; + dw 1096; // None + dw 1100; + dw 1080; + dw 236; // c1 = c0^2 + dw 236; + dw 1108; + dw 1108; // c2 = c0^3 + dw 236; + dw 1112; + dw 888; // rhs_low * c0 + dw 236; + dw 1116; + dw 1028; // rhs_high * c1 + dw 1108; + dw 1120; + dw 1104; // rhs_high_shifted * c2 + dw 1112; + dw 1124; + + output_offsets_ptr_loc: + dw 4; +} diff --git a/cairo/src/utils/ecdsa_circuit.py b/cairo/src/utils/ecdsa_circuit.py new file mode 100644 index 00000000..77e8bc44 --- /dev/null +++ b/cairo/src/utils/ecdsa_circuit.py @@ -0,0 +1,350 @@ +import garaga.hints.io as io +import garaga.modulo_circuit_structs as structs +from garaga.definitions import CURVES, CurveID, G1Point +from garaga.hints import neg_3 +from garaga.hints.ecip import n_coeffs_from_n_points +from garaga.modulo_circuit import WriteOps +from garaga.modulo_circuit_structs import G1PointCircuit, u384 +from garaga.precompiled_circuits.compilable_circuits.base import ( + BaseModuloCircuit, + ModuloCircuit, + PyFelt, +) +from garaga.precompiled_circuits.ec import ECIPCircuits +from garaga.starknet.tests_and_calldata_generators.msm import MSMCalldataBuilder + + +class FullEcdsaCircuitBatched(BaseModuloCircuit): + def __init__( + self, + curve_id: int, + n_points: int = 2, + auto_run: bool = True, + compilation_mode: int = 0, + ) -> None: + self.n_points = n_points + super().__init__( + name=f"full_ecip_{n_points}P", + curve_id=curve_id, + auto_run=auto_run, + compilation_mode=compilation_mode, + ) + + def build_input(self) -> list[PyFelt]: + input = [] + n_coeffs = n_coeffs_from_n_points(self.n_points, batched=True) + + # RLCSumDlogDiv + for _ in range(sum(n_coeffs)): + input.append(self.field.random()) + + for _ in range(self.n_points): + input.append(self.field.random()) # x + input.append(self.field.random()) # y + input.append(self.field.random()) # ep_low + input.append(self.field.random()) # en_low + input.append(self.field.random()) # sp_low + input.append(self.field.random()) # sn_low + input.append(self.field.random()) # ep_high + input.append(self.field.random()) # en_high + input.append(self.field.random()) # sp_high + input.append(self.field.random()) # sn_high + + # Q_low/high/high_shifted + A0 + for i in range(4): + input.append(self.field.random()) # x + input.append(self.field.random()) # y + + input.append(self.field(CURVES[self.curve_id].a)) # A_weirstrass + input.append(self.field.random()) # base_rlc. + + return input + + def sample_input(self): + cid = CurveID(self.curve_id) + pts = [ + G1Point.get_nG(cid, 1), + G1Point( + x=111354266934415748707439662129962068258185897787462436790090135304890680225071, + y=7955571364956903103447762143713116749685657035734622395391095226875188998922, + curve_id=CurveID.SECP256K1, + ), + ] + scalars = [ + 0xF6F935191273414ADA91071ED97A8A31347F85D5FAC890148FDAC827E0426B68, + 0x4FDA889C1E0B2F466819231FBF731EBFF91B507CC44A0C810B0DECDEAA99B7D2, + ] + builder = MSMCalldataBuilder(cid, pts, scalars) + (msm_hint, derive_point_from_x_hint) = builder.build_msm_hints() + scalars_low, scalars_high = builder.scalars_split() + epns_low, epns_high = [neg_3.scalar_to_base_neg3_le(s) for s in scalars_low], [ + neg_3.scalar_to_base_neg3_le(s) for s in scalars_high + ] + + Q_low, Q_high, Q_high_shifted, RLCSumDlogDiv = msm_hint.elmts + + rlc_sum_dlog_div_coeffs = ( + RLCSumDlogDiv.a_num + + RLCSumDlogDiv.a_den + + RLCSumDlogDiv.b_num + + RLCSumDlogDiv.b_den + ) + + assert len(rlc_sum_dlog_div_coeffs) == sum( + n_coeffs_from_n_points(self.n_points, batched=True) + ) + + input = [] + input.extend(rlc_sum_dlog_div_coeffs) + + def sign(x): + return 1 if x >= 0 else -1 + + for i in range(self.n_points): + input.append(self.field(pts[i].x)) + input.append(self.field(pts[i].y)) + print(f"pt_{i}: epns_low: {epns_low[i]}") + input.append(self.field(epns_low[i][0])) + input.append(self.field(epns_low[i][1])) + input.append(self.field(epns_low[i][2])) + input.append(self.field(epns_low[i][3])) + print(f"pt_{i}: epns_high: {epns_high[i]}") + input.append(self.field(epns_high[i][0])) + input.append(self.field(epns_high[i][1])) + input.append(self.field(epns_high[i][2])) + input.append(self.field(epns_high[i][3])) + + input.extend(Q_low.elmts) + input.extend(Q_high.elmts) + input.extend(Q_high_shifted.elmts) + _random = builder.A0 + print(f"A0 : {_random.to_cairo_1()}") + input.extend([self.field(_random.x), self.field(_random.y)]) + input.append(self.field(CURVES[self.curve_id].a)) # A_weirstrass + input.append(self.field(builder.rlc_coeff)) # base_rlc + + return input + + def _run_circuit_inner(self, input: list[PyFelt]) -> ModuloCircuit: + circuit = ECIPCircuits( + self.name, self.curve_id, compilation_mode=self.compilation_mode + ) + n_coeffs = n_coeffs_from_n_points(self.n_points, batched=True) + ff_coeffs = input[: sum(n_coeffs)] + + def split_list(input_list, lengths): + start_idx, result = 0, [] + for length in lengths: + result.append(input_list[start_idx : start_idx + length]) + start_idx += length + return result + + def get_log_div_coeffs(circuit, ff_coeffs): + _log_div_a_num, _log_div_a_den, _log_div_b_num, _log_div_b_den = split_list( + ff_coeffs, n_coeffs_from_n_points(self.n_points, batched=True) + ) + log_div_a_num, log_div_a_den, log_div_b_num, log_div_b_den = ( + circuit.write_struct( + structs.FunctionFeltCircuit( + name="SumDlogDiv", + elmts=[ + structs.u384Span("log_div_a_num", _log_div_a_num), + structs.u384Span("log_div_a_den", _log_div_a_den), + structs.u384Span("log_div_b_num", _log_div_b_num), + structs.u384Span("log_div_b_den", _log_div_b_den), + ], + ), + WriteOps.INPUT, + ) + ) + + return log_div_a_num, log_div_a_den, log_div_b_num, log_div_b_den + + log_div_a_num_low, log_div_a_den_low, log_div_b_num_low, log_div_b_den_low = ( + get_log_div_coeffs(circuit, ff_coeffs) + ) + + all_points = input[sum(n_coeffs) :] + + points = [] + ep_lows = [] + en_lows = [] + sp_lows = [] + sn_lows = [] + ep_highs = [] + en_highs = [] + sp_highs = [] + sn_highs = [] + for i in range(self.n_points): + print(f"i: {i}") + base_idx = i * 10 + pt_circuit = G1PointCircuit(f"p_{i}", all_points[base_idx : base_idx + 2]) + pt_circuit.validate(self.curve_id) + points.append(circuit.write_struct(pt_circuit)) + ep_lows.append(all_points[base_idx + 2]) + en_lows.append(all_points[base_idx + 3]) + sp_lows.append(all_points[base_idx + 4]) + sn_lows.append(all_points[base_idx + 5]) + ep_highs.append(all_points[base_idx + 6]) + en_highs.append(all_points[base_idx + 7]) + sp_highs.append(all_points[base_idx + 8]) + sn_highs.append(all_points[base_idx + 9]) + + epns_low = circuit.write_struct( + structs.StructSpan( + "epns_low", + [ + structs.Tuple( + f"epn_{i}", + elmts=[ + structs.u384("ep", [ep_lows[i]]), + structs.u384("en", [en_lows[i]]), + structs.u384("sp", [sp_lows[i]]), + structs.u384("sn", [sn_lows[i]]), + ], + ) + for i in range(self.n_points) + ], + ) + ) + + print(f"epns_low: {epns_low} (n_points: {self.n_points})") + + epns_high = circuit.write_struct( + structs.StructSpan( + "epns_high", + [ + structs.Tuple( + f"epn_{i}", + elmts=[ + structs.u384("ep", [ep_highs[i]]), + structs.u384("en", [en_highs[i]]), + structs.u384("sp", [sp_highs[i]]), + structs.u384("sn", [sn_highs[i]]), + ], + ) + for i in range(self.n_points) + ], + ) + ) + + rest_points = all_points[self.n_points * 10 :] + q_low = circuit.write_struct( + structs.G1PointCircuit("q_low", elmts=rest_points[0:2]) + ) + q_high = circuit.write_struct( + structs.G1PointCircuit("q_high", elmts=rest_points[2:4]) + ) + + q_high_shifted = circuit.write_struct( + structs.G1PointCircuit("q_high_shifted", elmts=rest_points[4:6]), + ) + random_point = structs.G1PointCircuit("a0", elmts=rest_points[6:8]) + random_point.validate(self.curve_id) + a0 = circuit.write_struct(random_point) + + A_weirstrass = circuit.write_struct( + structs.u384("A_weirstrass", elmts=[rest_points[8]]) + ) + base_rlc = circuit.write_struct( + structs.u384("base_rlc", elmts=[rest_points[9]]) + ) + + m_A0, b_A0, xA0, yA0, xA2, yA2, coeff0, coeff2 = ( + circuit._slope_intercept_same_point(a0, A_weirstrass) + ) + + lhs = circuit._eval_function_challenge_dupl( + (xA0, yA0), + (xA2, yA2), + coeff0, + coeff2, + log_div_a_num_low, + log_div_a_den_low, + log_div_b_num_low, + log_div_b_den_low, + ) + + def compute_base_rhs(circuit: ECIPCircuits, points, epns, m_A0, b_A0, xA0): + acc = circuit.set_or_get_constant(0) + for i, (pt, _epns) in enumerate(zip(points, epns)): + _epns = io.flatten(_epns) + print(f"i: {i}, _epns: {_epns}") + acc = circuit._accumulate_eval_point_challenge_signed_same_point( + eval_accumulator=acc, + slope_intercept=(m_A0, b_A0), + xA=xA0, + P=pt, + ep=_epns[0], + en=_epns[1], + sign_ep=_epns[2], + sign_en=_epns[3], + ) + return acc + + base_rhs_low = compute_base_rhs(circuit, points, epns_low, m_A0, b_A0, xA0) + rhs_low = circuit._RHS_finalize_acc( + base_rhs_low, + (m_A0, b_A0), + xA0, + (q_low[0], q_low[1]), + ) + + base_rhs_high = compute_base_rhs(circuit, points, epns_high, m_A0, b_A0, xA0) + rhs_high = circuit._RHS_finalize_acc( + base_rhs_high, (m_A0, b_A0), xA0, (q_high[0], q_high[1]) + ) + + base_rhs_high_shifted = ( + circuit._compute_eval_point_challenge_signed_same_point_2_pow_128( + (m_A0, b_A0), + xA0, + q_high, + ) + ) + rhs_high_shifted = circuit._RHS_finalize_acc( + base_rhs_high_shifted, + (m_A0, b_A0), + xA0, + (q_high_shifted[0], q_high_shifted[1]), + ) + + c0 = base_rlc + c1 = circuit.mul(c0, c0, "c1 = c0^2") + c2 = circuit.mul(c1, c0, "c2 = c0^3") + + rhs = circuit.sum( + [ + circuit.mul(rhs_low, c0, "rhs_low * c0"), + circuit.mul(rhs_high, c1, "rhs_high * c1"), + circuit.mul(rhs_high_shifted, c2, "rhs_high_shifted * c2"), + ], + "Sum of rhs_low * c0, rhs_high * c1, rhs_high_shifted * c2", + ) + + final_check = circuit.sub_and_assert( + lhs, rhs, circuit.set_or_get_constant(0), "Assert lhs - rhs = 0" + ) + + assert lhs.value == rhs.value, "lhs and rhs must be equal" + circuit.extend_struct_output(u384("final_check", [final_check])) + + return circuit + + +if __name__ == "__main__": + circuit = FullEcdsaCircuitBatched( + CurveID.SECP256K1.value, n_points=2, auto_run=False + ) + input = circuit.sample_input() + print(f"input = {[hex(v.value) for v in input]} len : {len(input)}") + circuit.circuit = circuit._run_circuit_inner(input) + + code, _ = circuit.circuit.compile_circuit() + + # # Print constants : + # print(circuit.circuit.constants) + + print(circuit.circuit.print_value_segment(base=16)) + + # print(code) diff --git a/cairo/src/utils/signature.cairo b/cairo/src/utils/signature.cairo index 1d161126..b32497a4 100644 --- a/cairo/src/utils/signature.cairo +++ b/cairo/src/utils/signature.cairo @@ -1,36 +1,344 @@ -from starkware.cairo.common.cairo_builtins import BitwiseBuiltin, KeccakBuiltin -from starkware.cairo.common.cairo_secp.bigint3 import BigInt3 -from starkware.cairo.common.cairo_secp.ec_point import EcPoint -from starkware.cairo.common.cairo_secp.signature import ( - validate_signature_entry, - try_get_point_from_x, - get_generator_point, - div_mod_n, +from starkware.cairo.common.cairo_builtins import ( + BitwiseBuiltin, + KeccakBuiltin, + ModBuiltin, + UInt384, + PoseidonBuiltin, ) +from starkware.cairo.common.poseidon_state import PoseidonBuiltinState +from starkware.cairo.common.registers import get_fp_and_pc, get_label_location +from ethereum.utils.numeric import divmod + from starkware.cairo.common.math_cmp import RC_BOUND -from starkware.cairo.common.cairo_secp.bigint import bigint_to_uint256, uint256_to_bigint from starkware.cairo.common.builtin_keccak.keccak import keccak_uint256s_bigend -from starkware.cairo.common.cairo_secp.ec import ec_add, ec_mul, ec_negate from starkware.cairo.common.uint256 import Uint256 from starkware.cairo.common.alloc import alloc -from src.utils.maths import unsigned_div_rem +from src.utils.maths import unsigned_div_rem from src.interfaces.interfaces import ICairo1Helpers +from src.utils.circuit_basic_field_ops import div_mod_p, neg_mod_p, is_opposite_mod_p, is_eq_mod_p +from src.utils.circuit_utils import ( + N_LIMBS, + hash_full_transcript_and_get_Z_3_LIMBS, + scalar_to_epns, + felt_to_UInt384, + run_modulo_circuit_basic, +) +from src.utils.uint256 import uint256_to_uint384 + +from src.utils.ecdsa_circuit import ( + get_full_ecip_2P_circuit, + get_ADD_EC_POINT_circuit, + get_DOUBLE_EC_POINT_circuit, +) + +struct G1Point { + x: UInt384, + y: UInt384, +} + +namespace secp256k1 { + const CURVE_ID = 2; + const P0 = 0xfffffffffffffffefffffc2f; + const P1 = 0xffffffffffffffffffffffff; + const P2 = 0xffffffffffffffff; + const P3 = 0x0; + const N0 = 0xaf48a03bbfd25e8cd0364141; + const N1 = 0xfffffffffffffffebaaedce6; + const N2 = 0xffffffffffffffff; + const N_LOW_128 = 0xbaaedce6af48a03bbfd25e8cd0364141; + const N_HIGH_128 = 0xfffffffffffffffffffffffffffffffe; + const N3 = 0x0; + const A0 = 0x0; + const A1 = 0x0; + const A2 = 0x0; + const A3 = 0x0; + const B0 = 0x7; + const B1 = 0x0; + const B2 = 0x0; + const B3 = 0x0; + const G0 = 0x3; + const G1 = 0x0; + const G2 = 0x0; + const G3 = 0x0; + const MIN_ONE_D0 = 0xfffffffffffffffefffffc2e; + const MIN_ONE_D1 = 0xffffffffffffffffffffffff; + const MIN_ONE_D2 = 0xffffffffffffffff; + const MIN_ONE_D3 = 0x0; +} + +@known_ap_change +func get_generator_point() -> (point: G1Point) { + // generator_point = ( + // 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798, + // 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 + // ). + return ( + point=G1Point( + x=UInt384( + 0x2dce28d959f2815b16f81798, 0x55a06295ce870b07029bfcdb, 0x79be667ef9dcbbac, 0x0 + ), + y=UInt384( + 0xa68554199c47d08ffb10d4b8, 0x5da4fbfc0e1108a8fd17b448, 0x483ada7726a3c465, 0x0 + ), + ), + ); +} + +@known_ap_change +func sign_to_UInt384_mod_secp256k1(sign: felt) -> (res: UInt384) { + if (sign == -1) { + return (res=UInt384(secp256k1.MIN_ONE_D0, secp256k1.MIN_ONE_D1, secp256k1.MIN_ONE_D2, 0)); + } else { + return (res=UInt384(1, 0, 0, 0)); + } +} + +// Takes a valid UInt384 value from ModuloBuiltin output, adds constraints to enforce it is canonically reduced mod p (ie: 0 <= a < p) and converts it to a Uint256. +// Assumes 1 < p < 2^256 passed as valid Uint384. +func uint384_to_uint256_mod_p{range_check_ptr}(a: UInt384, p: UInt384) -> (res: Uint256) { + assert a.d3 = 0; // From assumption : "p < 2^256", canonical reduction of a is only possible if a.d3 is 0. + if (a.d2 == p.d2) { + if (a.d1 == p.d1) { + assert [range_check_ptr] = p.d0 - 1 - a.d0; + tempvar range_check_ptr = range_check_ptr + 1; + } else { + assert [range_check_ptr] = p.d1 - 1 - a.d1; + tempvar range_check_ptr = range_check_ptr + 1; + } + } else { + assert [range_check_ptr] = p.d2 - a.d2; // a.d2 <= p.d2 && a.d2 != p.d2 => a.d2 < p.d2 + tempvar range_check_ptr = range_check_ptr + 1; + } + // Then decompose and rebuild uint256 + let (d1_high_64, d1_low_32) = divmod(a.d1, 2 ** 32); + // a.d2 is guaranteed to be in 64 bits since we know it's fully reduced. + return (res=Uint256(low=a.d0 + 2 ** 96 * d1_low_32, high=d1_high_64 + 2 ** 64 * a.d2)); +} + +// A function field element of the form : +// F(x,y) = a(x) + y b(x) +// Where a, b are rational functions of x. +// The rational functions are represented as polynomials in x with coefficients in F_p, starting from the constant term. +// No information about the degrees of the polynomials is stored here as they are derived implicitely from the MSM size. +struct FunctionFelt { + a_num: UInt384*, + a_den: UInt384*, + b_num: UInt384*, + b_den: UInt384*, +} + +func hash_sum_dlog_div_batched{poseidon_ptr: PoseidonBuiltin*}( + f: FunctionFelt, msm_size: felt, init_hash: felt, curve_id: felt +) -> (res: felt) { + alloc_locals; + assert poseidon_ptr[0].input.s0 = init_hash; + assert poseidon_ptr[0].input.s1 = 0; + assert poseidon_ptr[0].input.s2 = 1; + let poseidon_ptr = poseidon_ptr + PoseidonBuiltin.SIZE; + + let (s0: felt, s1: felt, s2: felt) = hash_full_transcript_and_get_Z_3_LIMBS( + limbs_ptr=cast(f.a_num, felt*), n=msm_size + 1, curve_id=curve_id + ); + let (s0: felt, s1: felt, s2: felt) = hash_full_transcript_and_get_Z_3_LIMBS( + limbs_ptr=cast(f.a_den, felt*), n=msm_size + 2, curve_id=curve_id + ); + let (s0: felt, s1: felt, s2: felt) = hash_full_transcript_and_get_Z_3_LIMBS( + limbs_ptr=cast(f.b_num, felt*), n=msm_size + 2, curve_id=curve_id + ); + let (Z: felt, _, _) = hash_full_transcript_and_get_Z_3_LIMBS( + limbs_ptr=cast(f.b_den, felt*), n=msm_size + 5, curve_id=curve_id + ); + + return (res=Z); +} + +func try_get_point_from_x_secp256k1{ + range_check96_ptr: felt*, + add_mod_ptr: ModBuiltin*, + mul_mod_ptr: ModBuiltin*, + poseidon_ptr: PoseidonBuiltin*, +}(x: UInt384, v: felt, result: G1Point*) -> (is_on_curve: felt) { + alloc_locals; + let (__fp__, _) = get_fp_and_pc(); + let (add_offsets_ptr: felt*) = get_label_location(add_offsets_ptr_loc); + let (mul_offsets_ptr: felt*) = get_label_location(mul_offsets_ptr_loc); + let constants_ptr_len = 2; + let input_len = 6; + let add_mod_n = 5; + let mul_mod_n = 7; + let n_assert_eq = 1; + + local rhs_from_x_is_a_square_residue: felt; + local y_try: UInt384; + %{ + from starkware.python.math_utils import is_quad_residue + from sympy import sqrt_mod + from garaga.definitions import CURVES, CurveID + from garaga.hints.io import bigint_pack, bigint_fill + curve_id = CurveID.SECP256K1.value + a = CURVES[curve_id].a + b = CURVES[curve_id].b + p = CURVES[curve_id].p + x = bigint_pack(ids.x, 4, 2**96) + rhs = (x**3 + a*x + b) % p + ids.rhs_from_x_is_a_square_residue = is_quad_residue(rhs, p) + if ids.rhs_from_x_is_a_square_residue == 1: + square_root = sqrt_mod(rhs, p) + if ids.v % 2 == square_root % 2: + pass + else: + square_root = - square_root % p + else: + square_root = sqrt_mod(rhs*CURVES[curve_id].fp_generator, p) + + bigint_fill(square_root, ids.y_try, 4, 2**96) + %} + + let P: UInt384 = UInt384(secp256k1.P0, secp256k1.P1, secp256k1.P2, secp256k1.P3); + + let input: UInt384* = cast(range_check96_ptr, UInt384*); + + assert input[0] = UInt384(1, 0, 0, 0); // constant + assert input[1] = UInt384(0, 0, 0, 0); // constant + assert input[2] = x; + assert input[3] = UInt384(secp256k1.A0, secp256k1.A1, secp256k1.A2, secp256k1.A3); + assert input[4] = UInt384(secp256k1.B0, secp256k1.B1, secp256k1.B2, secp256k1.B3); + assert input[5] = UInt384(secp256k1.G0, secp256k1.G1, secp256k1.G2, secp256k1.G3); + assert input[6] = y_try; + + if (rhs_from_x_is_a_square_residue != 0) { + assert input[7] = UInt384(1, 0, 0, 0); // True + } else { + assert input[7] = UInt384(0, 0, 0, 0); // False + } + + run_modulo_circuit_basic( + P, + add_offsets_ptr, + add_mod_n, + mul_offsets_ptr, + mul_mod_n, + input_len + constants_ptr_len, + n_assert_eq, + ); + + if (rhs_from_x_is_a_square_residue != 0) { + assert [result] = G1Point(x=x, y=y_try); + return (is_on_curve=1); + } else { + assert [result] = G1Point(x=UInt384(0, 0, 0, 0), y=UInt384(0, 0, 0, 0)); + return (is_on_curve=0); + } + + add_offsets_ptr_loc: + dw 40; // (ax)+b + dw 16; + dw 44; + dw 36; // (x3+ax)+b=rhs + dw 44; + dw 48; + dw 28; // (1-is_on_curve) + dw 60; + dw 0; + dw 56; // is_on_curve*rhs + (1-is_on_curve)*g*rhs + dw 64; + dw 68; + dw 4; // assert rhs_or_grhs == should_be_rhs_or_grhs + dw 72; + dw 68; + + mul_offsets_ptr_loc: + dw 8; // x2 + dw 8; + dw 32; + dw 8; // x3 + dw 32; + dw 36; + dw 12; // ax + dw 8; + dw 40; + dw 20; // g*rhs + dw 48; + dw 52; + dw 28; // is_on_curve*rhs + dw 48; + dw 56; + dw 60; // (1-is_on_curve)*grhs + dw 52; + dw 64; + dw 24; // y_try^2=should_be_rhs_or_grhs + dw 24; + dw 72; +} + +func get_point_from_x_secp256k1{ + range_check96_ptr: felt*, + add_mod_ptr: ModBuiltin*, + mul_mod_ptr: ModBuiltin*, + poseidon_ptr: PoseidonBuiltin*, +}(x: felt, attempt: felt) -> (res: G1Point) { + alloc_locals; + let (local res: G1Point*) = alloc(); + let (x_384: UInt384) = felt_to_UInt384(x); + + let (is_on_curve) = try_get_point_from_x_secp256k1(x=x_384, v=0, result=res); + + if (is_on_curve != 0) { + return (res=[res]); + } else { + assert poseidon_ptr[0].input.s0 = x; + assert poseidon_ptr[0].input.s1 = attempt; + assert poseidon_ptr[0].input.s2 = 2; + let new_x = poseidon_ptr[0].output.s0; + tempvar poseidon_ptr = poseidon_ptr + PoseidonBuiltin.SIZE; + return get_point_from_x_secp256k1(x=new_x, attempt=attempt + 1); + } +} namespace Signature { // A version of verify_eth_signature that uses the keccak builtin. + + // Assert 1 <= x < N. Assumes valid Uint256. + func validate_signature_entry{range_check_ptr}(x: Uint256) { + if (x.high == 0) { + if (x.low == 0) { + assert 1 = 0; + return (); + } else { + return (); + } + } else { + if (x.high == secp256k1.N_HIGH_128) { + assert [range_check_ptr] = secp256k1.N_LOW_128 - 1 - x.low; + tempvar range_check_ptr = range_check_ptr + 1; + return (); + } else { + assert [range_check_ptr] = secp256k1.N_HIGH_128 - 1 - x.high; + tempvar range_check_ptr = range_check_ptr + 1; + return (); + } + } + } + func verify_eth_signature_uint256{ - range_check_ptr, bitwise_ptr: BitwiseBuiltin*, keccak_ptr: KeccakBuiltin* + range_check_ptr, + range_check96_ptr: felt*, + add_mod_ptr: ModBuiltin*, + mul_mod_ptr: ModBuiltin*, + bitwise_ptr: BitwiseBuiltin*, + keccak_ptr: KeccakBuiltin*, + poseidon_ptr: PoseidonBuiltin*, }(msg_hash: Uint256, r: Uint256, s: Uint256, y_parity: felt, eth_address: felt) { alloc_locals; - let (msg_hash_bigint: BigInt3) = uint256_to_bigint(msg_hash); - let (r_bigint: BigInt3) = uint256_to_bigint(r); - let (s_bigint: BigInt3) = uint256_to_bigint(s); - + let msg_hash_uint384: UInt384 = uint256_to_uint384(msg_hash); + // Todo :fix with UInt384 with_attr error_message("Signature out of range.") { - validate_signature_entry(r_bigint); - validate_signature_entry(s_bigint); + validate_signature_entry(r); + validate_signature_entry(s); } + let r_uint384: UInt384 = uint256_to_uint384(r); + let s_uint384: UInt384 = uint256_to_uint384(s); with_attr error_message("Invalid y_parity") { assert (1 - y_parity) * y_parity = 0; @@ -38,7 +346,7 @@ namespace Signature { with_attr error_message("Invalid signature.") { let (success, recovered_address) = try_recover_eth_address( - msg_hash=msg_hash_bigint, r=r_bigint, s=s_bigint, y_parity=y_parity + msg_hash=msg_hash_uint384, r=r_uint384, s=s_uint384, y_parity=y_parity ); assert success = 1; } @@ -59,32 +367,262 @@ namespace Signature { // @dev * r is the x coordinate of some nonzero point on the curve. // @dev * All the limbs of s and msg_hash are in the range (-2 ** 210.99, 2 ** 210.99). // @dev * All the limbs of r are in the range (-2 ** 124.99, 2 ** 124.99). - func try_recover_public_key{range_check_ptr}( - msg_hash: BigInt3, r: BigInt3, s: BigInt3, y_parity: felt - ) -> (public_key_point: EcPoint, success: felt) { + func try_recover_public_key{ + range_check_ptr, + range_check96_ptr: felt*, + add_mod_ptr: ModBuiltin*, + mul_mod_ptr: ModBuiltin*, + poseidon_ptr: PoseidonBuiltin*, + }(msg_hash: UInt384, r: UInt384, s: UInt384, y_parity: felt) -> ( + public_key_point: G1Point, success: felt + ) { alloc_locals; - let (local r_point: EcPoint*) = alloc(); - let (is_on_curve) = try_get_point_from_x(x=r, v=y_parity, result=r_point); + let (__fp__, _) = get_fp_and_pc(); + let (local r_point: G1Point*) = alloc(); + let (is_on_curve) = try_get_point_from_x_secp256k1(x=r, v=y_parity, result=r_point); if (is_on_curve == 0) { - return (public_key_point=EcPoint(x=BigInt3(0, 0, 0), y=BigInt3(0, 0, 0)), success=0); + assert 1 = 0; + return ( + public_key_point=G1Point(x=UInt384(0, 0, 0, 0), y=UInt384(0, 0, 0, 0)), success=0 + ); } - let (generator_point: EcPoint) = get_generator_point(); + let (generator_point: G1Point) = get_generator_point(); // The result is given by // -(msg_hash / r) * gen + (s / r) * r_point // where the division by r is modulo N. - let (u1: BigInt3) = div_mod_n(msg_hash, r); - let (u2: BigInt3) = div_mod_n(s, r); + let N = UInt384(secp256k1.N0, secp256k1.N1, secp256k1.N2, secp256k1.N3); + + let (_u1: UInt384) = div_mod_p(msg_hash, r, N); + let (_u1: UInt384) = neg_mod_p(_u1, N); + let (_u2: UInt384) = div_mod_p(s, r, N); + + let (u1) = uint384_to_uint256_mod_p(_u1, N); + let (u2) = uint384_to_uint256_mod_p(_u2, N); + + let (ep1_low, en1_low, sp1_low, sn1_low) = scalar_to_epns(u1.low); + let (ep1_high, en1_high, sp1_high, sn1_high) = scalar_to_epns(u1.high); + + let (ep1_low_384) = felt_to_UInt384(ep1_low); + let (en1_low_384) = felt_to_UInt384(en1_low); + let (sp1_low_384) = sign_to_UInt384_mod_secp256k1(sp1_low); + let (sn1_low_384) = sign_to_UInt384_mod_secp256k1(sn1_low); + + let (ep1_high_384) = felt_to_UInt384(ep1_high); + let (en1_high_384) = felt_to_UInt384(en1_high); + let (sp1_high_384) = sign_to_UInt384_mod_secp256k1(sp1_high); + let (sn1_high_384) = sign_to_UInt384_mod_secp256k1(sn1_high); - let (point1) = ec_mul(generator_point, u1); - // We prefer negating the point over negating the scalar because negating mod SECP_P is - // computationally easier than mod N. - let (minus_point1) = ec_negate(point1); + let (ep2_low, en2_low, sp2_low, sn2_low) = scalar_to_epns(u2.low); - let (point2) = ec_mul([r_point], u2); + let (ep2_low_384) = felt_to_UInt384(ep2_low); + let (en2_low_384) = felt_to_UInt384(en2_low); + let (sp2_low_384) = sign_to_UInt384_mod_secp256k1(sp2_low); + let (sn2_low_384) = sign_to_UInt384_mod_secp256k1(sn2_low); - let (public_key_point) = ec_add(minus_point1, point2); - return (public_key_point=public_key_point, success=1); + let (ep2_high, en2_high, sp2_high, sn2_high) = scalar_to_epns(u2.high); + let (ep2_high_384) = felt_to_UInt384(ep2_high); + let (en2_high_384) = felt_to_UInt384(en2_high); + let (sp2_high_384) = sign_to_UInt384_mod_secp256k1(sp2_high); + let (sn2_high_384) = sign_to_UInt384_mod_secp256k1(sn2_high); + let (local generator_point: G1Point) = get_generator_point(); + + // _hash_inputs_points_scalars_and_result_points + + %{ + from garaga.hints.io import pack_bigint_ptr, pack_felt_ptr, fill_sum_dlog_div, fill_g1_point, bigint_split + from garaga.starknet.tests_and_calldata_generators.msm import MSMCalldataBuilder + from garaga.definitions import G1Point + import time + curve_id = CurveID.SECP256K1 + r_point = (bigint_pack(ids.r_point.x, 4, 2**96), bigint_pack(ids.r_point.y, 4, 2**96)) + points = [G1Point.get_nG(curve_id, 1), G1Point(r_point[0], r_point[1], curve_id)] + scalars = [ids.u1.low + 2**128*ids.u1.high, ids.u2.low + 2**128*ids.u2.high] + builder = MSMCalldataBuilder(curve_id, points, scalars) + (msm_hint, derive_point_from_x_hint) = builder.build_msm_hints() + Q_low, Q_high, Q_high_shifted, RLCSumDlogDiv = msm_hint.elmts + + def fill_elmt_at_index( + x, ptr: object, memory: object, index: int, static_offset: int = 0 + ): + limbs = bigint_split(x, 4, 2**96) + for i in range(4): + memory[ptr + index * 4 + i + static_offset] = limbs[i] + return + + + def fill_elmts_at_index( + x, + ptr: object, + memory: object, + index: int, + static_offset: int = 0, + ): + for i in range(len(x)): + fill_elmt_at_index(x[i], ptr + i * 4, memory, index, static_offset) + return + + rlc_sum_dlog_div_coeffs = RLCSumDlogDiv.a_num + RLCSumDlogDiv.a_den + RLCSumDlogDiv.b_num + RLCSumDlogDiv.b_den + assert len(rlc_sum_dlog_div_coeffs) == 18 + 4*2, f"len(rlc_sum_dlog_div_coeffs) == {len(rlc_sum_dlog_div_coeffs)} != {18 + 4*2}" + + + offset = 4 + fill_elmts_at_index(rlc_sum_dlog_div_coeffs, ids.range_check96_ptr, memory, 4, offset) + + fill_elmt_at_index(Q_low[0], ids.range_check96_ptr, memory, 50, offset) + fill_elmt_at_index(Q_low[1], ids.range_check96_ptr, memory, 51, offset) + fill_elmt_at_index(Q_high[0], ids.range_check96_ptr, memory, 52, offset) + fill_elmt_at_index(Q_high[1], ids.range_check96_ptr, memory, 53, offset) + fill_elmt_at_index(Q_high_shifted[0], ids.range_check96_ptr, memory, 54, offset) + fill_elmt_at_index(Q_high_shifted[1], ids.range_check96_ptr, memory, 55, offset) + %} + + assert poseidon_ptr[0].input = PoseidonBuiltinState(s0='MSM_G1', s1=0, s2=1); + assert poseidon_ptr[1].input = PoseidonBuiltinState( + s0=secp256k1.CURVE_ID + poseidon_ptr[0].output.s0, + s1=2 + poseidon_ptr[0].output.s1, + s2=poseidon_ptr[0].output.s2, + ); + + // tempvar init_s0 = poseidon_ptr[1].output.s0 + 0; + // // %{ print(f"CAIROS0: {hex(ids.init_s0)}") %} + let poseidon_ptr = poseidon_ptr + 2 * PoseidonBuiltin.SIZE; + let (_, _, _) = hash_full_transcript_and_get_Z_3_LIMBS(cast(&generator_point, felt*), 2); + let (_, _, _) = hash_full_transcript_and_get_Z_3_LIMBS(cast(r_point, felt*), 2); + // Q_low, Q_high, Q_high_shifted (filled by prover) (50 - 55). + let (_s0, _s1, _s2) = hash_full_transcript_and_get_Z_3_LIMBS( + cast(range_check96_ptr + 4 + 50 * N_LIMBS, felt*), 3 * 2 + ); + // U1, U2 + assert poseidon_ptr[0].input = PoseidonBuiltinState( + s0=_s0 + u1.low, s1=_s1 + u1.high, s2=_s2 + ); + assert poseidon_ptr[1].input = PoseidonBuiltinState( + s0=poseidon_ptr[0].output.s0 + u2.low, + s1=poseidon_ptr[0].output.s1 + u2.high, + s2=poseidon_ptr[0].output.s2, + ); + + tempvar rlc_coeff = poseidon_ptr[1].output.s1 + 0; + let poseidon_ptr = poseidon_ptr + 2 * PoseidonBuiltin.SIZE; + %{ print(f"CAIRORLC: {hex(ids.rlc_coeff)}") %} + let (rlc_coeff_u384) = felt_to_UInt384(rlc_coeff); + + // Hash sumdlogdiv 2 points : (4-29) + let (_random_x_coord, _, _) = hash_full_transcript_and_get_Z_3_LIMBS( + cast(range_check96_ptr + 4 * N_LIMBS, felt*), 26 + ); + %{ print(f"CAIROX: {hex(ids._random_x_coord)}") %} + + tempvar range_check96_ptr_init = range_check96_ptr; + tempvar range_check96_ptr_after_circuit = range_check96_ptr + 224 + (4 + 117 + 108 - 1) * + N_LIMBS; + + let (random_point: G1Point) = get_point_from_x_secp256k1{ + range_check96_ptr=range_check96_ptr_after_circuit + }(x=_random_x_coord, attempt=0); + + tempvar range_check96_ptr_final = range_check96_ptr_after_circuit; + let range_check96_ptr = range_check96_ptr_init; + + let ecip_input: UInt384* = cast(range_check96_ptr, UInt384*); + // Constants (0-3) + assert ecip_input[0] = UInt384(3, 0, 0, 0); + assert ecip_input[1] = UInt384(0, 0, 0, 0); + assert ecip_input[2] = UInt384(12528508628158887531275213211, 66632300, 0, 0); + assert ecip_input[3] = UInt384(12528508628158887531275213211, 4361599596, 0, 0); + + // RLCSumDlogDiv for 2 points : n_coeffs = 18 + 4 * 2 = 26 (filled by prover) (4-29) + + // Generator point + assert ecip_input[30] = UInt384( + 0x2dce28d959f2815b16f81798, 0x55a06295ce870b07029bfcdb, 0x79be667ef9dcbbac, 0x0 + ); // x_gen + assert ecip_input[31] = UInt384( + 0xa68554199c47d08ffb10d4b8, 0x5da4fbfc0e1108a8fd17b448, 0x483ada7726a3c465, 0x0 + ); // y_gen + // R point + assert ecip_input[32] = r_point.x; + assert ecip_input[33] = r_point.y; + + assert ecip_input[34] = ep1_low_384; + assert ecip_input[35] = en1_low_384; + assert ecip_input[36] = sp1_low_384; + assert ecip_input[37] = sn1_low_384; + + assert ecip_input[38] = ep2_low_384; + assert ecip_input[39] = en2_low_384; + assert ecip_input[40] = sp2_low_384; + assert ecip_input[41] = sn2_low_384; + + assert ecip_input[42] = ep1_high_384; + assert ecip_input[43] = en1_high_384; + assert ecip_input[44] = sp1_high_384; + assert ecip_input[45] = sn1_high_384; + + assert ecip_input[46] = ep2_high_384; + assert ecip_input[47] = en2_high_384; + assert ecip_input[48] = sp2_high_384; + assert ecip_input[49] = sn2_high_384; + + // Q_low / Q_high / Q_high_shifted (filled by prover) (50 - 55). + // ... + // Random point A0 + // let a0:G1Point = G1Point {x: u384{limb0:0x24bbb2e640ceea04c582be56, limb1:0x3194a04768eadeb55fc1ba0a, limb2:0x7b7954ea50caf5a, limb3:0x0}, y: u384{limb0:0x48afd5cdf3ea97eb92138b3c, limb1:0x796f538416c264e0d776e0d, limb2:0x6ef4f09165269157, limb3:0x0}}; + // G1Point{x: u384{limb0:0x7fae4cd63658d585d7d8a264, limb1:0x721fe8c75e82c0be38844e0a, limb2:0x5891e91528037ca, limb3:0x0}, y: u384{limb0:0xa06fe9692227dfdc6dd6b4b5, limb1:0xc4330da0e6a11158bce59b92, limb2:0x524aade87df0f5d7, limb3:0x0}} + + assert ecip_input[56] = random_point.x; + assert ecip_input[57] = random_point.y; + + // a_weirstrass + assert ecip_input[58] = UInt384(secp256k1.A0, secp256k1.A1, secp256k1.A2, secp256k1.A3); + // base_rlc + assert ecip_input[59] = rlc_coeff_u384; + + // let (point1) = ec_mul(generator_point, u1); + // let (minus_point1) = ec_negate(point1); + // let (point2) = ec_mul([r_point], u2); + // let (public_key_point) = ec_add(minus_point1, point2); + // return (public_key_point=public_key_point, success=1); + + let (add_offsets_ptr, mul_offsets_ptr) = get_full_ecip_2P_circuit(); + + let p = UInt384(secp256k1.P0, secp256k1.P1, secp256k1.P2, secp256k1.P3); + + assert add_mod_ptr[0] = ModBuiltin( + p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=add_offsets_ptr, n=117 + ); + assert mul_mod_ptr[0] = ModBuiltin( + p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=mul_offsets_ptr, n=108 + ); + + %{ + from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner + assert builtin_runners["add_mod_builtin"].instance_def.batch_size == 1 + assert builtin_runners["mul_mod_builtin"].instance_def.batch_size == 1 + + ModBuiltinRunner.fill_memory( + memory=memory, + add_mod=(ids.add_mod_ptr.address_, builtin_runners["add_mod_builtin"], 117), + mul_mod=(ids.mul_mod_ptr.address_, builtin_runners["mul_mod_builtin"], 108), + ) + %} + + tempvar range_check96_ptr = range_check96_ptr_final; + let add_mod_ptr = add_mod_ptr + 117 * ModBuiltin.SIZE; + let mul_mod_ptr = mul_mod_ptr + 108 * ModBuiltin.SIZE; + // Add Q_low and Q_high_shifted: + // %{ + // from garaga.hints.io import pack_bigint_array + + // arro = pack_bigint_array(ids.ecip_input, 4, 2**96, 283) + // for i, v in enumerate(arro): + // print(f"{i}: {hex(v)}") + // %} + let (res) = add_ec_points_secp256k1( + G1Point(x=ecip_input[50], y=ecip_input[51]), G1Point(x=ecip_input[54], y=ecip_input[55]) + ); + return (public_key_point=res, success=1); } // @notice Recovers the Ethereum address from a signature. @@ -96,17 +634,25 @@ namespace Signature { // @param y_parity The y parity value of the signature. true if odd, false if even. // @return The Ethereum address. func try_recover_eth_address{ - range_check_ptr, bitwise_ptr: BitwiseBuiltin*, keccak_ptr: KeccakBuiltin* - }(msg_hash: BigInt3, r: BigInt3, s: BigInt3, y_parity: felt) -> (success: felt, address: felt) { + range_check_ptr, + range_check96_ptr: felt*, + add_mod_ptr: ModBuiltin*, + mul_mod_ptr: ModBuiltin*, + bitwise_ptr: BitwiseBuiltin*, + keccak_ptr: KeccakBuiltin*, + poseidon_ptr: PoseidonBuiltin*, + }(msg_hash: UInt384, r: UInt384, s: UInt384, y_parity: felt) -> (success: felt, address: felt) { alloc_locals; let (public_key_point, success) = try_recover_public_key( msg_hash=msg_hash, r=r, s=s, y_parity=y_parity ); if (success == 0) { + assert 1 = 0; return (success=0, address=0); } - let (x_uint256) = bigint_to_uint256(public_key_point.x); - let (y_uint256) = bigint_to_uint256(public_key_point.y); + let modulus = UInt384(secp256k1.P0, secp256k1.P1, secp256k1.P2, secp256k1.P3); + let (x_uint256) = uint384_to_uint256_mod_p(public_key_point.x, modulus); + let (y_uint256) = uint384_to_uint256_mod_p(public_key_point.y, modulus); let address = Internals.public_key_point_to_eth_address(x=x_uint256, y=y_uint256); return (success=success, address=address); } @@ -132,3 +678,70 @@ namespace Internals { return eth_address; } } + +// Add two EC points. Doesn't check if the inputs are on curve nor if they are the point at infinity. +func add_ec_points_secp256k1{ + range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin* +}(P: G1Point, Q: G1Point) -> (res: G1Point) { + alloc_locals; + let (__fp__, _) = get_fp_and_pc(); + let modulus = UInt384(secp256k1.P0, secp256k1.P1, secp256k1.P2, secp256k1.P3); + let (same_x) = is_eq_mod_p(P.x, Q.x, modulus); + + if (same_x != 0) { + let (opposite_y) = is_opposite_mod_p(P.y, Q.y, modulus); + + if (opposite_y != 0) { + // P + (-P) = O (point at infinity) + return (res=G1Point(UInt384(0, 0, 0, 0), UInt384(0, 0, 0, 0))); + } else { + // P = Q, so we need to double the point + let (add_offsets, mul_offsets) = get_DOUBLE_EC_POINT_circuit(); + let input: UInt384* = cast(range_check96_ptr, UInt384*); + assert input[0] = UInt384(3, 0, 0, 0); + assert input[1] = P.x; + assert input[2] = P.y; + assert input[3] = UInt384(secp256k1.A0, secp256k1.A1, secp256k1.A2, secp256k1.A3); + + run_modulo_circuit_basic( + p=modulus, + add_offsets_ptr=add_offsets, + add_n=6, + mul_offsets_ptr=mul_offsets, + mul_n=5, + input_len=4, + n_assert_eq=0, + ); + return ( + res=G1Point( + x=[cast(cast(input, felt*) + 44, UInt384*)], + y=[cast(cast(input, felt*) + 56, UInt384*)], + ), + ); + } + } else { + // P and Q have different x-coordinates, perform regular addition + let (add_offsets, mul_offsets) = get_ADD_EC_POINT_circuit(); + let input: UInt384* = cast(range_check96_ptr, UInt384*); + assert input[0] = P.x; + assert input[1] = P.y; + assert input[2] = Q.x; + assert input[3] = Q.y; + + run_modulo_circuit_basic( + p=modulus, + add_offsets_ptr=add_offsets, + add_n=6, + mul_offsets_ptr=mul_offsets, + mul_n=3, + input_len=4, + n_assert_eq=0, + ); + return ( + res=G1Point( + x=[cast(cast(input, felt*) + 36, UInt384*)], + y=[cast(cast(input, felt*) + 48, UInt384*)], + ), + ); + } +} diff --git a/cairo/src/utils/transaction.cairo b/cairo/src/utils/transaction.cairo index 17490efd..a1437214 100644 --- a/cairo/src/utils/transaction.cairo +++ b/cairo/src/utils/transaction.cairo @@ -1,6 +1,12 @@ from starkware.cairo.common.alloc import alloc from starkware.cairo.common.bool import TRUE, FALSE -from starkware.cairo.common.cairo_builtins import BitwiseBuiltin, HashBuiltin, KeccakBuiltin +from starkware.cairo.common.cairo_builtins import ( + HashBuiltin, + BitwiseBuiltin, + KeccakBuiltin, + PoseidonBuiltin, + ModBuiltin, +) from starkware.cairo.common.math_cmp import is_not_zero, is_nn from starkware.cairo.common.math import assert_not_zero, assert_nn from starkware.cairo.common.memcpy import memcpy @@ -359,6 +365,10 @@ namespace Transaction { pedersen_ptr: HashBuiltin*, bitwise_ptr: BitwiseBuiltin*, range_check_ptr, + range_check96_ptr: felt*, + add_mod_ptr: ModBuiltin*, + mul_mod_ptr: ModBuiltin*, + poseidon_ptr: PoseidonBuiltin*, keccak_ptr: KeccakBuiltin*, }(tx: model.TransactionEncoded*, chain_id: felt) { alloc_locals; diff --git a/cairo/src/utils/uint256.cairo b/cairo/src/utils/uint256.cairo index ec8897e1..9582fc50 100644 --- a/cairo/src/utils/uint256.cairo +++ b/cairo/src/utils/uint256.cairo @@ -8,8 +8,10 @@ from starkware.cairo.common.uint256 import ( uint256_lt, uint256_not, ) +from starkware.cairo.common.cairo_builtins import UInt384 from starkware.cairo.common.bool import FALSE from starkware.cairo.common.math_cmp import is_nn +from ethereum.utils.numeric import divmod from src.utils.maths import unsigned_div_rem @@ -380,6 +382,15 @@ func uint256_to_uint160{range_check_ptr}(x: Uint256) -> felt { return x.low + high * 2 ** 128; } +// @notice Converts a 256-bit unsigned integer to a 384-bit unsigned integer. +// @param a The 256-bit unsigned integer. +// @return res The resulting 384-bit unsigned integer. +func uint256_to_uint384{range_check_ptr}(a: Uint256) -> UInt384 { + let (high_64_high, high_64_low) = divmod(a.high, 2 ** 64); + let (low_32_high, low_96_low) = divmod(a.low, 2 ** 96); + let res = UInt384(low_96_low, low_32_high + 2 ** 32 * high_64_low, high_64_high, 0); + return res; +} // @notice Return true if both integers are equal. // @dev Same as the one from starkware's cairo common library, but without the useless range_check arg func uint256_eq(a: Uint256, b: Uint256) -> (res: felt) { diff --git a/cairo/tests/programs/test_os.py b/cairo/tests/programs/test_os.py index 68030364..f32bd8f0 100644 --- a/cairo/tests/programs/test_os.py +++ b/cairo/tests/programs/test_os.py @@ -278,7 +278,7 @@ def test_create_tx_returndata(self, cairo_run): ) @pytest.mark.slow - @settings(max_examples=1) # for max_examples=2, it takes 1773.25s in local + @settings(deadline=None) @given(nonce=integers(min_value=2**64, max_value=2**248 - 1)) def test_should_raise_when_nonce_is_greater_u64(self, cairo_run, nonce): initial_state = { diff --git a/cairo/tests/src/utils/test_signature.cairo b/cairo/tests/src/utils/test_signature.cairo index 1d0b2051..86e88417 100644 --- a/cairo/tests/src/utils/test_signature.cairo +++ b/cairo/tests/src/utils/test_signature.cairo @@ -1,12 +1,24 @@ from ethereum_types.numeric import U256 -from starkware.cairo.common.cairo_builtins import BitwiseBuiltin, KeccakBuiltin +from starkware.cairo.common.cairo_builtins import ( + BitwiseBuiltin, + KeccakBuiltin, + ModBuiltin, + PoseidonBuiltin, +) from starkware.cairo.common.cairo_secp.bigint import uint256_to_bigint from src.utils.signature import Signature, Internals +from src.utils.uint256 import uint256_eq, uint256_to_uint384 func test__public_key_point_to_eth_address{ - range_check_ptr, bitwise_ptr: BitwiseBuiltin*, keccak_ptr: KeccakBuiltin* + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + keccak_ptr: KeccakBuiltin*, + range_check96_ptr: felt*, + add_mod_ptr: ModBuiltin*, + mul_mod_ptr: ModBuiltin*, + poseidon_ptr: PoseidonBuiltin*, }(x: U256, y: U256) -> felt { let eth_address = Internals.public_key_point_to_eth_address(x=[x.value], y=[y.value]); @@ -14,7 +26,13 @@ func test__public_key_point_to_eth_address{ } func test__verify_eth_signature_uint256{ - range_check_ptr, bitwise_ptr: BitwiseBuiltin*, keccak_ptr: KeccakBuiltin* + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + keccak_ptr: KeccakBuiltin*, + range_check96_ptr: felt*, + add_mod_ptr: ModBuiltin*, + mul_mod_ptr: ModBuiltin*, + poseidon_ptr: PoseidonBuiltin*, }(msg_hash: U256, r: U256, s: U256, y_parity: felt, eth_address: felt) { Signature.verify_eth_signature_uint256( [msg_hash.value], [r.value], [s.value], y_parity, eth_address @@ -23,14 +41,20 @@ func test__verify_eth_signature_uint256{ } func test__try_recover_eth_address{ - range_check_ptr, bitwise_ptr: BitwiseBuiltin*, keccak_ptr: KeccakBuiltin* + range_check_ptr, + bitwise_ptr: BitwiseBuiltin*, + keccak_ptr: KeccakBuiltin*, + range_check96_ptr: felt*, + add_mod_ptr: ModBuiltin*, + mul_mod_ptr: ModBuiltin*, + poseidon_ptr: PoseidonBuiltin*, }(msg_hash: U256, r: U256, s: U256, y_parity: felt) -> (success: felt, address: felt) { - let (msg_hash_bigint) = uint256_to_bigint([msg_hash.value]); - let (r_bigint) = uint256_to_bigint([r.value]); - let (s_bigint) = uint256_to_bigint([s.value]); + let msg_hash_uint384 = uint256_to_uint384([msg_hash.value]); + let r_uint384 = uint256_to_uint384([r.value]); + let s_uint384 = uint256_to_uint384([s.value]); let (success, address) = Signature.try_recover_eth_address( - msg_hash=msg_hash_bigint, r=r_bigint, s=s_bigint, y_parity=y_parity + msg_hash=msg_hash_uint384, r=r_uint384, s=s_uint384, y_parity=y_parity ); return (success=success, address=address); diff --git a/pyproject.toml b/pyproject.toml index ef699118..2575471d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,6 +14,7 @@ dependencies = [ "toml>=0.10.2", "web3>=7.2.0", "xxhash>=3.5.0", + "garaga", ] [tool.uv] @@ -36,6 +37,7 @@ dev-dependencies = [ [tool.uv.sources] ethereum = { git = "https://github.com/kkrt-labs/execution-specs.git", rev = "7d685c83af787e7519f8787563a5e94020700d6e" } +garaga = { git = "https://github.com/keep-starknet-strange/garaga.git", rev = "hydra_upd" } cairo-addons = { workspace = true } [tool.uv.workspace] diff --git a/uv.lock b/uv.lock index 5629866d..e8979047 100644 --- a/uv.lock +++ b/uv.lock @@ -185,6 +185,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f8/ed/e97229a566617f2ae958a6b13e7cc0f585470eac730a73e9e82c32a3cdd2/arrow-1.3.0-py3-none-any.whl", hash = "sha256:c728b120ebc00eb84e01882a6f5e7927a53960aa990ce7dd2b10f39005a67f80", size = 66419 }, ] +[[package]] +name = "asgiref" +version = "3.8.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/29/38/b3395cc9ad1b56d2ddac9970bc8f4141312dbaec28bc7c218b0dfafd0f42/asgiref-3.8.1.tar.gz", hash = "sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590", size = 35186 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/e3/893e8757be2612e6c266d9bb58ad2e3651524b5b40cf56761e985a28b13e/asgiref-3.8.1-py3-none-any.whl", hash = "sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47", size = 23828 }, +] + [[package]] name = "asn1crypto" version = "1.5.1" @@ -606,6 +618,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/99/a9/ce3d5fd9df58da092c90ddc7b214fd313b54d5bc325770c488c8864ad17a/ckzg-2.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0b249914aeaf05cabc71c5c3797e3d6c126cb2c64192b7eb6755ef6aa5ab2f11", size = 98327 }, ] +[[package]] +name = "click" +version = "8.1.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "platform_system == 'Windows'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188 }, +] + [[package]] name = "coincurve" version = "20.0.0" @@ -669,6 +693,58 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e6/75/49e5bfe642f71f272236b5b2d2691cf915a7283cc0ceda56357b61daa538/comm-0.2.2-py3-none-any.whl", hash = "sha256:e6fb86cb70ff661ee8c9c14e7d36d6de3b4066f1441be4063df9c5009f0a64d3", size = 7180 }, ] +[[package]] +name = "crypto-cpp-py" +version = "1.4.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ecdsa" }, + { name = "pywin32", marker = "os_name == 'nt'" }, + { name = "sympy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d6/ca/73848492ea85458512efdb6bdf6b166e7f611f38e14014b13c97dea46818/crypto_cpp_py-1.4.5.tar.gz", hash = "sha256:e82a7143682f23e1b1507d0cfd8a8d7263e2b876a04d29160abb57ca5e66ea81", size = 154634 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/be/91/5a62fc78286a46893882139723d64f505e90eaa344c0876110f269ecf402/crypto_cpp_py-1.4.5-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:31f41a942fb6e90d7adc90deb8a9f6d0d1ad73fa6d4aff4fa8ae85185efb8a4e", size = 259153 }, + { url = "https://files.pythonhosted.org/packages/49/c9/dc17a8c4df29179327d1d98adc78887d47f534464a3c2908387fce759d62/crypto_cpp_py-1.4.5-cp310-cp310-macosx_13_0_universal2.whl", hash = "sha256:39f248661fa9cd152f18d4f499ba03638cd0fd28d911c141f84ecd9f15a3f5b4", size = 256897 }, + { url = "https://files.pythonhosted.org/packages/e4/a1/4730b18c30e5e1a9e7a5ee0977f02eb971fff7b46e788f47f8e8a73ee072/crypto_cpp_py-1.4.5-cp310-cp310-macosx_14_0_universal2.whl", hash = "sha256:876091d6169152cf57a03f2dca3684cecedd7c7c6438a2e1193661c949873dcc", size = 256557 }, + { url = "https://files.pythonhosted.org/packages/0c/b3/0f892591816b259888313eb081dfcba2ec69d12916af60805443e506ab2a/crypto_cpp_py-1.4.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0afc0ef20c00a370265a11d2344f0c97433285ad22a19742d71b90a176c52366", size = 211669 }, + { url = "https://files.pythonhosted.org/packages/30/8f/191f76346d73a7f964d622b4c252586f193a2557c484cc2ca6092c2cd249/crypto_cpp_py-1.4.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2beeebe4d4f6cc1ae93f97e3275f0167efef92e34b75292f720944f4e360e8aa", size = 211300 }, + { url = "https://files.pythonhosted.org/packages/fd/d2/88fffd786e5f667bd24e7be4ed3edcd8fea3802b20ae21af7a042d35dcf0/crypto_cpp_py-1.4.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:53d5cf7ffe4d0260f86d2c2ab7260adb52b73be17c8a26ae647c987ff160683f", size = 151315 }, + { url = "https://files.pythonhosted.org/packages/55/52/efde2dfc25ef3fe2442fdc8d32333d3f85d431afc849481c6ea926d92269/crypto_cpp_py-1.4.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2d59875b1e4b16985e1e0535ed6546d8917c73892e63c1b2221516d3d108b3f", size = 160233 }, + { url = "https://files.pythonhosted.org/packages/5b/82/bcfc9122e4604042d7e595a827d55ac5b56bedefb44c44e941553725cf62/crypto_cpp_py-1.4.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b4a50403728a04f31df6321b5b230360792396a3657e144c738a2ab15969324d", size = 745500 }, + { url = "https://files.pythonhosted.org/packages/d4/5d/69473076106b6b3407ce03ec60cf7224b4acd6d5717538e07576db7770a4/crypto_cpp_py-1.4.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c9701f4cacb0136749993c1ea19f5a9c6fa2c21e7a30e4b37ee1f700e9b5387e", size = 796023 }, + { url = "https://files.pythonhosted.org/packages/c7/3f/63a77e472853a855a1aae50d56ad61d2f571c494d8cb84f4ca29606cb1f6/crypto_cpp_py-1.4.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:2b0769efb08ab277213ced3f95cc120c7c818ec2ef6a4c419027c67428f326a2", size = 753325 }, + { url = "https://files.pythonhosted.org/packages/87/01/1c8d6d4a9f2b35cc7534b9d1b8cb3ebd05a71df268bc26a3e1b1757229ae/crypto_cpp_py-1.4.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4b75fc50c15d0a43135316e95622976aa2ec4cf939e3540f25af69e286110353", size = 712889 }, + { url = "https://files.pythonhosted.org/packages/49/a2/d66e271c5e7165bd0b5923a7dd75a630d83f11d3ae6c9fdb8ed9178a1013/crypto_cpp_py-1.4.5-cp310-cp310-win32.whl", hash = "sha256:b5e7a539047a9d38b55ff0afb66482a73d4c3f16bd79dd18f4b932eb1a0e4606", size = 175821 }, + { url = "https://files.pythonhosted.org/packages/84/39/e4f0620638824d40c722e5fcb3782a2e1756e4916679558afecdab314870/crypto_cpp_py-1.4.5-cp310-cp310-win_amd64.whl", hash = "sha256:78d3eee46cb48f4b1675ed8fdc4c317c07954a52a7bea172a1a38dab933a9a58", size = 175822 }, + { url = "https://files.pythonhosted.org/packages/2b/32/717958ea5c4884652d19c623cef9d35a88e02517b4ec88203e35a453f112/crypto_cpp_py-1.4.5-cp311-cp311-macosx_12_0_universal2.whl", hash = "sha256:8ec48b5fe4afb955954e98469e66db4539475e898d8a8ce45e20c6d83df451a7", size = 259154 }, + { url = "https://files.pythonhosted.org/packages/fb/23/8d9c0664373ea022a56f2ee068b9baac18ddb08a60053120f03fdd8bc952/crypto_cpp_py-1.4.5-cp311-cp311-macosx_13_0_universal2.whl", hash = "sha256:774164e14d7570f4da031f0790f9a7fe364ffe8d8807da24b8ab23f5391188ca", size = 256897 }, + { url = "https://files.pythonhosted.org/packages/80/f1/759c5ee238cf55db1d26c2f49e52e5494883de07aa561dfdaec5af010ce8/crypto_cpp_py-1.4.5-cp311-cp311-macosx_14_0_universal2.whl", hash = "sha256:033e29769174dfc04e54bdae62fea2f2d7ebafd829cddb1d4c1ae10733b38cd5", size = 256557 }, + { url = "https://files.pythonhosted.org/packages/f5/fd/2d249adeefb3ad18b55f2887167a407ce170e4df25c4e54bfb81aa12ee6e/crypto_cpp_py-1.4.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4d6c4a80a7c87d178c0cbb9fe99567f9764ad70e381c32c1057bf944b4c8964", size = 211669 }, + { url = "https://files.pythonhosted.org/packages/6e/fa/f2de5b010fa10ea76bacac4617b6e29d1574e0e61df3edb4a403254e70ce/crypto_cpp_py-1.4.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05eb5af63dca637782ee156b4e9a60313393c8adbeaec327a4139e96d5bf9227", size = 211301 }, + { url = "https://files.pythonhosted.org/packages/eb/a7/5731df36cfde2152f047762a1890b0fdedc0f8aca5c472a9de62b856bef9/crypto_cpp_py-1.4.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3e481b362c2f5af6aa090a150edce0bead36844b32653ea598d44ba288ee37cc", size = 151315 }, + { url = "https://files.pythonhosted.org/packages/68/12/bacf24be6017e3e638ebc6c3ab6f540e06d55289469da48073bee612beab/crypto_cpp_py-1.4.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7489b0667f64fbf33156919769fb2092e30d18e450c23c836ec3aee061d9c285", size = 160233 }, + { url = "https://files.pythonhosted.org/packages/57/e8/57fcbd8963b40d2c3288faa4500eb62901f79a9f3e16f601c53e7743e616/crypto_cpp_py-1.4.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9a3ec8b201174775c47613c667eb5ea73226abb8359004d5b683964e3e4d94f0", size = 745500 }, + { url = "https://files.pythonhosted.org/packages/cf/0d/d5c228c09d0250ec81c51b37c55ccb1a8a23df68c5bec84f9c2f9f594e49/crypto_cpp_py-1.4.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:48a3277b316f4fd94741db83fbd5a0c76fc22b415f80a7f7f3a63b738e4566fa", size = 796024 }, + { url = "https://files.pythonhosted.org/packages/60/62/88c45c0660c6ef0321c1e1dc46687812c9edf92e33fb90790778c934a7a3/crypto_cpp_py-1.4.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:e63b3f09422ac3eb31c52789bef9375d159b1c36636fd577e80af81497e63348", size = 753324 }, + { url = "https://files.pythonhosted.org/packages/f3/1b/262bcd02ee2efa41ea2bb2a3f2023e832660cd9f3e9c20053890bd7ca21c/crypto_cpp_py-1.4.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ef7a290f13c43f6d7dc3a706d3dde70e064dfaf9b45ba21c7079d497f3761758", size = 712891 }, + { url = "https://files.pythonhosted.org/packages/b5/87/3fc27350f9f5f6003afed7c31440641844b50264f5a953ec2f882e20c65d/crypto_cpp_py-1.4.5-cp311-cp311-win32.whl", hash = "sha256:8063143330df10fd6983a96a954bd22532a2eb8a9f3fd19f0b61cb8b622c0fd7", size = 175820 }, + { url = "https://files.pythonhosted.org/packages/e2/87/d955e77fcbe73a26bb4adbc841746e818d5231bcb4b72cd4027bcb73c842/crypto_cpp_py-1.4.5-cp311-cp311-win_amd64.whl", hash = "sha256:8c6de782e6a888b0c9e4d7c9d1b1eb6529c28515ecab26759a1a08e50ac6212a", size = 175824 }, + { url = "https://files.pythonhosted.org/packages/cf/8e/4f10e6456ed92f914011700eb399a9bef4e5e6e5d19022f77ec1819dba89/crypto_cpp_py-1.4.5-cp312-cp312-macosx_12_0_universal2.whl", hash = "sha256:e2575239e76025fb769fd0509a79d0177b7337ba72667e88fa2fac90e407ea88", size = 259151 }, + { url = "https://files.pythonhosted.org/packages/47/0d/762581a5ba797d8475bac030394380e0aac9e991bbeb38af84d4388cf5c9/crypto_cpp_py-1.4.5-cp312-cp312-macosx_13_0_universal2.whl", hash = "sha256:56258116a6ea434a143f643b88fa989a5431216e2a2118956d6f4d2321785759", size = 256897 }, + { url = "https://files.pythonhosted.org/packages/40/86/1d69f2e8bba8e699801a2e84af3ed7eb99aa555846d0ebf93b2e07981639/crypto_cpp_py-1.4.5-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:335be1e18e23ee877c86b6743e30ea2d742f3f8a8df391644ba74f4fa09f7a30", size = 256557 }, + { url = "https://files.pythonhosted.org/packages/d4/79/7371466e219898e9b0e8efca4385fc560e1bf3fd216f30388919d4f6ce27/crypto_cpp_py-1.4.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97319c440b45850663f8369d77da9769c96770762b2e57301081244712e81d3e", size = 211670 }, + { url = "https://files.pythonhosted.org/packages/35/a1/4c334bb554dafc2a138faf2cbc534131fe29d75b7e074274a253a3c2d5e6/crypto_cpp_py-1.4.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2913f709d7667dd0d5bdb023b7a4fcad9a90415a31d73b918c2eb6e88310e16a", size = 211301 }, + { url = "https://files.pythonhosted.org/packages/76/73/5736328a9b20cc9160680eb5d75a843d827f1cee9e98e0de7585c8d3936d/crypto_cpp_py-1.4.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:68072232295aeb315675a120d694c4115850ab2d2c7baebd1376332a1b3dc4af", size = 151313 }, + { url = "https://files.pythonhosted.org/packages/1a/22/46ea9cc61629af9b54c5dfd84f20e885dd6b6c5cd99bd49a7674b29a5205/crypto_cpp_py-1.4.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ebfbd1e31a2b77cdd1b3a00e492f4f76433e307d5c3fd749d80122b5413f5167", size = 160234 }, + { url = "https://files.pythonhosted.org/packages/be/63/f0f55022f31688469d970cc712bee16d84463d1dd4fff1406474c4e1f290/crypto_cpp_py-1.4.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:639c9a5fcca7f73da812d550be5c52829daca9214b61198b1c3dc28f93d1226c", size = 745502 }, + { url = "https://files.pythonhosted.org/packages/e1/87/ec87bf24dae29ef25f7ae3412845e0477085d1e8450b91185ab755cd85f9/crypto_cpp_py-1.4.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:a14770150ef3aef47fa8df84f8a2b873a7d1907552b80933198dd2c7fd9d1846", size = 796024 }, + { url = "https://files.pythonhosted.org/packages/4d/eb/6d488d81b1593d0d020c2baef9eb071dacdd8b2280932e1392131d50ead3/crypto_cpp_py-1.4.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:5155f0e88338a41f3f17ab2b43d08c4a803045a0067442945462240184e836f7", size = 753323 }, + { url = "https://files.pythonhosted.org/packages/b0/ab/a9b3b31eba86a396a2e2c74995cc7503d0cbbf6a66e697cc7b3b9c2036e0/crypto_cpp_py-1.4.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0ff4571e0b98e55d8af184d735e71f0f7b5c5de3849080ae9f34a104af33b008", size = 712890 }, + { url = "https://files.pythonhosted.org/packages/3a/b3/2ec0b373e96fb9844007326be39c46bb58b6559a66dcf202b60540cf95a3/crypto_cpp_py-1.4.5-cp312-cp312-win32.whl", hash = "sha256:5a94bcb49b13ef5976ebba8df678376841d9c0b4da8db8271b8aec829da01f7d", size = 175819 }, + { url = "https://files.pythonhosted.org/packages/54/f2/f846e94a148ada4490b255b7e09ddb2b393d2897b1e50993ed401cc28804/crypto_cpp_py-1.4.5-cp312-cp312-win_amd64.whl", hash = "sha256:0ff107f43a48e30bcd1ce5b5be0b7d1223718261ed4fdb401ad2f0bc3b323320", size = 175823 }, +] + [[package]] name = "cytoolz" version = "1.0.0" @@ -772,14 +848,14 @@ wheels = [ [[package]] name = "ecdsa" -version = "0.19.0" +version = "0.18.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "six" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5e/d0/ec8ac1de7accdcf18cfe468653ef00afd2f609faf67c423efbd02491051b/ecdsa-0.19.0.tar.gz", hash = "sha256:60eaad1199659900dd0af521ed462b793bbdf867432b3948e87416ae4caf6bf8", size = 197791 } +sdist = { url = "https://files.pythonhosted.org/packages/ff/7b/ba6547a76c468a0d22de93e89ae60d9561ec911f59532907e72b0d8bc0f1/ecdsa-0.18.0.tar.gz", hash = "sha256:190348041559e21b22a1d65cee485282ca11a6f81d503fddb84d5017e9ed1e49", size = 197938 } wheels = [ - { url = "https://files.pythonhosted.org/packages/00/e7/ed3243b30d1bec41675b6394a1daae46349dc2b855cb83be846a5a918238/ecdsa-0.19.0-py2.py3-none-any.whl", hash = "sha256:2cea9b88407fdac7bbeca0833b189e4c9c53f2ef1e1eaa29f6224dbc809b707a", size = 149266 }, + { url = "https://files.pythonhosted.org/packages/09/d4/4f05f5d16a4863b30ba96c23b23e942da8889abfa1cdbabf2a0df12a4532/ecdsa-0.18.0-py2.py3-none-any.whl", hash = "sha256:80600258e7ed2f16b9aa1d7c295bd70194109ad5a30fdee0eaeefef1d4c559dd", size = 142915 }, ] [[package]] @@ -1068,6 +1144,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c6/c8/a5be5b7550c10858fcf9b0ea054baccab474da77d37f1e828ce043a3a5d4/frozenlist-1.5.0-py3-none-any.whl", hash = "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3", size = 11901 }, ] +[[package]] +name = "garaga" +version = "0.15.3" +source = { git = "https://github.com/keep-starknet-strange/garaga.git?rev=hydra_upd#15c5962bfd6c45331e7ec5093c7a4642bdebd81a" } +dependencies = [ + { name = "fastecdsa" }, + { name = "pysha3" }, + { name = "python-dotenv" }, + { name = "requests" }, + { name = "starknet-py" }, + { name = "sympy" }, + { name = "typer" }, +] + [[package]] name = "gprof2dot" version = "2024.6.6" @@ -1518,6 +1608,7 @@ dependencies = [ { name = "cairo-addons" }, { name = "cairo-lang" }, { name = "ethereum" }, + { name = "garaga" }, { name = "marshmallow-dataclass" }, { name = "python-dotenv" }, { name = "toml" }, @@ -1548,6 +1639,7 @@ requires-dist = [ { name = "cairo-addons", editable = "python/cairo-addons" }, { name = "cairo-lang", specifier = ">=0.13.2" }, { name = "ethereum", git = "https://github.com/kkrt-labs/execution-specs.git?rev=7d685c83af787e7519f8787563a5e94020700d6e" }, + { name = "garaga", git = "https://github.com/keep-starknet-strange/garaga.git?rev=hydra_upd" }, { name = "marshmallow-dataclass", specifier = ">=8.6.1" }, { name = "python-dotenv", specifier = ">=1.0.1" }, { name = "toml", specifier = ">=0.10.2" }, @@ -1582,6 +1674,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2d/00/d90b10b962b4277f5e64a78b6609968859ff86889f5b898c1a778c06ec00/lark-1.2.2-py3-none-any.whl", hash = "sha256:c2276486b02f0f1b90be155f2c8ba4a8e194d42775786db622faccd652d8e80c", size = 111036 }, ] +[[package]] +name = "markdown-it-py" +version = "3.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdurl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 }, +] + [[package]] name = "markupsafe" version = "3.0.2" @@ -1725,6 +1829,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a4/f5/051413e04f6da25069db5e76759ecdb8cd2a8ab4a94045b5a3bf548c66fa/maturin-1.8.1-py3-none-win_arm64.whl", hash = "sha256:e95f077fd2ddd2f048182880eed458c308571a534be3eb2add4d3dac55bf57f4", size = 6552131 }, ] +[[package]] +name = "mdurl" +version = "0.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 }, +] + [[package]] name = "mistune" version = "3.0.2" @@ -2093,6 +2206,53 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2c/dc/5b3345688bb14cda0ea23f42c96553aa75c4b8a6992f38cac0df6a44ec31/polars-1.18.0-cp39-abi3-win_arm64.whl", hash = "sha256:52b543da52f4f6a661a2fa3cdd4b499938bdb34eeae538ec3bcef6c8c41bfc33", size = 28631561 }, ] +[[package]] +name = "poseidon-py" +version = "0.1.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/f5/54bc701a78a7a502952271b54e8a4b3c9a0d7c70079350f7d49f184b3bf7/poseidon_py-0.1.5.tar.gz", hash = "sha256:acfa0f79176505226dc79c27e1a6a55e1184753920463826101a2f1c2dd2fbf6", size = 138764 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/61/d2/33f2d0c303cb7c07292c07167ae6f3a7b02ccc0093b878bb3b62c82e323c/poseidon_py-0.1.5-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:3a8b4cc09d28439764956c47a00e49aa36c23421f724b0ffbd2c62550325240e", size = 49112 }, + { url = "https://files.pythonhosted.org/packages/fe/bd/b72b889458b6fcfdff153b6ad9e8d2f48c23748964de4d45e8cc3b59ab59/poseidon_py-0.1.5-cp310-cp310-macosx_13_0_universal2.whl", hash = "sha256:a7e611fe04d200eb782a0e7b6f8ee8e34da531a527f96685ff5f12117014fca8", size = 48791 }, + { url = "https://files.pythonhosted.org/packages/b4/ff/b77795035f0ae06b92837f9b5b89342e55af082e4014098ab609a5f7ee60/poseidon_py-0.1.5-cp310-cp310-macosx_14_0_universal2.whl", hash = "sha256:5070cb74a20c433c2a20e91e14f4a92a2f66b8001adaf15ed5febc941d5ea00f", size = 48528 }, + { url = "https://files.pythonhosted.org/packages/75/3d/67d3a2932432c47bf7be1a461be60560aba94db16b2e2d637de412583e78/poseidon_py-0.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15a6c334161ee8444fb908c0c2f9f2a4d14c6a6ace3397bd3b1ed7673244870b", size = 27582 }, + { url = "https://files.pythonhosted.org/packages/c7/52/13e984e61145322f39ae2d6f5822797110f640a53247e3ff54179074ac23/poseidon_py-0.1.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a8899e5ea0ba5d1bd41cc54b337780030d9f68859e94bb124d76a751b124a63", size = 28565 }, + { url = "https://files.pythonhosted.org/packages/9b/bb/c504d0e264524963cfc1b52f16f5f5d3965dbd91412ccc1ff3b7c76304c2/poseidon_py-0.1.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:02c1206449d327ffd8eadca80d7c122d8adfaa529639cf5e5a186fa81cd19977", size = 27517 }, + { url = "https://files.pythonhosted.org/packages/27/73/4ab215e8da10ff81d84ac3d00d8fd2da332d0e23b2f0f506f1d70da06559/poseidon_py-0.1.5-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:755ea18163c156702160c5ede046903c7c2350de806ed92da80e7bae16f61e23", size = 27702 }, + { url = "https://files.pythonhosted.org/packages/1b/01/65757a787dbddde1f9222fe04562ec6815a2e647c4120fac7e72ca22c3a9/poseidon_py-0.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ec16f0c8f74d9de6b2083006e4f408ea77c1b68375a2670a43c04754fff92f05", size = 28168 }, + { url = "https://files.pythonhosted.org/packages/e9/3f/bd4de121917c4475f64e5eef38809b7158e85f7d770d48cbfceb49432c17/poseidon_py-0.1.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:67d31aebd0e00b1f27e27642e086b04951fa2696417a2ef8b5e11f1d86d097f2", size = 29114 }, + { url = "https://files.pythonhosted.org/packages/81/39/257bdf67578555eae98516bd1c603b244dbdac6ffdb25fc94e6d311ae8a1/poseidon_py-0.1.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:c47f68fbe13b9e68a0f0af005b329639f75edcb7c44def9030c0fdf37602ca3e", size = 28175 }, + { url = "https://files.pythonhosted.org/packages/5c/73/9a4cea086ec687efb8dc7d05e573664f1879e53d1a484718c94dbaf153fe/poseidon_py-0.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:14ea566f3e79e59c5d30dfca1f8130953f95cc65aa259424a9c2d37906c63fa5", size = 28273 }, + { url = "https://files.pythonhosted.org/packages/4d/af/fbcb502239bc9350cd4210a3875bb98c84d1b4523c0e7ec46bad51571257/poseidon_py-0.1.5-cp310-cp310-win32.whl", hash = "sha256:618c6af537bf0a2efdaacd5a9d511615d50ee21c31f098b1247f24a5b3542893", size = 39698 }, + { url = "https://files.pythonhosted.org/packages/82/9f/74f4dd34e56a932c72aabf2aabda8d718426d806e984bf1342f5679facfa/poseidon_py-0.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:c6778847c2f6a6a22c8898425adc960ef284d18925780ccd56f53821a66acf4b", size = 39704 }, + { url = "https://files.pythonhosted.org/packages/c9/ff/82febbd624b20ea4fdb051049d2462d8516792132c09bf04009bbdb2e3ce/poseidon_py-0.1.5-cp311-cp311-macosx_12_0_universal2.whl", hash = "sha256:af55e19a30e4c75a63c353e1f616d04e188bf901ddce1df3e8bc4aadaf6769e8", size = 49113 }, + { url = "https://files.pythonhosted.org/packages/63/55/ea23ccc2db97520ea580206f5da0e4c488553db7274b38ff6e022c00224c/poseidon_py-0.1.5-cp311-cp311-macosx_13_0_universal2.whl", hash = "sha256:c1c68d5db997356941433f95808885395f6c2f4132c8a80d6e189881a553d7df", size = 48791 }, + { url = "https://files.pythonhosted.org/packages/2d/72/4c6854c0b9401b32915dc78ec8a26d93c8084b6d0c602c6fe2bdbb728fe1/poseidon_py-0.1.5-cp311-cp311-macosx_14_0_universal2.whl", hash = "sha256:eead4b7b489e66747e6ff8bb73ef0ace3ae8a15e0622ff0b9415e0cf9d2e6c1c", size = 48527 }, + { url = "https://files.pythonhosted.org/packages/37/7f/67e949eaafcf91970f8479390eca3df3f364f9b7567fc060d83571e80150/poseidon_py-0.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2efb15008ed0dad41777ffe427432107140313c77c764965612d4e4a6a426925", size = 27581 }, + { url = "https://files.pythonhosted.org/packages/5f/f0/33dc591a3b895dc5a537c54da8e57714677e31c25ae9feda2c49f708a0a9/poseidon_py-0.1.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b218cd61003175791cd1d168559b4aa12cbe9fba2b630e34431d653227c6da05", size = 28566 }, + { url = "https://files.pythonhosted.org/packages/bc/f9/e8f5e1ee4494412c448fb42263cbbb14eea0e138db5dac2235b55c7a25bb/poseidon_py-0.1.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57e67d2dfabab2085e8f30353c4c19eb53b02cd858ca138cb3aa32a03c34e673", size = 27517 }, + { url = "https://files.pythonhosted.org/packages/d6/28/d701aa6a35932505478d56976d48d8d4d43b337a839f59590f4042c425b0/poseidon_py-0.1.5-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fcde98980879d4d145f25c51c06284564a255cbbd6726a1874712474a8b04137", size = 27702 }, + { url = "https://files.pythonhosted.org/packages/36/ec/81564318cfd177b01af321b70905b4182416a3f280c44fb62b3f383af6c4/poseidon_py-0.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:aaa220a9a28246f3b76353697322b6588052d38e7ecaf18337eecaa6cfa7e6d2", size = 28169 }, + { url = "https://files.pythonhosted.org/packages/43/a9/35743480fc29ba66c8a9b2b6a1741a389ce77382cb7192e05ba422829a8d/poseidon_py-0.1.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:b1750a301b426e3f6ca805672752860e81cf4f6cc2b3e6cd6816d4da78f2dd46", size = 29112 }, + { url = "https://files.pythonhosted.org/packages/f6/c3/1921cac04ffb35ea9c81c1a590b808b82214c9a37091459cf3df61041a31/poseidon_py-0.1.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:1ffe57ffacab103c37606b70eda7dd97c857b3d462a7926038123b05be5ba457", size = 28175 }, + { url = "https://files.pythonhosted.org/packages/84/2b/3ef37e366c9309c7a98eac43dc4a3cfec89fd79170a68dc87e5dd002cd38/poseidon_py-0.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4faeb29252770e10a08c4d6aa2a095c171668640f21d5721441f5015ab1dbc4c", size = 28272 }, + { url = "https://files.pythonhosted.org/packages/e8/08/ee7fd5cfb746b0813f8fe2cb828eb0a3b6665c7fb9527de0fafbafe08bf5/poseidon_py-0.1.5-cp311-cp311-win32.whl", hash = "sha256:df84226f66078d1aca460db3590b65400fcc1aa593c205baba96c0d25b80b39d", size = 39699 }, + { url = "https://files.pythonhosted.org/packages/82/ff/01ef7d2e69134dbbbdfa9e07cb3d5bc351287fa707941cae129d7bf677f6/poseidon_py-0.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:b520591c30af7f0be29ea88404b931eecee8babe0d734e7446aed3e164f8ef83", size = 39705 }, + { url = "https://files.pythonhosted.org/packages/df/37/decd4ef25e831ddea898f5257161df046264dfea2040a9e4ae6c399c82cc/poseidon_py-0.1.5-cp312-cp312-macosx_12_0_universal2.whl", hash = "sha256:4f2d28448e5b0bea2622ca23667de8a27b1a6056068181c5a41e78be65f0d980", size = 49111 }, + { url = "https://files.pythonhosted.org/packages/88/7c/fa0627b5bbc2eaebdb10ddda38bc60f3ca13b184d06d4b2602e6214adecc/poseidon_py-0.1.5-cp312-cp312-macosx_13_0_universal2.whl", hash = "sha256:311291b8caa39f7ebeb3c837f239a46e8214d30722f9e01ded62d79c0b061b8a", size = 48792 }, + { url = "https://files.pythonhosted.org/packages/ca/6e/f17dfcc3c980ff45cc714cf69af99ffda6a1b6ab14879d0bd3cf16458012/poseidon_py-0.1.5-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:06c07b1e2ad273d50b243121b1e94b28bf893bd4942fe1808f98d33cd2de2790", size = 48527 }, + { url = "https://files.pythonhosted.org/packages/9a/f2/36e0dd8a11537a18ff6baca1ac1740baeafae9bc5a47f2fb6dcfe7b6c307/poseidon_py-0.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55501c7c881eaf406568db70a16c56c5f92c325eda65f9f741e75ec5cced7ad6", size = 27582 }, + { url = "https://files.pythonhosted.org/packages/02/c4/a9eee31ee95a840d34b38e984d3e72569e3f994eefd943e334bb75f4910a/poseidon_py-0.1.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cbd1ed7d8567e057cc181542aff18dc0b11cf2c67593243830cc2fedb73b112f", size = 28565 }, + { url = "https://files.pythonhosted.org/packages/65/f1/b652421d4d6e6ab8cce3ece95a903a0598bae6d34ed088242cbea1f9a3e4/poseidon_py-0.1.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:19ae4ddd2b1d05d1ed2e3b38e58c3ac5940a46001b080d5112ce346be4d09681", size = 27517 }, + { url = "https://files.pythonhosted.org/packages/20/b7/fedcc8358630276b33d4b0bac31c6b46563a5aa147f4ba378cef69c4e702/poseidon_py-0.1.5-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1ba4956c6b886457d43e43a4465aed18f9bd1f23e7bd2c5388c9a74ae8f0842", size = 27702 }, + { url = "https://files.pythonhosted.org/packages/8a/08/d30e45d20bb1c341e25f4e3b0237649d95ceb9089fcf808b5cbdf45870e5/poseidon_py-0.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3e4e76745181fb50c77813b1c7c845f92f2d3b4620bf784f43e01be5713e1c14", size = 28170 }, + { url = "https://files.pythonhosted.org/packages/9d/09/b1a5a7e4334fb66649ded00a3d265a99c4fe9a7d79fc530857d84f1921ba/poseidon_py-0.1.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:28c0f134533b827eb0bc883347ec38dca2a5559fb277aeeb4ac9cce7f6d30a16", size = 29112 }, + { url = "https://files.pythonhosted.org/packages/7a/33/a64ab8c3fff9122a0789ab724530db2869245abfe63630103256186eb55d/poseidon_py-0.1.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:7bc3995f771b7d98f05b200c2c19c1ae6238bb9f625733042a6df9633219e762", size = 28173 }, + { url = "https://files.pythonhosted.org/packages/0b/53/d9320624ec201cea53d7cca6089d6a1191b765ab847e2b0dba929c716081/poseidon_py-0.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f09faa440ff5f10099a3e667bb5f8781d27a7bc719f45119d08d12574a4d9281", size = 28272 }, + { url = "https://files.pythonhosted.org/packages/bc/fa/9a001511ffd2c00d37d280d54262ee437a3484de8b7f350f41961c0b9a8e/poseidon_py-0.1.5-cp312-cp312-win32.whl", hash = "sha256:4a7fad5110fc64125ef8fbbdc1d49798159b568e239dbef18ada8fd87eed1fc9", size = 39699 }, + { url = "https://files.pythonhosted.org/packages/c6/75/31ffe6e288943d97834ef2bdffa24988087b0bce02c91e945b7bd5df11e9/poseidon_py-0.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:0261221c68c36fd11cfcb91e5074953bfbe7a33031d806d3ab2dc5c7c1e70a2b", size = 39703 }, +] + [[package]] name = "prometheus-client" version = "0.21.1" @@ -2409,6 +2569,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/dd/36/a6a44b5162a9d102b085ef7107299be766868679ab2c974a4888823c8a0f/pyinstrument-5.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:2478d2c55f77ad8e281e67b0dfe7c2176304bb824c307e86e11890f5e68d7feb", size = 122766 }, ] +[[package]] +name = "pysha3" +version = "1.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/73/bf/978d424ac6c9076d73b8fdc8ab8ad46f98af0c34669d736b1d83c758afee/pysha3-1.0.2.tar.gz", hash = "sha256:fe988e73f2ce6d947220624f04d467faf05f1bbdbc64b0a201296bb3af92739e", size = 829192 } + [[package]] name = "pytest" version = "8.3.4" @@ -2506,21 +2672,17 @@ wheels = [ [[package]] name = "pywin32" -version = "308" +version = "306" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/72/a6/3e9f2c474895c1bb61b11fa9640be00067b5c5b363c501ee9c3fa53aec01/pywin32-308-cp310-cp310-win32.whl", hash = "sha256:796ff4426437896550d2981b9c2ac0ffd75238ad9ea2d3bfa67a1abd546d262e", size = 5927028 }, - { url = "https://files.pythonhosted.org/packages/d9/b4/84e2463422f869b4b718f79eb7530a4c1693e96b8a4e5e968de38be4d2ba/pywin32-308-cp310-cp310-win_amd64.whl", hash = "sha256:4fc888c59b3c0bef905ce7eb7e2106a07712015ea1c8234b703a088d46110e8e", size = 6558484 }, - { url = "https://files.pythonhosted.org/packages/9f/8f/fb84ab789713f7c6feacaa08dad3ec8105b88ade8d1c4f0f0dfcaaa017d6/pywin32-308-cp310-cp310-win_arm64.whl", hash = "sha256:a5ab5381813b40f264fa3495b98af850098f814a25a63589a8e9eb12560f450c", size = 7971454 }, - { url = "https://files.pythonhosted.org/packages/eb/e2/02652007469263fe1466e98439831d65d4ca80ea1a2df29abecedf7e47b7/pywin32-308-cp311-cp311-win32.whl", hash = "sha256:5d8c8015b24a7d6855b1550d8e660d8daa09983c80e5daf89a273e5c6fb5095a", size = 5928156 }, - { url = "https://files.pythonhosted.org/packages/48/ef/f4fb45e2196bc7ffe09cad0542d9aff66b0e33f6c0954b43e49c33cad7bd/pywin32-308-cp311-cp311-win_amd64.whl", hash = "sha256:575621b90f0dc2695fec346b2d6302faebd4f0f45c05ea29404cefe35d89442b", size = 6559559 }, - { url = "https://files.pythonhosted.org/packages/79/ef/68bb6aa865c5c9b11a35771329e95917b5559845bd75b65549407f9fc6b4/pywin32-308-cp311-cp311-win_arm64.whl", hash = "sha256:100a5442b7332070983c4cd03f2e906a5648a5104b8a7f50175f7906efd16bb6", size = 7972495 }, - { url = "https://files.pythonhosted.org/packages/00/7c/d00d6bdd96de4344e06c4afbf218bc86b54436a94c01c71a8701f613aa56/pywin32-308-cp312-cp312-win32.whl", hash = "sha256:587f3e19696f4bf96fde9d8a57cec74a57021ad5f204c9e627e15c33ff568897", size = 5939729 }, - { url = "https://files.pythonhosted.org/packages/21/27/0c8811fbc3ca188f93b5354e7c286eb91f80a53afa4e11007ef661afa746/pywin32-308-cp312-cp312-win_amd64.whl", hash = "sha256:00b3e11ef09ede56c6a43c71f2d31857cf7c54b0ab6e78ac659497abd2834f47", size = 6543015 }, - { url = "https://files.pythonhosted.org/packages/9d/0f/d40f8373608caed2255781a3ad9a51d03a594a1248cd632d6a298daca693/pywin32-308-cp312-cp312-win_arm64.whl", hash = "sha256:9b4de86c8d909aed15b7011182c8cab38c8850de36e6afb1f0db22b8959e3091", size = 7976033 }, - { url = "https://files.pythonhosted.org/packages/a9/a4/aa562d8935e3df5e49c161b427a3a2efad2ed4e9cf81c3de636f1fdddfd0/pywin32-308-cp313-cp313-win32.whl", hash = "sha256:1c44539a37a5b7b21d02ab34e6a4d314e0788f1690d65b48e9b0b89f31abbbed", size = 5938579 }, - { url = "https://files.pythonhosted.org/packages/c7/50/b0efb8bb66210da67a53ab95fd7a98826a97ee21f1d22949863e6d588b22/pywin32-308-cp313-cp313-win_amd64.whl", hash = "sha256:fd380990e792eaf6827fcb7e187b2b4b1cede0585e3d0c9e84201ec27b9905e4", size = 6542056 }, - { url = "https://files.pythonhosted.org/packages/26/df/2b63e3e4f2df0224f8aaf6d131f54fe4e8c96400eb9df563e2aae2e1a1f9/pywin32-308-cp313-cp313-win_arm64.whl", hash = "sha256:ef313c46d4c18dfb82a2431e3051ac8f112ccee1a34f29c263c583c568db63cd", size = 7974986 }, + { url = "https://files.pythonhosted.org/packages/08/dc/28c668097edfaf4eac4617ef7adf081b9cf50d254672fcf399a70f5efc41/pywin32-306-cp310-cp310-win32.whl", hash = "sha256:06d3420a5155ba65f0b72f2699b5bacf3109f36acbe8923765c22938a69dfc8d", size = 8506422 }, + { url = "https://files.pythonhosted.org/packages/d3/d6/891894edec688e72c2e308b3243fad98b4066e1839fd2fe78f04129a9d31/pywin32-306-cp310-cp310-win_amd64.whl", hash = "sha256:84f4471dbca1887ea3803d8848a1616429ac94a4a8d05f4bc9c5dcfd42ca99c8", size = 9226392 }, + { url = "https://files.pythonhosted.org/packages/8b/1e/fc18ad83ca553e01b97aa8393ff10e33c1fb57801db05488b83282ee9913/pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407", size = 8507689 }, + { url = "https://files.pythonhosted.org/packages/7e/9e/ad6b1ae2a5ad1066dc509350e0fbf74d8d50251a51e420a2a8feaa0cecbd/pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e", size = 9227547 }, + { url = "https://files.pythonhosted.org/packages/91/20/f744bff1da8f43388498503634378dbbefbe493e65675f2cc52f7185c2c2/pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a", size = 10388324 }, + { url = "https://files.pythonhosted.org/packages/14/91/17e016d5923e178346aabda3dfec6629d1a26efe587d19667542105cf0a6/pywin32-306-cp312-cp312-win32.whl", hash = "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b", size = 8507705 }, + { url = "https://files.pythonhosted.org/packages/83/1c/25b79fc3ec99b19b0a0730cc47356f7e2959863bf9f3cd314332bddb4f68/pywin32-306-cp312-cp312-win_amd64.whl", hash = "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e", size = 9227429 }, + { url = "https://files.pythonhosted.org/packages/1c/43/e3444dc9a12f8365d9603c2145d16bf0a2f8180f343cf87be47f5579e547/pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040", size = 10388145 }, ] [[package]] @@ -2770,6 +2932,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9e/51/17023c0f8f1869d8806b979a2bffa3f861f26a3f1a66b094288323fba52f/rfc3986_validator-0.1.1-py2.py3-none-any.whl", hash = "sha256:2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9", size = 4242 }, ] +[[package]] +name = "rich" +version = "13.9.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, + { name = "pygments" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", size = 223149 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424 }, +] + [[package]] name = "rlp" version = "4.0.1" @@ -2885,6 +3061,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/55/21/47d163f615df1d30c094f6c8bbb353619274edccf0327b185cc2493c2c33/setuptools-75.6.0-py3-none-any.whl", hash = "sha256:ce74b49e8f7110f9bf04883b730f4765b774ef3ef28f722cce7c273d253aaf7d", size = 1224032 }, ] +[[package]] +name = "shellingham" +version = "1.5.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755 }, +] + [[package]] name = "six" version = "1.17.0" @@ -2947,16 +3132,35 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521 }, ] +[[package]] +name = "starknet-py" +version = "0.24.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp" }, + { name = "asgiref" }, + { name = "crypto-cpp-py" }, + { name = "eth-keyfile" }, + { name = "lark" }, + { name = "marshmallow" }, + { name = "marshmallow-dataclass" }, + { name = "marshmallow-oneofschema" }, + { name = "poseidon-py" }, + { name = "pycryptodome" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7d/bb/54300a5a710a19fb1bef7ba4d93ca04e05498612f363671e38b2b4c21ff7/starknet_py-0.24.3.tar.gz", hash = "sha256:c27b0d8953cf18071086e4438b688f61ad0a2fa0bf6778cff241a4001aac043a", size = 97727 } + [[package]] name = "sympy" -version = "1.13.3" +version = "1.12.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mpmath" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/11/8a/5a7fd6284fa8caac23a26c9ddf9c30485a48169344b4bd3b0f02fef1890f/sympy-1.13.3.tar.gz", hash = "sha256:b27fd2c6530e0ab39e275fc9b683895367e51d5da91baa8d3d64db2565fec4d9", size = 7533196 } +sdist = { url = "https://files.pythonhosted.org/packages/41/8a/0d1bbd33cd3091c913d298746e56f40586fa954788f51b816c6336424675/sympy-1.12.1.tar.gz", hash = "sha256:2877b03f998cd8c08f07cd0de5b767119cd3ef40d09f41c30d722f6686b0fb88", size = 6722359 } wheels = [ - { url = "https://files.pythonhosted.org/packages/99/ff/c87e0622b1dadea79d2fb0b25ade9ed98954c9033722eb707053d310d4f3/sympy-1.13.3-py3-none-any.whl", hash = "sha256:54612cf55a62755ee71824ce692986f23c88ffa77207b30c1368eda4a7060f73", size = 6189483 }, + { url = "https://files.pythonhosted.org/packages/61/53/e18c8c97d0b2724d85c9830477e3ebea3acf1dcdc6deb344d5d9c93a9946/sympy-1.12.1-py3-none-any.whl", hash = "sha256:9b2cbc7f1a640289430e13d2a56f02f867a1da0190f2f99d8968c2f74da0e515", size = 5743129 }, ] [[package]] @@ -3078,6 +3282,21 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9a/bb/d43e5c75054e53efce310e79d63df0ac3f25e34c926be5dffb7d283fb2a8/typeguard-2.13.3-py3-none-any.whl", hash = "sha256:5e3e3be01e887e7eafae5af63d1f36c849aaa94e3a0112097312aabfa16284f1", size = 17605 }, ] +[[package]] +name = "typer" +version = "0.15.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "rich" }, + { name = "shellingham" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cb/ce/dca7b219718afd37a0068f4f2530a727c2b74a8b6e8e0c0080a4c0de4fcd/typer-0.15.1.tar.gz", hash = "sha256:a0588c0a7fa68a1978a069818657778f86abe6ff5ea6abf472f940a08bfe4f0a", size = 99789 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d0/cc/0a838ba5ca64dc832aa43f727bd586309846b0ffb2ce52422543e6075e8a/typer-0.15.1-py3-none-any.whl", hash = "sha256:7994fb7b8155b64d3402518560648446072864beefd44aa2dc36972a5972e847", size = 44908 }, +] + [[package]] name = "types-python-dateutil" version = "2.9.0.20241206" From 9933512028c3297c05ed6b812b3d7eaf59e59c7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Walter?= Date: Tue, 21 Jan 2025 06:39:10 +0100 Subject: [PATCH 02/17] Update signature of sign_to_uint384_mod_secp256k1 --- cairo/src/utils/signature.cairo | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/cairo/src/utils/signature.cairo b/cairo/src/utils/signature.cairo index b32497a4..04d8df3f 100644 --- a/cairo/src/utils/signature.cairo +++ b/cairo/src/utils/signature.cairo @@ -86,11 +86,15 @@ func get_generator_point() -> (point: G1Point) { } @known_ap_change -func sign_to_UInt384_mod_secp256k1(sign: felt) -> (res: UInt384) { +func sign_to_uint384_mod_secp256k1(sign: felt) -> UInt384 { if (sign == -1) { - return (res=UInt384(secp256k1.MIN_ONE_D0, secp256k1.MIN_ONE_D1, secp256k1.MIN_ONE_D2, 0)); + let res = UInt384( + secp256k1.MIN_ONE_D0, secp256k1.MIN_ONE_D1, secp256k1.MIN_ONE_D2, secp256k1.MIN_ONE_D3 + ); + return res; } else { - return (res=UInt384(1, 0, 0, 0)); + let res = UInt384(1, 0, 0, 0); + return res; } } @@ -405,26 +409,26 @@ namespace Signature { let (ep1_low_384) = felt_to_UInt384(ep1_low); let (en1_low_384) = felt_to_UInt384(en1_low); - let (sp1_low_384) = sign_to_UInt384_mod_secp256k1(sp1_low); - let (sn1_low_384) = sign_to_UInt384_mod_secp256k1(sn1_low); + let sp1_low_384 = sign_to_uint384_mod_secp256k1(sp1_low); + let sn1_low_384 = sign_to_uint384_mod_secp256k1(sn1_low); let (ep1_high_384) = felt_to_UInt384(ep1_high); let (en1_high_384) = felt_to_UInt384(en1_high); - let (sp1_high_384) = sign_to_UInt384_mod_secp256k1(sp1_high); - let (sn1_high_384) = sign_to_UInt384_mod_secp256k1(sn1_high); + let sp1_high_384 = sign_to_uint384_mod_secp256k1(sp1_high); + let sn1_high_384 = sign_to_uint384_mod_secp256k1(sn1_high); let (ep2_low, en2_low, sp2_low, sn2_low) = scalar_to_epns(u2.low); let (ep2_low_384) = felt_to_UInt384(ep2_low); let (en2_low_384) = felt_to_UInt384(en2_low); - let (sp2_low_384) = sign_to_UInt384_mod_secp256k1(sp2_low); - let (sn2_low_384) = sign_to_UInt384_mod_secp256k1(sn2_low); + let sp2_low_384 = sign_to_uint384_mod_secp256k1(sp2_low); + let sn2_low_384 = sign_to_uint384_mod_secp256k1(sn2_low); let (ep2_high, en2_high, sp2_high, sn2_high) = scalar_to_epns(u2.high); let (ep2_high_384) = felt_to_UInt384(ep2_high); let (en2_high_384) = felt_to_UInt384(en2_high); - let (sp2_high_384) = sign_to_UInt384_mod_secp256k1(sp2_high); - let (sn2_high_384) = sign_to_UInt384_mod_secp256k1(sn2_high); + let sp2_high_384 = sign_to_uint384_mod_secp256k1(sp2_high); + let sn2_high_384 = sign_to_uint384_mod_secp256k1(sn2_high); let (local generator_point: G1Point) = get_generator_point(); // _hash_inputs_points_scalars_and_result_points From 582111d61a92fa4ad05db28b9071a6850f84d317 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Walter?= Date: Tue, 21 Jan 2025 09:57:09 +0100 Subject: [PATCH 03/17] Remve dead code and start splitting uint384 utils --- cairo/src/precompiles/ec_recover.cairo | 3 +- cairo/src/utils/circuit_basic_field_ops.cairo | 115 ++++-------------- cairo/src/utils/signature.cairo | 62 +++------- cairo/src/utils/uint256.cairo | 20 +-- cairo/src/utils/uint384.cairo | 44 +++++++ cairo/tests/src/utils/test_signature.cairo | 3 +- 6 files changed, 97 insertions(+), 150 deletions(-) create mode 100644 cairo/src/utils/uint384.cairo diff --git a/cairo/src/precompiles/ec_recover.cairo b/cairo/src/precompiles/ec_recover.cairo index 4f9998bd..bd891379 100644 --- a/cairo/src/precompiles/ec_recover.cairo +++ b/cairo/src/precompiles/ec_recover.cairo @@ -17,7 +17,8 @@ from starkware.cairo.common.cairo_secp.bigint import bigint_to_uint256, uint256_ from starkware.cairo.common.memset import memset from src.errors import Errors -from src.utils.uint256 import uint256_eq, uint256_to_uint384 +from src.utils.uint256 import uint256_eq +from src.utils.uint384 import uint256_to_uint384 from src.utils.utils import Helpers from src.utils.array import slice from src.utils.signature import Signature diff --git a/cairo/src/utils/circuit_basic_field_ops.cairo b/cairo/src/utils/circuit_basic_field_ops.cairo index dd3ed73d..0f19e3e7 100644 --- a/cairo/src/utils/circuit_basic_field_ops.cairo +++ b/cairo/src/utils/circuit_basic_field_ops.cairo @@ -1,77 +1,6 @@ from starkware.cairo.common.cairo_builtins import UInt384 from starkware.cairo.common.cairo_builtins import ModBuiltin from starkware.cairo.common.registers import get_fp_and_pc -from ethereum.utils.numeric import divmod - -const POW_2_32 = 2 ** 32; -const POW_2_64 = 2 ** 64; -const POW_2_96 = 2 ** 96; - -// Compute u512 mod p, where u512 = high * 2^256 + low -// Each high/low limb is 32 bits big and passed in BE -func u512_mod_p{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin*}( - low: (v0: felt, v1: felt, v2: felt, v3: felt, v4: felt, v5: felt, v6: felt, v7: felt), - high: (v0: felt, v1: felt, v2: felt, v3: felt, v4: felt, v5: felt, v6: felt, v7: felt), - p: UInt384, -) -> (result: UInt384) { - let (_, pc) = get_fp_and_pc(); - - pc_labelx: - let add_offsets_ptr = pc + (add_offsets - pc_labelx); - let mul_offsets_ptr = pc + (mul_offsets - pc_labelx); - - // High limbs. - assert [range_check96_ptr] = high.v7 + high.v6 * POW_2_32 + high.v5 * POW_2_64; - assert [range_check96_ptr + 1] = high.v4 + high.v3 * POW_2_32 + high.v2 * POW_2_64; - assert [range_check96_ptr + 2] = high.v1 + high.v0 * POW_2_32; - assert [range_check96_ptr + 3] = 0; - - // Shift Limbs. - assert [range_check96_ptr + 4] = 0; - assert [range_check96_ptr + 5] = 0; - assert [range_check96_ptr + 6] = 0x10000000000000000; - assert [range_check96_ptr + 7] = 0; - - // Low limbs. - assert [range_check96_ptr + 8] = low.v7 + low.v6 * POW_2_32 + low.v5 * POW_2_64; - assert [range_check96_ptr + 9] = low.v4 + low.v3 * POW_2_32 + low.v2 * POW_2_64; - assert [range_check96_ptr + 10] = low.v1 + low.v0 * POW_2_32; - assert [range_check96_ptr + 11] = 0; - - assert add_mod_ptr[0] = ModBuiltin( - p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=add_offsets_ptr, n=1 - ); - assert mul_mod_ptr[0] = ModBuiltin( - p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=mul_offsets_ptr, n=1 - ); - %{ - from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner - assert builtin_runners["add_mod_builtin"].instance_def.batch_size == 1 - assert builtin_runners["mul_mod_builtin"].instance_def.batch_size == 1 - - ModBuiltinRunner.fill_memory( - memory=memory, - add_mod=(ids.add_mod_ptr.address_, builtin_runners["add_mod_builtin"], 1), - mul_mod=(ids.mul_mod_ptr.address_, builtin_runners["mul_mod_builtin"], 1), - ) - %} - let range_check96_ptr = range_check96_ptr + 20; - let add_mod_ptr = add_mod_ptr + ModBuiltin.SIZE; - let mul_mod_ptr = mul_mod_ptr + ModBuiltin.SIZE; - return (result=[cast(range_check96_ptr - 4, UInt384*)]); - - mul_offsets: - // Compute High * Shift - dw 0; // [High] - dw 4; // [Shift] - dw 12; // [High * Shift] - - // Computes [Low + High * Shift] - add_offsets: - dw 8; // Low - dw 12; // [High * Shift] - dw 16; // [Low + High * Shift] -} // Compute X + Y mod p. func add_mod_p{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*}( @@ -79,8 +8,8 @@ func add_mod_p{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*}( ) -> (x_plus_y: UInt384) { let (_, pc) = get_fp_and_pc(); - pc_labelx: - let add_offsets_ptr = pc + (add_offsets - pc_labelx); + pc_label: + let add_offsets_ptr = pc + (add_offsets - pc_label); // X limbs (offset 0) assert [range_check96_ptr] = x.d0; @@ -124,8 +53,8 @@ func sub_mod_p{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*}( ) -> (x_minus_y: UInt384) { let (_, pc) = get_fp_and_pc(); - pc_labelx: - let add_offsets_ptr = pc + (add_offsets - pc_labelx); + pc_label: + let add_offsets_ptr = pc + (add_offsets - pc_label); // X limbs (offset 0) assert [range_check96_ptr] = x.d0; @@ -171,8 +100,8 @@ func neg_mod_p{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*}(y: UInt384, p ) { let (_, pc) = get_fp_and_pc(); - pc_labelx: - let add_offsets_ptr = pc + (add_offsets - pc_labelx); + pc_label: + let add_offsets_ptr = pc + (add_offsets - pc_label); // X limbs (offset 0) assert [range_check96_ptr] = 0; @@ -218,8 +147,8 @@ func div_mod_p{range_check96_ptr: felt*, mul_mod_ptr: ModBuiltin*}( ) -> (x_div_y: UInt384) { let (_, pc) = get_fp_and_pc(); - pc_labelx: - let mul_offsets_ptr = pc + (mul_offsets - pc_labelx); + pc_label: + let mul_offsets_ptr = pc + (mul_offsets - pc_label); // X limbs (offset 0) assert [range_check96_ptr] = x.d0; @@ -263,8 +192,8 @@ func div_mod_p{range_check96_ptr: felt*, mul_mod_ptr: ModBuiltin*}( func assert_zero_mod_P{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*}(x: UInt384, p: UInt384) { let (_, pc) = get_fp_and_pc(); - pc_labelx: - let add_offsets_ptr = pc + (add_offsets - pc_labelx); + pc_label: + let add_offsets_ptr = pc + (add_offsets - pc_label); // Const 0. assert [range_check96_ptr] = 0; @@ -308,8 +237,8 @@ func assert_not_zero_mod_P{range_check96_ptr: felt*, mul_mod_ptr: ModBuiltin*}( ) { let (_, pc) = get_fp_and_pc(); - pc_labelx: - let mul_offsets_ptr = pc + (mul_offsets - pc_labelx); + pc_label: + let mul_offsets_ptr = pc + (mul_offsets - pc_label); // Const 1. (offset 0) assert [range_check96_ptr] = 1; @@ -391,8 +320,8 @@ func assert_eq_mod_p{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*}( ) { let (_, pc) = get_fp_and_pc(); - pc_labelx: - let add_offsets_ptr = pc + (add_offsets - pc_labelx); + pc_label: + let add_offsets_ptr = pc + (add_offsets - pc_label); // Const 0. (offset 0) assert [range_check96_ptr] = 0; @@ -448,9 +377,9 @@ func assert_neq_mod_p{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mo ) { let (_, pc) = get_fp_and_pc(); - pc_labelx: - let add_offsets_ptr = pc + (add_offsets - pc_labelx); - let mul_offsets_ptr = pc + (mul_offsets - pc_labelx); + pc_label: + let add_offsets_ptr = pc + (add_offsets - pc_label); + let mul_offsets_ptr = pc + (mul_offsets - pc_label); // Const 1. (0) assert [range_check96_ptr] = 1; @@ -551,8 +480,8 @@ func assert_opposite_mod_p{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*}( ) { let (_, pc) = get_fp_and_pc(); - pc_labelx: - let add_offsets_ptr = pc + (add_offsets - pc_labelx); + pc_label: + let add_offsets_ptr = pc + (add_offsets - pc_label); // Const 0. assert [range_check96_ptr] = 0; @@ -601,9 +530,9 @@ func assert_not_opposite_mod_p{ }(x: UInt384, y: UInt384, p: UInt384) { let (_, pc) = get_fp_and_pc(); - pc_labelx: - let add_offsets_ptr = pc + (add_offsets - pc_labelx); - let mul_offsets_ptr = pc + (mul_offsets - pc_labelx); + pc_label: + let add_offsets_ptr = pc + (add_offsets - pc_label); + let mul_offsets_ptr = pc + (mul_offsets - pc_label); // Const 1. (0) assert [range_check96_ptr] = 1; diff --git a/cairo/src/utils/signature.cairo b/cairo/src/utils/signature.cairo index 04d8df3f..ddad202e 100644 --- a/cairo/src/utils/signature.cairo +++ b/cairo/src/utils/signature.cairo @@ -24,13 +24,13 @@ from src.utils.circuit_utils import ( felt_to_UInt384, run_modulo_circuit_basic, ) -from src.utils.uint256 import uint256_to_uint384 - from src.utils.ecdsa_circuit import ( get_full_ecip_2P_circuit, get_ADD_EC_POINT_circuit, get_DOUBLE_EC_POINT_circuit, ) +from src.utils.uint256 import assert_uint256_le +from src.utils.uint384 import uint384_to_uint256, uint256_to_uint384 struct G1Point { x: UInt384, @@ -43,12 +43,14 @@ namespace secp256k1 { const P1 = 0xffffffffffffffffffffffff; const P2 = 0xffffffffffffffff; const P3 = 0x0; + const P_LOW_128 = 0xfffffffffffffffffffffffefffffc2f; + const P_HIGH_128 = 0xffffffffffffffffffffffffffffffff; const N0 = 0xaf48a03bbfd25e8cd0364141; const N1 = 0xfffffffffffffffebaaedce6; const N2 = 0xffffffffffffffff; + const N3 = 0x0; const N_LOW_128 = 0xbaaedce6af48a03bbfd25e8cd0364141; const N_HIGH_128 = 0xfffffffffffffffffffffffffffffffe; - const N3 = 0x0; const A0 = 0x0; const A1 = 0x0; const A2 = 0x0; @@ -98,33 +100,11 @@ func sign_to_uint384_mod_secp256k1(sign: felt) -> UInt384 { } } -// Takes a valid UInt384 value from ModuloBuiltin output, adds constraints to enforce it is canonically reduced mod p (ie: 0 <= a < p) and converts it to a Uint256. -// Assumes 1 < p < 2^256 passed as valid Uint384. -func uint384_to_uint256_mod_p{range_check_ptr}(a: UInt384, p: UInt384) -> (res: Uint256) { - assert a.d3 = 0; // From assumption : "p < 2^256", canonical reduction of a is only possible if a.d3 is 0. - if (a.d2 == p.d2) { - if (a.d1 == p.d1) { - assert [range_check_ptr] = p.d0 - 1 - a.d0; - tempvar range_check_ptr = range_check_ptr + 1; - } else { - assert [range_check_ptr] = p.d1 - 1 - a.d1; - tempvar range_check_ptr = range_check_ptr + 1; - } - } else { - assert [range_check_ptr] = p.d2 - a.d2; // a.d2 <= p.d2 && a.d2 != p.d2 => a.d2 < p.d2 - tempvar range_check_ptr = range_check_ptr + 1; - } - // Then decompose and rebuild uint256 - let (d1_high_64, d1_low_32) = divmod(a.d1, 2 ** 32); - // a.d2 is guaranteed to be in 64 bits since we know it's fully reduced. - return (res=Uint256(low=a.d0 + 2 ** 96 * d1_low_32, high=d1_high_64 + 2 ** 64 * a.d2)); -} - // A function field element of the form : // F(x,y) = a(x) + y b(x) // Where a, b are rational functions of x. // The rational functions are represented as polynomials in x with coefficients in F_p, starting from the constant term. -// No information about the degrees of the polynomials is stored here as they are derived implicitely from the MSM size. +// No information about the degrees of the polynomials is stored here as they are derived implicitly from the MSM size. struct FunctionFelt { a_num: UInt384*, a_den: UInt384*, @@ -396,13 +376,16 @@ namespace Signature { // where the division by r is modulo N. let N = UInt384(secp256k1.N0, secp256k1.N1, secp256k1.N2, secp256k1.N3); + let N_min_one = Uint256(secp256k1.N_LOW_128 - 1, secp256k1.N_HIGH_128); let (_u1: UInt384) = div_mod_p(msg_hash, r, N); let (_u1: UInt384) = neg_mod_p(_u1, N); let (_u2: UInt384) = div_mod_p(s, r, N); - let (u1) = uint384_to_uint256_mod_p(_u1, N); - let (u2) = uint384_to_uint256_mod_p(_u2, N); + let u1 = uint384_to_uint256(_u1); + assert_uint256_le(u1, N_min_one); + let u2 = uint384_to_uint256(_u2); + assert_uint256_le(u2, N_min_one); let (ep1_low, en1_low, sp1_low, sn1_low) = scalar_to_epns(u1.low); let (ep1_high, en1_high, sp1_high, sn1_high) = scalar_to_epns(u1.high); @@ -583,12 +566,6 @@ namespace Signature { // base_rlc assert ecip_input[59] = rlc_coeff_u384; - // let (point1) = ec_mul(generator_point, u1); - // let (minus_point1) = ec_negate(point1); - // let (point2) = ec_mul([r_point], u2); - // let (public_key_point) = ec_add(minus_point1, point2); - // return (public_key_point=public_key_point, success=1); - let (add_offsets_ptr, mul_offsets_ptr) = get_full_ecip_2P_circuit(); let p = UInt384(secp256k1.P0, secp256k1.P1, secp256k1.P2, secp256k1.P3); @@ -615,14 +592,6 @@ namespace Signature { tempvar range_check96_ptr = range_check96_ptr_final; let add_mod_ptr = add_mod_ptr + 117 * ModBuiltin.SIZE; let mul_mod_ptr = mul_mod_ptr + 108 * ModBuiltin.SIZE; - // Add Q_low and Q_high_shifted: - // %{ - // from garaga.hints.io import pack_bigint_array - - // arro = pack_bigint_array(ids.ecip_input, 4, 2**96, 283) - // for i, v in enumerate(arro): - // print(f"{i}: {hex(v)}") - // %} let (res) = add_ec_points_secp256k1( G1Point(x=ecip_input[50], y=ecip_input[51]), G1Point(x=ecip_input[54], y=ecip_input[55]) ); @@ -651,12 +620,13 @@ namespace Signature { msg_hash=msg_hash, r=r, s=s, y_parity=y_parity ); if (success == 0) { - assert 1 = 0; return (success=0, address=0); } - let modulus = UInt384(secp256k1.P0, secp256k1.P1, secp256k1.P2, secp256k1.P3); - let (x_uint256) = uint384_to_uint256_mod_p(public_key_point.x, modulus); - let (y_uint256) = uint384_to_uint256_mod_p(public_key_point.y, modulus); + let max_value = Uint256(secp256k1.P_LOW_128 - 1, secp256k1.P_HIGH_128); + let x_uint256 = uint384_to_uint256(public_key_point.x); + assert_uint256_le(x_uint256, max_value); + let y_uint256 = uint384_to_uint256(public_key_point.y); + assert_uint256_le(y_uint256, max_value); let address = Internals.public_key_point_to_eth_address(x=x_uint256, y=y_uint256); return (success=success, address=address); } diff --git a/cairo/src/utils/uint256.cairo b/cairo/src/utils/uint256.cairo index 9582fc50..18d26ab2 100644 --- a/cairo/src/utils/uint256.cairo +++ b/cairo/src/utils/uint256.cairo @@ -382,15 +382,6 @@ func uint256_to_uint160{range_check_ptr}(x: Uint256) -> felt { return x.low + high * 2 ** 128; } -// @notice Converts a 256-bit unsigned integer to a 384-bit unsigned integer. -// @param a The 256-bit unsigned integer. -// @return res The resulting 384-bit unsigned integer. -func uint256_to_uint384{range_check_ptr}(a: Uint256) -> UInt384 { - let (high_64_high, high_64_low) = divmod(a.high, 2 ** 64); - let (low_32_high, low_96_low) = divmod(a.low, 2 ** 96); - let res = UInt384(low_96_low, low_32_high + 2 ** 32 * high_64_low, high_64_high, 0); - return res; -} // @notice Return true if both integers are equal. // @dev Same as the one from starkware's cairo common library, but without the useless range_check arg func uint256_eq(a: Uint256, b: Uint256) -> (res: felt) { @@ -402,3 +393,14 @@ func uint256_eq(a: Uint256, b: Uint256) -> (res: felt) { } return (res=1); } + +func assert_uint256_le{range_check_ptr}(a: Uint256, b: Uint256) { + assert [range_check_ptr + 0] = b.high - a.high; + if (b.high != a.high) { + let range_check_ptr = range_check_ptr + 1; + return (); + } + assert [range_check_ptr + 1] = b.low - a.low; + let range_check_ptr = range_check_ptr + 2; + return (); +} diff --git a/cairo/src/utils/uint384.cairo b/cairo/src/utils/uint384.cairo new file mode 100644 index 00000000..da34bd57 --- /dev/null +++ b/cairo/src/utils/uint384.cairo @@ -0,0 +1,44 @@ +from starkware.cairo.common.cairo_builtins import UInt384 +from starkware.cairo.common.uint256 import Uint256 +from ethereum.utils.numeric import divmod + +// @notice Converts a 256-bit unsigned integer to a 384-bit unsigned integer. +// @param a The 256-bit unsigned integer. +// @return res The resulting 384-bit unsigned integer. +func uint256_to_uint384{range_check_ptr}(a: Uint256) -> UInt384 { + let (high_64_high, high_64_low) = divmod(a.high, 2 ** 64); + let (low_32_high, low_96_low) = divmod(a.low, 2 ** 96); + let res = UInt384(low_96_low, low_32_high + 2 ** 32 * high_64_low, high_64_high, 0); + return res; +} + +// @notice Converts a 384-bit unsigned integer to a 256-bit unsigned integer. +// @dev Raises if it doesn't fit in 256 bits. +// @param a The 384-bit unsigned integer. +// @return res The resulting 256-bit unsigned integer. +func uint384_to_uint256{range_check_ptr}(a: UInt384) -> Uint256 { + assert a.d3 = 0; + let (d2_high, d2_low) = divmod(a.d2, 2 ** 64); + assert d2_high = 0; + let (d1_high, d1_low) = divmod(a.d1, 2 ** 32); + let res = Uint256(low=a.d0 + 2 ** 96 * d1_low, high=d1_high + 2 ** 64 * d2_low); + return res; +} + +func assert_uint384_le{range_check96_ptr: felt*}(a: UInt384, b: UInt384) { + assert [range_check96_ptr + 0] = b.d3 - a.d3; + if (b.d3 != a.d0) { + return (); + } + assert [range_check96_ptr + 1] = b.d2 - a.d2; + if (b.d2 != a.d3) { + return (); + } + assert [range_check96_ptr + 2] = b.d1 - a.d1; + if (b.d1 != a.d2) { + return (); + } + assert [range_check96_ptr + 3] = b.d0 - a.d0; + let range_check96_ptr = range_check96_ptr + 4; + return (); +} diff --git a/cairo/tests/src/utils/test_signature.cairo b/cairo/tests/src/utils/test_signature.cairo index 86e88417..4fc81517 100644 --- a/cairo/tests/src/utils/test_signature.cairo +++ b/cairo/tests/src/utils/test_signature.cairo @@ -9,7 +9,8 @@ from starkware.cairo.common.cairo_builtins import ( from starkware.cairo.common.cairo_secp.bigint import uint256_to_bigint from src.utils.signature import Signature, Internals -from src.utils.uint256 import uint256_eq, uint256_to_uint384 +from src.utils.uint256 import uint256_eq +from src.utils.uint384 import uint256_to_uint384 func test__public_key_point_to_eth_address{ range_check_ptr, From d1d4fc9492287f7cd29312a7f654b8c5e966ee41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Walter?= Date: Tue, 21 Jan 2025 11:40:39 +0100 Subject: [PATCH 04/17] test for assert_uint256_le --- cairo/src/utils/uint256.cairo | 2 ++ cairo/tests/src/utils/test_uint256.cairo | 15 ++++++++++++++- cairo/tests/src/utils/test_uint256.py | 19 +++++++++++++++++++ cairo/tests/utils/compiler.py | 1 + 4 files changed, 36 insertions(+), 1 deletion(-) diff --git a/cairo/src/utils/uint256.cairo b/cairo/src/utils/uint256.cairo index 18d26ab2..134f6924 100644 --- a/cairo/src/utils/uint256.cairo +++ b/cairo/src/utils/uint256.cairo @@ -394,6 +394,8 @@ func uint256_eq(a: Uint256, b: Uint256) -> (res: felt) { return (res=1); } +// @notice Assert that a is less than or equal to b. +// @dev Uint256 are supposed to be well formed func assert_uint256_le{range_check_ptr}(a: Uint256, b: Uint256) { assert [range_check_ptr + 0] = b.high - a.high; if (b.high != a.high) { diff --git a/cairo/tests/src/utils/test_uint256.cairo b/cairo/tests/src/utils/test_uint256.cairo index a47f471a..0fdc8b19 100644 --- a/cairo/tests/src/utils/test_uint256.cairo +++ b/cairo/tests/src/utils/test_uint256.cairo @@ -4,7 +4,7 @@ from starkware.cairo.common.cairo_builtins import HashBuiltin from starkware.cairo.common.uint256 import Uint256 from starkware.cairo.common.alloc import alloc -from src.utils.uint256 import uint256_to_uint160, uint256_add, uint256_sub +from src.utils.uint256 import uint256_to_uint160, uint256_add, uint256_sub, assert_uint256_le func test__uint256_to_uint160{range_check_ptr}() { // Given @@ -49,3 +49,16 @@ func test__uint256_sub{range_check_ptr}() -> Uint256 { return res; } + +func test__assert_uint256_le{range_check_ptr}() { + alloc_locals; + let (a_ptr) = alloc(); + let (b_ptr) = alloc(); + %{ + segments.write_arg(ids.a_ptr, program_input["a"]) + segments.write_arg(ids.b_ptr, program_input["b"]) + %} + assert_uint256_le([cast(a_ptr, Uint256*)], [cast(b_ptr, Uint256*)]); + + return (); +} diff --git a/cairo/tests/src/utils/test_uint256.py b/cairo/tests/src/utils/test_uint256.py index 9826192e..30d8b918 100644 --- a/cairo/tests/src/utils/test_uint256.py +++ b/cairo/tests/src/utils/test_uint256.py @@ -39,3 +39,22 @@ def test_sub(self, cairo_run, a, b): "test__uint256_sub", a=int_to_uint256(a), b=int_to_uint256(b) ) assert res["low"] + res["high"] * 2**128 == (a - b) % 2**256 + + class TestAssertUint256Le: + @given( + a=integers(min_value=0, max_value=2**256 - 1), + b=integers(min_value=0, max_value=2**256 - 1), + ) + @settings(max_examples=50) + def test_assert_uint256_le(self, cairo_run, a, b): + if a > b: + with pytest.raises(Exception): + cairo_run( + "test__assert_uint256_le", + a=int_to_uint256(a), + b=int_to_uint256(b), + ) + else: + cairo_run( + "test__assert_uint256_le", a=int_to_uint256(a), b=int_to_uint256(b) + ) diff --git a/cairo/tests/utils/compiler.py b/cairo/tests/utils/compiler.py index 13d1d7b5..ff61fa13 100644 --- a/cairo/tests/utils/compiler.py +++ b/cairo/tests/utils/compiler.py @@ -68,6 +68,7 @@ def get_cairo_program(cairo_file: Path, main_path, dump_path: Optional[Path] = N logger.info(f"Compiling {cairo_file}") program = cairo_compile(cairo_file, debug_info=True, proof_mode=False) if dump_path is not None: + dump_path.parent.mkdir(parents=True, exist_ok=True) dump_path.with_suffix(".lock").write_text( json.dumps(program.Schema().dump(program), indent=4, sort_keys=True) ) From 788244aae53c9eff3f289357d55ff5d4173bdaf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Walter?= Date: Tue, 21 Jan 2025 12:05:11 +0100 Subject: [PATCH 05/17] Add uint384 tests --- cairo/src/utils/uint384.cairo | 12 +++++-- cairo/src/utils/uint384.py | 10 ++++++ cairo/tests/src/utils/test_uint384.cairo | 35 ++++++++++++++++++ cairo/tests/src/utils/test_uint384.py | 46 ++++++++++++++++++++++++ 4 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 cairo/src/utils/uint384.py create mode 100644 cairo/tests/src/utils/test_uint384.cairo create mode 100644 cairo/tests/src/utils/test_uint384.py diff --git a/cairo/src/utils/uint384.cairo b/cairo/src/utils/uint384.cairo index da34bd57..4b48c2e2 100644 --- a/cairo/src/utils/uint384.cairo +++ b/cairo/src/utils/uint384.cairo @@ -25,17 +25,23 @@ func uint384_to_uint256{range_check_ptr}(a: UInt384) -> Uint256 { return res; } +// @notice Asserts that a 384-bit unsigned integer is less than or equal to another 384-bit unsigned integer. +// @param a The first 384-bit unsigned integer. +// @param b The second 384-bit unsigned integer. func assert_uint384_le{range_check96_ptr: felt*}(a: UInt384, b: UInt384) { assert [range_check96_ptr + 0] = b.d3 - a.d3; - if (b.d3 != a.d0) { + if (b.d3 != a.d3) { + let range_check96_ptr = range_check96_ptr + 1; return (); } assert [range_check96_ptr + 1] = b.d2 - a.d2; - if (b.d2 != a.d3) { + if (b.d2 != a.d2) { + let range_check96_ptr = range_check96_ptr + 2; return (); } assert [range_check96_ptr + 2] = b.d1 - a.d1; - if (b.d1 != a.d2) { + if (b.d1 != a.d1) { + let range_check96_ptr = range_check96_ptr + 3; return (); } assert [range_check96_ptr + 3] = b.d0 - a.d0; diff --git a/cairo/src/utils/uint384.py b/cairo/src/utils/uint384.py new file mode 100644 index 00000000..e43f83e0 --- /dev/null +++ b/cairo/src/utils/uint384.py @@ -0,0 +1,10 @@ +def int_to_uint384(value): + d0 = value & ((1 << 96) - 1) + d1 = (value >> 96) & ((1 << 96) - 1) + d2 = (value >> 192) & ((1 << 96) - 1) + d3 = (value >> 288) & ((1 << 96) - 1) + return d0, d1, d2, d3 + + +def uint384_to_int(d0, d1, d2, d3): + return d0 + d1 * 2**96 + d2 * 2**192 + d3 * 2**288 diff --git a/cairo/tests/src/utils/test_uint384.cairo b/cairo/tests/src/utils/test_uint384.cairo new file mode 100644 index 00000000..0104c7f6 --- /dev/null +++ b/cairo/tests/src/utils/test_uint384.cairo @@ -0,0 +1,35 @@ +from starkware.cairo.common.cairo_builtins import HashBuiltin, UInt384 +from starkware.cairo.common.uint256 import Uint256 +from starkware.cairo.common.alloc import alloc + +from src.utils.uint384 import assert_uint384_le, uint384_to_uint256, uint256_to_uint384 + +func test__uint256_to_uint384{range_check_ptr}() -> UInt384 { + alloc_locals; + let (a_ptr) = alloc(); + %{ segments.write_arg(ids.a_ptr, program_input["a"]) %} + let res = uint256_to_uint384([cast(a_ptr, Uint256*)]); + return res; +} + +func test__uint384_to_uint256{range_check_ptr}() -> Uint256 { + alloc_locals; + let (a_ptr) = alloc(); + %{ segments.write_arg(ids.a_ptr, program_input["a"]) %} + let res = uint384_to_uint256([cast(a_ptr, UInt384*)]); + + return res; +} + +func test__assert_uint384_le{range_check96_ptr: felt*}() { + alloc_locals; + let (a_ptr) = alloc(); + let (b_ptr) = alloc(); + %{ + segments.write_arg(ids.a_ptr, program_input["a"]) + segments.write_arg(ids.b_ptr, program_input["b"]) + %} + assert_uint384_le([cast(a_ptr, UInt384*)], [cast(b_ptr, UInt384*)]); + + return (); +} diff --git a/cairo/tests/src/utils/test_uint384.py b/cairo/tests/src/utils/test_uint384.py new file mode 100644 index 00000000..63c50846 --- /dev/null +++ b/cairo/tests/src/utils/test_uint384.py @@ -0,0 +1,46 @@ +import pytest +from hypothesis import given +from hypothesis.strategies import integers + +from src.utils.uint256 import int_to_uint256, uint256_to_int +from src.utils.uint384 import int_to_uint384, uint384_to_int + +pytestmark = pytest.mark.python_vm + + +class TestUint384: + + class TestUint256ToUint384: + @given(a=integers(min_value=0, max_value=2**256 - 1)) + def test_should_pass_if_fits_in_256_bits(self, cairo_run, a): + res = cairo_run("test__uint256_to_uint384", a=int_to_uint256(a)) + assert uint384_to_int(res["d0"], res["d1"], res["d2"], res["d3"]) == a + + class TestUint384ToUint256: + @given(a=integers(min_value=0, max_value=2**256 - 1)) + def test_should_pass_if_fits_in_256_bits(self, cairo_run, a): + res = cairo_run("test__uint384_to_uint256", a=int_to_uint384(a)) + assert uint256_to_int(res["low"], res["high"]) == a + + @given(a=integers(min_value=2**256, max_value=2**384 - 1)) + def test_should_fail_if_does_not_fit_in_256_bits(self, cairo_run, a): + with pytest.raises(Exception): + cairo_run("test__uint384_to_uint256", a=int_to_uint384(a)) + + class TestAssertUint384Le: + @given( + a=integers(min_value=0, max_value=2**384 - 1), + b=integers(min_value=0, max_value=2**384 - 1), + ) + def test_assert_uint384_le(self, cairo_run, a, b): + if a > b: + with pytest.raises(Exception): + cairo_run( + "test__assert_uint384_le", + a=int_to_uint384(a), + b=int_to_uint384(b), + ) + else: + cairo_run( + "test__assert_uint384_le", a=int_to_uint384(a), b=int_to_uint384(b) + ) From cff175962a913fbea01e8dcd6476e23093b569a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Walter?= Date: Tue, 21 Jan 2025 12:39:29 +0100 Subject: [PATCH 06/17] Add hashdict to dict settings --- .vscode/settings.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.vscode/settings.json b/.vscode/settings.json index f98da303..c1595803 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -19,6 +19,7 @@ "frozendict", "fspaths", "getattr", + "hashdict", "hookwrapper", "intdigest", "ipykernel", From 6536bf6039bf35991acab013e315df1190aed415 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Walter?= Date: Tue, 21 Jan 2025 13:02:20 +0100 Subject: [PATCH 07/17] Move some secp256k1 utils to dedicated file --- cairo/src/curve/g1_point.cairo | 6 +++ cairo/src/curve/secp256k1.cairo | 61 +++++++++++++++++++++ cairo/src/utils/signature.cairo | 62 ++-------------------- cairo/tests/src/curve/test_secp256k1.cairo | 17 ++++++ cairo/tests/src/curve/test_secp256k1.py | 5 ++ 5 files changed, 93 insertions(+), 58 deletions(-) create mode 100644 cairo/src/curve/g1_point.cairo create mode 100644 cairo/src/curve/secp256k1.cairo create mode 100644 cairo/tests/src/curve/test_secp256k1.cairo create mode 100644 cairo/tests/src/curve/test_secp256k1.py diff --git a/cairo/src/curve/g1_point.cairo b/cairo/src/curve/g1_point.cairo new file mode 100644 index 00000000..47ce38e5 --- /dev/null +++ b/cairo/src/curve/g1_point.cairo @@ -0,0 +1,6 @@ +from starkware.cairo.common.cairo_builtins import UInt384 + +struct G1Point { + x: UInt384, + y: UInt384, +} diff --git a/cairo/src/curve/secp256k1.cairo b/cairo/src/curve/secp256k1.cairo new file mode 100644 index 00000000..b4d079e3 --- /dev/null +++ b/cairo/src/curve/secp256k1.cairo @@ -0,0 +1,61 @@ +from starkware.cairo.common.cairo_builtins import UInt384 +from starkware.cairo.lang.compiler.lib.registers import get_fp_and_pc + +from src.curve.g1_point import G1Point + +namespace secp256k1 { + const CURVE_ID = 2; + const P0 = 0xfffffffffffffffefffffc2f; + const P1 = 0xffffffffffffffffffffffff; + const P2 = 0xffffffffffffffff; + const P3 = 0x0; + const P_LOW_128 = 0xfffffffffffffffffffffffefffffc2f; + const P_HIGH_128 = 0xffffffffffffffffffffffffffffffff; + const N0 = 0xaf48a03bbfd25e8cd0364141; + const N1 = 0xfffffffffffffffebaaedce6; + const N2 = 0xffffffffffffffff; + const N3 = 0x0; + const N_LOW_128 = 0xbaaedce6af48a03bbfd25e8cd0364141; + const N_HIGH_128 = 0xfffffffffffffffffffffffffffffffe; + const A0 = 0x0; + const A1 = 0x0; + const A2 = 0x0; + const A3 = 0x0; + const B0 = 0x7; + const B1 = 0x0; + const B2 = 0x0; + const B3 = 0x0; + const G0 = 0x3; + const G1 = 0x0; + const G2 = 0x0; + const G3 = 0x0; + const MIN_ONE_D0 = 0xfffffffffffffffefffffc2e; + const MIN_ONE_D1 = 0xffffffffffffffffffffffff; + const MIN_ONE_D2 = 0xffffffffffffffff; + const MIN_ONE_D3 = 0x0; +} + +// @notice generator_point = ( +// 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798, +// 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 +// ) +// @dev Split in 96 bits chunks +func get_generator_point() -> G1Point* { + + let (_, pc) = get_fp_and_pc(); + + pc_label: + let generator_ptr = pc + (generator_label - pc_label); + + return cast(generator_ptr, G1Point*); + + generator_label: + dw 0x2dce28d959f2815b16f81798; // x.d0 + dw 0x55a06295ce870b07029bfcdb; // x.d1 + dw 0x79be667ef9dcbbac; // x.d2 + dw 0x0; // x.d3 + dw 0xa68554199c47d08ffb10d4b8; // y.d0 + dw 0x5da4fbfc0e1108a8fd17b448; // y.d1 + dw 0x483ada7726a3c465; // y.d2 + dw 0x0; // y.d3 +} diff --git a/cairo/src/utils/signature.cairo b/cairo/src/utils/signature.cairo index ddad202e..68c58f90 100644 --- a/cairo/src/utils/signature.cairo +++ b/cairo/src/utils/signature.cairo @@ -31,61 +31,8 @@ from src.utils.ecdsa_circuit import ( ) from src.utils.uint256 import assert_uint256_le from src.utils.uint384 import uint384_to_uint256, uint256_to_uint384 - -struct G1Point { - x: UInt384, - y: UInt384, -} - -namespace secp256k1 { - const CURVE_ID = 2; - const P0 = 0xfffffffffffffffefffffc2f; - const P1 = 0xffffffffffffffffffffffff; - const P2 = 0xffffffffffffffff; - const P3 = 0x0; - const P_LOW_128 = 0xfffffffffffffffffffffffefffffc2f; - const P_HIGH_128 = 0xffffffffffffffffffffffffffffffff; - const N0 = 0xaf48a03bbfd25e8cd0364141; - const N1 = 0xfffffffffffffffebaaedce6; - const N2 = 0xffffffffffffffff; - const N3 = 0x0; - const N_LOW_128 = 0xbaaedce6af48a03bbfd25e8cd0364141; - const N_HIGH_128 = 0xfffffffffffffffffffffffffffffffe; - const A0 = 0x0; - const A1 = 0x0; - const A2 = 0x0; - const A3 = 0x0; - const B0 = 0x7; - const B1 = 0x0; - const B2 = 0x0; - const B3 = 0x0; - const G0 = 0x3; - const G1 = 0x0; - const G2 = 0x0; - const G3 = 0x0; - const MIN_ONE_D0 = 0xfffffffffffffffefffffc2e; - const MIN_ONE_D1 = 0xffffffffffffffffffffffff; - const MIN_ONE_D2 = 0xffffffffffffffff; - const MIN_ONE_D3 = 0x0; -} - -@known_ap_change -func get_generator_point() -> (point: G1Point) { - // generator_point = ( - // 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798, - // 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 - // ). - return ( - point=G1Point( - x=UInt384( - 0x2dce28d959f2815b16f81798, 0x55a06295ce870b07029bfcdb, 0x79be667ef9dcbbac, 0x0 - ), - y=UInt384( - 0xa68554199c47d08ffb10d4b8, 0x5da4fbfc0e1108a8fd17b448, 0x483ada7726a3c465, 0x0 - ), - ), - ); -} +from src.curve.secp256k1 import secp256k1, get_generator_point +from src.curve.g1_point import G1Point @known_ap_change func sign_to_uint384_mod_secp256k1(sign: felt) -> UInt384 { @@ -370,7 +317,6 @@ namespace Signature { public_key_point=G1Point(x=UInt384(0, 0, 0, 0), y=UInt384(0, 0, 0, 0)), success=0 ); } - let (generator_point: G1Point) = get_generator_point(); // The result is given by // -(msg_hash / r) * gen + (s / r) * r_point // where the division by r is modulo N. @@ -412,7 +358,7 @@ namespace Signature { let (en2_high_384) = felt_to_UInt384(en2_high); let sp2_high_384 = sign_to_uint384_mod_secp256k1(sp2_high); let sn2_high_384 = sign_to_uint384_mod_secp256k1(sn2_high); - let (local generator_point: G1Point) = get_generator_point(); + let generator_point = get_generator_point(); // _hash_inputs_points_scalars_and_result_points @@ -474,7 +420,7 @@ namespace Signature { // tempvar init_s0 = poseidon_ptr[1].output.s0 + 0; // // %{ print(f"CAIROS0: {hex(ids.init_s0)}") %} let poseidon_ptr = poseidon_ptr + 2 * PoseidonBuiltin.SIZE; - let (_, _, _) = hash_full_transcript_and_get_Z_3_LIMBS(cast(&generator_point, felt*), 2); + let (_, _, _) = hash_full_transcript_and_get_Z_3_LIMBS(cast(generator_point, felt*), 2); let (_, _, _) = hash_full_transcript_and_get_Z_3_LIMBS(cast(r_point, felt*), 2); // Q_low, Q_high, Q_high_shifted (filled by prover) (50 - 55). let (_s0, _s1, _s2) = hash_full_transcript_and_get_Z_3_LIMBS( diff --git a/cairo/tests/src/curve/test_secp256k1.cairo b/cairo/tests/src/curve/test_secp256k1.cairo new file mode 100644 index 00000000..293a2680 --- /dev/null +++ b/cairo/tests/src/curve/test_secp256k1.cairo @@ -0,0 +1,17 @@ +from starkware.cairo.common.cairo_builtins import UInt384 +from src.curve.secp256k1 import get_generator_point + +func test__get_generator_point() { + let generator = get_generator_point(); + + assert generator.x.d0 = 0x2dce28d959f2815b16f81798; + assert generator.x.d1 = 0x55a06295ce870b07029bfcdb; + assert generator.x.d2 = 0x79be667ef9dcbbac; + assert generator.x.d3 = 0x0; + assert generator.y.d0 = 0xa68554199c47d08ffb10d4b8; + assert generator.y.d1 = 0x5da4fbfc0e1108a8fd17b448; + assert generator.y.d2 = 0x483ada7726a3c465; + assert generator.y.d3 = 0x0; + + return (); +} diff --git a/cairo/tests/src/curve/test_secp256k1.py b/cairo/tests/src/curve/test_secp256k1.py new file mode 100644 index 00000000..b85f5731 --- /dev/null +++ b/cairo/tests/src/curve/test_secp256k1.py @@ -0,0 +1,5 @@ +class TestSecp256k1: + + class TestGetGeneratorPoint: + def test_get_generator_point(self, cairo_run): + cairo_run("test__get_generator_point") From 4471c92d8daa49dfd30776dfacecc692af0039e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Walter?= Date: Tue, 21 Jan 2025 13:27:27 +0100 Subject: [PATCH 08/17] Some cleaning of signature.cairo --- .vscode/settings.json | 1 + cairo/src/curve/secp256k1.cairo | 17 +++++++-------- cairo/src/utils/circuit_utils.cairo | 34 +++++++++++++---------------- cairo/src/utils/signature.cairo | 25 --------------------- 4 files changed, 24 insertions(+), 53 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index c1595803..c623d2ff 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -12,6 +12,7 @@ "defaultdict", "divmod", "eips", + "epns", "exitstatus", "fibonacci", "filterwarnings", diff --git a/cairo/src/curve/secp256k1.cairo b/cairo/src/curve/secp256k1.cairo index b4d079e3..3c2c95df 100644 --- a/cairo/src/curve/secp256k1.cairo +++ b/cairo/src/curve/secp256k1.cairo @@ -41,7 +41,6 @@ namespace secp256k1 { // ) // @dev Split in 96 bits chunks func get_generator_point() -> G1Point* { - let (_, pc) = get_fp_and_pc(); pc_label: @@ -50,12 +49,12 @@ func get_generator_point() -> G1Point* { return cast(generator_ptr, G1Point*); generator_label: - dw 0x2dce28d959f2815b16f81798; // x.d0 - dw 0x55a06295ce870b07029bfcdb; // x.d1 - dw 0x79be667ef9dcbbac; // x.d2 - dw 0x0; // x.d3 - dw 0xa68554199c47d08ffb10d4b8; // y.d0 - dw 0x5da4fbfc0e1108a8fd17b448; // y.d1 - dw 0x483ada7726a3c465; // y.d2 - dw 0x0; // y.d3 + dw 0x2dce28d959f2815b16f81798; // x.d0 + dw 0x55a06295ce870b07029bfcdb; // x.d1 + dw 0x79be667ef9dcbbac; // x.d2 + dw 0x0; // x.d3 + dw 0xa68554199c47d08ffb10d4b8; // y.d0 + dw 0x5da4fbfc0e1108a8fd17b448; // y.d1 + dw 0x483ada7726a3c465; // y.d2 + dw 0x0; // y.d3 } diff --git a/cairo/src/utils/circuit_utils.cairo b/cairo/src/utils/circuit_utils.cairo index 26958af4..5bb08fdf 100644 --- a/cairo/src/utils/circuit_utils.cairo +++ b/cairo/src/utils/circuit_utils.cairo @@ -115,9 +115,10 @@ func sign{range_check_ptr}(value) -> felt { // From a 128 bit scalar, decomposes it into base (-3) such that // scalar = sum(digits[i] * (-3)^i for i in [0, 81]) +// digits[i] in {-1, 0, 1} for all i // scalar = sum_p - sum_n -// Where sum_p = sum(digits[i] * (-3)^i for i in [0, 81] if digits[i]==1) -// And sum_n = sum(digits[i] * (-3)^i for i in [0, 81] if digits[i]==-1) +// sum_p = sum(digits[i] * (-3)^i for i in [0, 81] if digits[i]==1) +// sum_n = sum(digits[i] * (-3)^i for i in [0, 81] if digits[i]==-1) // Returns (abs(sum_p), abs(sum_n), p_sign, n_sign) func scalar_to_epns{range_check_ptr}(scalar: felt) -> ( sum_p: felt, sum_n: felt, p_sign: felt, n_sign: felt @@ -138,22 +139,21 @@ func scalar_to_epns{range_check_ptr}(scalar: felt) -> ( if (d0 == 1) { tempvar sum_p = 1; tempvar sum_n = 0; - tempvar pow3 = -3; } else { tempvar sum_p = 0; tempvar sum_n = 1; - tempvar pow3 = -3; } } else { tempvar sum_p = 0; tempvar sum_n = 0; - tempvar pow3 = -3; } + tempvar pow3 = -3; + loop: - let pow3 = [ap - 1]; - let sum_n = [ap - 2]; let sum_p = [ap - 3]; + let sum_n = [ap - 2]; + let pow3 = [ap - 1]; %{ memory[ap] = 1 if i == 82 else 0 %} jmp end if [ap] != 0, ap++; @@ -184,13 +184,8 @@ func scalar_to_epns{range_check_ptr}(scalar: felt) -> ( let pow3 = [ap - 2]; let sum_n = [ap - 3]; let sum_p = [ap - 4]; - assert pow3 = (-3) ** 82; // + assert pow3 = (-3) ** 82; - // %{ - // from starkware.cairo.common.math_utils import as_int - // print(f"{as_int(ids.sum_p, PRIME)=}") - // print(f"{as_int(ids.sum_n, PRIME)=}") - // %} assert scalar = sum_p - sum_n; let p_sign = sign(sum_p); @@ -211,16 +206,17 @@ func felt_to_UInt384{range_check96_ptr: felt*}(x: felt) -> (res: UInt384) { %} assert [range_check96_ptr + 3] = STARK_MIN_ONE_D2 - d2; assert x = d0 + d1 * 2 ** 96 + d2 * 2 ** 192; + if (d2 == STARK_MIN_ONE_D2) { - // Take advantage of Cairo prime structure. STARK_MIN_ONE = 0 + 0 * BASE + stark_min_1_d2 * (BASE)**2. + // STARK_MIN_ONE = 0x800000000000011000000000000000000000000000000000000000000000000 + // So d0 = 0, d1 = 0, d2 = 0x800000000000011 + // If d2 == STARK_MIN_ONE_D2, then d0 == 0 and d1 == 0 assert d0 = 0; assert d1 = 0; - tempvar range_check96_ptr = range_check96_ptr + 4; - return (res=UInt384(d0, d1, d2, 0)); - } else { - tempvar range_check96_ptr = range_check96_ptr + 4; - return (res=UInt384(d0, d1, d2, 0)); } + + tempvar range_check96_ptr = range_check96_ptr + 4; + return (res=UInt384(d0, d1, d2, 0)); } func run_modulo_circuit_basic{ diff --git a/cairo/src/utils/signature.cairo b/cairo/src/utils/signature.cairo index 68c58f90..30611609 100644 --- a/cairo/src/utils/signature.cairo +++ b/cairo/src/utils/signature.cairo @@ -59,31 +59,6 @@ struct FunctionFelt { b_den: UInt384*, } -func hash_sum_dlog_div_batched{poseidon_ptr: PoseidonBuiltin*}( - f: FunctionFelt, msm_size: felt, init_hash: felt, curve_id: felt -) -> (res: felt) { - alloc_locals; - assert poseidon_ptr[0].input.s0 = init_hash; - assert poseidon_ptr[0].input.s1 = 0; - assert poseidon_ptr[0].input.s2 = 1; - let poseidon_ptr = poseidon_ptr + PoseidonBuiltin.SIZE; - - let (s0: felt, s1: felt, s2: felt) = hash_full_transcript_and_get_Z_3_LIMBS( - limbs_ptr=cast(f.a_num, felt*), n=msm_size + 1, curve_id=curve_id - ); - let (s0: felt, s1: felt, s2: felt) = hash_full_transcript_and_get_Z_3_LIMBS( - limbs_ptr=cast(f.a_den, felt*), n=msm_size + 2, curve_id=curve_id - ); - let (s0: felt, s1: felt, s2: felt) = hash_full_transcript_and_get_Z_3_LIMBS( - limbs_ptr=cast(f.b_num, felt*), n=msm_size + 2, curve_id=curve_id - ); - let (Z: felt, _, _) = hash_full_transcript_and_get_Z_3_LIMBS( - limbs_ptr=cast(f.b_den, felt*), n=msm_size + 5, curve_id=curve_id - ); - - return (res=Z); -} - func try_get_point_from_x_secp256k1{ range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, From 86783dbd19646e65843523e41f841bc8ab754915 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Walter?= Date: Tue, 21 Jan 2025 14:56:10 +0100 Subject: [PATCH 09/17] Uint384 utils in dedicated file and tested --- cairo/src/utils/circuit_basic_field_ops.cairo | 628 ------------------ cairo/src/utils/circuit_utils.cairo | 45 -- cairo/src/utils/signature.cairo | 43 +- cairo/src/utils/uint384.cairo | 381 ++++++++++- cairo/tests/src/utils/test_uint384.cairo | 161 ++++- cairo/tests/src/utils/test_uint384.py | 230 ++++++- 6 files changed, 779 insertions(+), 709 deletions(-) delete mode 100644 cairo/src/utils/circuit_basic_field_ops.cairo diff --git a/cairo/src/utils/circuit_basic_field_ops.cairo b/cairo/src/utils/circuit_basic_field_ops.cairo deleted file mode 100644 index 0f19e3e7..00000000 --- a/cairo/src/utils/circuit_basic_field_ops.cairo +++ /dev/null @@ -1,628 +0,0 @@ -from starkware.cairo.common.cairo_builtins import UInt384 -from starkware.cairo.common.cairo_builtins import ModBuiltin -from starkware.cairo.common.registers import get_fp_and_pc - -// Compute X + Y mod p. -func add_mod_p{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*}( - x: UInt384, y: UInt384, p: UInt384 -) -> (x_plus_y: UInt384) { - let (_, pc) = get_fp_and_pc(); - - pc_label: - let add_offsets_ptr = pc + (add_offsets - pc_label); - - // X limbs (offset 0) - assert [range_check96_ptr] = x.d0; - assert [range_check96_ptr + 1] = x.d1; - assert [range_check96_ptr + 2] = x.d2; - assert [range_check96_ptr + 3] = x.d3; - // Y limbs (offset 4) - assert [range_check96_ptr + 4] = y.d0; - assert [range_check96_ptr + 5] = y.d1; - assert [range_check96_ptr + 6] = y.d2; - assert [range_check96_ptr + 7] = y.d3; - - assert add_mod_ptr[0] = ModBuiltin( - p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=add_offsets_ptr, n=1 - ); - %{ - from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner - assert builtin_runners["add_mod_builtin"].instance_def.batch_size == 1 - - ModBuiltinRunner.fill_memory( - memory=memory, - add_mod=(ids.add_mod_ptr.address_, builtin_runners["add_mod_builtin"], 1), - mul_mod=None, - ) - %} - - let range_check96_ptr = range_check96_ptr + 12; - let add_mod_ptr = add_mod_ptr + ModBuiltin.SIZE; - return (x_plus_y=[cast(range_check96_ptr - 4, UInt384*)]); - - add_offsets: - // Instruction : assert 0 + 4 == 8 - dw 0; // X - dw 4; // Y - dw 8; // X+Y -} - -// Compute X - Y mod p. -func sub_mod_p{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*}( - x: UInt384, y: UInt384, p: UInt384 -) -> (x_minus_y: UInt384) { - let (_, pc) = get_fp_and_pc(); - - pc_label: - let add_offsets_ptr = pc + (add_offsets - pc_label); - - // X limbs (offset 0) - assert [range_check96_ptr] = x.d0; - assert [range_check96_ptr + 1] = x.d1; - assert [range_check96_ptr + 2] = x.d2; - assert [range_check96_ptr + 3] = x.d3; - // Y limbs (offset 4) - assert [range_check96_ptr + 4] = y.d0; - assert [range_check96_ptr + 5] = y.d1; - assert [range_check96_ptr + 6] = y.d2; - assert [range_check96_ptr + 7] = y.d3; - - assert add_mod_ptr[0] = ModBuiltin( - p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=add_offsets_ptr, n=1 - ); - %{ - from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner - assert builtin_runners["add_mod_builtin"].instance_def.batch_size == 1 - - ModBuiltinRunner.fill_memory( - memory=memory, - add_mod=(ids.add_mod_ptr.address_, builtin_runners["add_mod_builtin"], 1), - mul_mod=None, - ) - %} - - let range_check96_ptr = range_check96_ptr + 12; - let add_mod_ptr = add_mod_ptr + ModBuiltin.SIZE; - return (x_minus_y=[cast(range_check96_ptr - 4, UInt384*)]); - - add_offsets: - // Instruction : assert 4 + 8 == 0 - // 8 is unallocated, so the assert is Y + ? == X - // => ? == X - Y, at offset 8. - dw 4; // Y - dw 8; // X-Y - dw 0; -} - -// Compute - Y mod p. -func neg_mod_p{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*}(y: UInt384, p: UInt384) -> ( - neg_y: UInt384 -) { - let (_, pc) = get_fp_and_pc(); - - pc_label: - let add_offsets_ptr = pc + (add_offsets - pc_label); - - // X limbs (offset 0) - assert [range_check96_ptr] = 0; - assert [range_check96_ptr + 1] = 0; - assert [range_check96_ptr + 2] = 0; - assert [range_check96_ptr + 3] = 0; - // Y limbs (offset 4) - assert [range_check96_ptr + 4] = y.d0; - assert [range_check96_ptr + 5] = y.d1; - assert [range_check96_ptr + 6] = y.d2; - assert [range_check96_ptr + 7] = y.d3; - - assert add_mod_ptr[0] = ModBuiltin( - p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=add_offsets_ptr, n=1 - ); - %{ - from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner - assert builtin_runners["add_mod_builtin"].instance_def.batch_size == 1 - - ModBuiltinRunner.fill_memory( - memory=memory, - add_mod=(ids.add_mod_ptr.address_, builtin_runners["add_mod_builtin"], 1), - mul_mod=None, - ) - %} - - let range_check96_ptr = range_check96_ptr + 12; - let add_mod_ptr = add_mod_ptr + ModBuiltin.SIZE; - return (neg_y=[cast(range_check96_ptr - 4, UInt384*)]); - - add_offsets: - // Instruction : assert 4 + 8 == 0 - // 8 is unallocated, so the assert is Y + ? == 0 - // => ? == -Y, at offset 8. - dw 4; // Y - dw 8; // -Y - dw 0; // 0 -} - -// Compute X / Y mod p. -func div_mod_p{range_check96_ptr: felt*, mul_mod_ptr: ModBuiltin*}( - x: UInt384, y: UInt384, p: UInt384 -) -> (x_div_y: UInt384) { - let (_, pc) = get_fp_and_pc(); - - pc_label: - let mul_offsets_ptr = pc + (mul_offsets - pc_label); - - // X limbs (offset 0) - assert [range_check96_ptr] = x.d0; - assert [range_check96_ptr + 1] = x.d1; - assert [range_check96_ptr + 2] = x.d2; - assert [range_check96_ptr + 3] = x.d3; - // Y limbs (offset 4) - assert [range_check96_ptr + 4] = y.d0; - assert [range_check96_ptr + 5] = y.d1; - assert [range_check96_ptr + 6] = y.d2; - assert [range_check96_ptr + 7] = y.d3; - - assert mul_mod_ptr[0] = ModBuiltin( - p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=mul_offsets_ptr, n=1 - ); - %{ - from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner - assert builtin_runners["mul_mod_builtin"].instance_def.batch_size == 1 - - ModBuiltinRunner.fill_memory( - memory=memory, - add_mod=None, - mul_mod=(ids.mul_mod_ptr.address_, builtin_runners["mul_mod_builtin"], 1), - ) - %} - - let range_check96_ptr = range_check96_ptr + 12; - let mul_mod_ptr = mul_mod_ptr + ModBuiltin.SIZE; - return (x_div_y=[cast(range_check96_ptr - 4, UInt384*)]); - - mul_offsets: - // Instruction : assert 4 8 == 0 - // 8 is unallocated, so the assert is Y * ? == X - // => ? == X / Y, at offset 8. - dw 4; // Y - dw 8; // X/Y - dw 0; // X -} - -// Assert X == 0 mod p. -func assert_zero_mod_P{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*}(x: UInt384, p: UInt384) { - let (_, pc) = get_fp_and_pc(); - - pc_label: - let add_offsets_ptr = pc + (add_offsets - pc_label); - - // Const 0. - assert [range_check96_ptr] = 0; - assert [range_check96_ptr + 1] = 0; - assert [range_check96_ptr + 2] = 0; - assert [range_check96_ptr + 3] = 0; - // X limbs. - assert [range_check96_ptr + 4] = x.d0; - assert [range_check96_ptr + 5] = x.d1; - assert [range_check96_ptr + 6] = x.d2; - assert [range_check96_ptr + 7] = x.d3; - - assert add_mod_ptr[0] = ModBuiltin( - p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=add_offsets_ptr, n=1 - ); - %{ - from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner - assert builtin_runners["add_mod_builtin"].instance_def.batch_size == 1 - - ModBuiltinRunner.fill_memory( - memory=memory, - add_mod=(ids.add_mod_ptr.address_, builtin_runners["add_mod_builtin"], 1), - mul_mod=None, - ) - %} - let range_check96_ptr = range_check96_ptr + 8; - let add_mod_ptr = add_mod_ptr + ModBuiltin.SIZE; - return (); - - add_offsets: - // Instruction (offsets) : assert 0 + 4 == 0 - // <=> 0 + X == 0 mod p. => X == 0 mod p. - dw 0; // 0 - dw 4; // X - dw 0; // 0 -} - -// Assert X != 0 mod p. -func assert_not_zero_mod_P{range_check96_ptr: felt*, mul_mod_ptr: ModBuiltin*}( - x: UInt384, p: UInt384 -) { - let (_, pc) = get_fp_and_pc(); - - pc_label: - let mul_offsets_ptr = pc + (mul_offsets - pc_label); - - // Const 1. (offset 0) - assert [range_check96_ptr] = 1; - assert [range_check96_ptr + 1] = 0; - assert [range_check96_ptr + 2] = 0; - assert [range_check96_ptr + 3] = 0; - // X limbs (offset 4) - assert [range_check96_ptr + 4] = x.d0; - assert [range_check96_ptr + 5] = x.d1; - assert [range_check96_ptr + 6] = x.d2; - assert [range_check96_ptr + 7] = x.d3; - - // X^-1 (offset 8) - let x_inv_d0 = [range_check96_ptr + 8]; - let x_inv_d1 = [range_check96_ptr + 9]; - let x_inv_d2 = [range_check96_ptr + 10]; - let x_inv_d3 = [range_check96_ptr + 11]; - - %{ - from garaga.hints.io import bigint_split, bigint_pack - p = bigint_pack(ids.p, 4, 2**96) - x = bigint_pack(ids.x, 4, 2**96) - x_inv = pow(x, -1, p) - limbs = bigint_split(x_inv) - ids.x_inv_d0 = limbs[0] - ids.x_inv_d1 = limbs[1] - ids.x_inv_d2 = limbs[2] - ids.x_inv_d3 = limbs[3] - %} - - assert mul_mod_ptr[0] = ModBuiltin( - p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=mul_offsets_ptr, n=1 - ); - - %{ - from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner - assert builtin_runners["mul_mod_builtin"].instance_def.batch_size == 1 - - ModBuiltinRunner.fill_memory( - memory=memory, - add_mod=None, - mul_mod=(ids.mul_mod_ptr.address_, builtin_runners["mul_mod_builtin"], 1), - ) - %} - let range_check96_ptr = range_check96_ptr + 12; - let mul_mod_ptr = mul_mod_ptr + ModBuiltin.SIZE; - return (); - - // Assert X*X_inv == 1 (hints will fill X_inv and proof will assert X*X_inv == 1). - // If X_inv does not exists, no valid proof can be generated. - mul_offsets: - // Instruction (offsets) : assert 4 * 8 == 0 - dw 4; // X - dw 8; // X_inv - dw 0; // 0 -} - -// Returns 1 if X == 0 mod p, 0 otherwise. -func is_zero_mod_p{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin*}( - x: UInt384, p: UInt384 -) -> (res: felt) { - %{ - from garaga.hints.io import bigint_pack - x = bigint_pack(ids.x, 4, 2**96) - p = bigint_pack(ids.p, 4, 2**96) - %} - if (nondet %{ x % p == 0 %} != 0) { - assert_zero_mod_P(x, p); - return (res=1); - } else { - assert_not_zero_mod_P(x, p); - return (res=0); - } -} - -// Assert X == Y mod p by asserting Y - X == 0 -func assert_eq_mod_p{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*}( - x: UInt384, y: UInt384, p: UInt384 -) { - let (_, pc) = get_fp_and_pc(); - - pc_label: - let add_offsets_ptr = pc + (add_offsets - pc_label); - - // Const 0. (offset 0) - assert [range_check96_ptr] = 0; - assert [range_check96_ptr + 1] = 0; - assert [range_check96_ptr + 2] = 0; - assert [range_check96_ptr + 3] = 0; - // X limbs (offset 4) - assert [range_check96_ptr + 4] = x.d0; - assert [range_check96_ptr + 5] = x.d1; - assert [range_check96_ptr + 6] = x.d2; - assert [range_check96_ptr + 7] = x.d3; - // Y limbs (offset 8) - assert [range_check96_ptr + 8] = y.d0; - assert [range_check96_ptr + 9] = y.d1; - assert [range_check96_ptr + 10] = y.d2; - assert [range_check96_ptr + 11] = y.d3; - - // Builtin results : - // (- X) (offset 12) - // (Y - X) (offset 16) - - assert add_mod_ptr[0] = ModBuiltin( - p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=add_offsets_ptr, n=2 - ); - %{ - from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner - assert builtin_runners["add_mod_builtin"].instance_def.batch_size == 1 - - ModBuiltinRunner.fill_memory( - memory=memory, - add_mod=(ids.add_mod_ptr.address_, builtin_runners["add_mod_builtin"], 2), - mul_mod=None, - ) - %} - let range_check96_ptr = range_check96_ptr + 16; - let add_mod_ptr = add_mod_ptr + 2 * ModBuiltin.SIZE; - return (); - - // Compute 0 - X (X + (-X) = 0) - add_offsets: - dw 4; - dw 12; // - X - dw 0; - // Compute - X + Y and assert == 0 - dw 12; // - X - dw 8; // Y - dw 0; -} - -// assert X != Y mod p by asserting (X-Y) != 0 -func assert_neq_mod_p{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin*}( - x: UInt384, y: UInt384, p: UInt384 -) { - let (_, pc) = get_fp_and_pc(); - - pc_label: - let add_offsets_ptr = pc + (add_offsets - pc_label); - let mul_offsets_ptr = pc + (mul_offsets - pc_label); - - // Const 1. (0) - assert [range_check96_ptr] = 1; - assert [range_check96_ptr + 1] = 0; - assert [range_check96_ptr + 2] = 0; - assert [range_check96_ptr + 3] = 0; - // X limbs. (4) - assert [range_check96_ptr + 4] = x.d0; - assert [range_check96_ptr + 5] = x.d1; - assert [range_check96_ptr + 6] = x.d2; - assert [range_check96_ptr + 7] = x.d3; - // Y limbs. (8) - assert [range_check96_ptr + 8] = y.d0; - assert [range_check96_ptr + 9] = y.d1; - assert [range_check96_ptr + 10] = y.d2; - assert [range_check96_ptr + 11] = y.d3; - - // [X-Y] (12) - - // [X-Y]^-1 (16) - let diff_inv_d0 = [range_check96_ptr + 16]; - let diff_inv_d1 = [range_check96_ptr + 17]; - let diff_inv_d2 = [range_check96_ptr + 18]; - let diff_inv_d3 = [range_check96_ptr + 19]; - - %{ - from garaga.hints.io import bigint_split, bigint_pack - p = bigint_pack(ids.p, 4, 2**96) - x = bigint_pack(ids.x, 4, 2**96) - y = bigint_pack(ids.y, 4, 2**96) - diff = (x - y) % p - diff_inv = pow(diff, -1, p) - limbs = bigint_split(diff_inv) - ids.diff_inv_d0 = limbs[0] - ids.diff_inv_d1 = limbs[1] - ids.diff_inv_d2 = limbs[2] - ids.diff_inv_d3 = limbs[3] - %} - - assert add_mod_ptr[0] = ModBuiltin( - p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=add_offsets_ptr, n=1 - ); - assert mul_mod_ptr[0] = ModBuiltin( - p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=mul_offsets_ptr, n=1 - ); - %{ - from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner - assert builtin_runners["add_mod_builtin"].instance_def.batch_size == 1 - assert builtin_runners["mul_mod_builtin"].instance_def.batch_size == 1 - - ModBuiltinRunner.fill_memory( - memory=memory, - add_mod=(ids.add_mod_ptr.address_, builtin_runners["add_mod_builtin"], 1), - mul_mod=(ids.mul_mod_ptr.address_, builtin_runners["mul_mod_builtin"], 1), - ) - %} - let range_check96_ptr = range_check96_ptr + 20; - let add_mod_ptr = add_mod_ptr + ModBuiltin.SIZE; - let mul_mod_ptr = mul_mod_ptr + ModBuiltin.SIZE; - return (); - - // Compute X - Y <=> Y + (X-Y) == X - add_offsets: - dw 8; // Y - dw 12; // X - Y - dw 4; // X - - mul_offsets: - // Assert (X-Y)*(X-Y)^-1 == 1 ==> (X-Y) != 0 - dw 12; // [X-Y] - dw 16; // [X-Y]^-1 - dw 0; -} - -// Returns 1 if X == Y mod p, 0 otherwise. -func is_eq_mod_p{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin*}( - x: UInt384, y: UInt384, p: UInt384 -) -> (res: felt) { - %{ - from garaga.hints.io import bigint_pack - x = bigint_pack(ids.x, 4, 2**96) - y = bigint_pack(ids.y, 4, 2**96) - p = bigint_pack(ids.p, 4, 2**96) - %} - - if (nondet %{ x % p == y % p %} != 0) { - assert_eq_mod_p(x, y, p); - return (res=1); - } else { - assert_neq_mod_p(x, y, p); - return (res=0); - } -} - -// Assert X == - Y mod p by asserting X + Y == 0 -func assert_opposite_mod_p{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*}( - x: UInt384, y: UInt384, p: UInt384 -) { - let (_, pc) = get_fp_and_pc(); - - pc_label: - let add_offsets_ptr = pc + (add_offsets - pc_label); - - // Const 0. - assert [range_check96_ptr] = 0; - assert [range_check96_ptr + 1] = 0; - assert [range_check96_ptr + 2] = 0; - assert [range_check96_ptr + 3] = 0; - // X limbs. - assert [range_check96_ptr + 4] = x.d0; - assert [range_check96_ptr + 5] = x.d1; - assert [range_check96_ptr + 6] = x.d2; - assert [range_check96_ptr + 7] = x.d3; - // Y limbs. - assert [range_check96_ptr + 8] = y.d0; - assert [range_check96_ptr + 9] = y.d1; - assert [range_check96_ptr + 10] = y.d2; - assert [range_check96_ptr + 11] = y.d3; - - assert add_mod_ptr[0] = ModBuiltin( - p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=add_offsets_ptr, n=1 - ); - %{ - from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner - assert builtin_runners["add_mod_builtin"].instance_def.batch_size == 1 - - ModBuiltinRunner.fill_memory( - memory=memory, - add_mod=(ids.add_mod_ptr.address_, builtin_runners["add_mod_builtin"], 1), - mul_mod=None, - ) - %} - - let range_check96_ptr = range_check96_ptr + 12; - let add_mod_ptr = add_mod_ptr + ModBuiltin.SIZE; - return (); - - // Assert X + Y == 0 <=> X == -Y - add_offsets: - dw 4; // X - dw 8; // Y - dw 0; -} - -// assert X != -Y mod p by asserting X + Y != 0 -func assert_not_opposite_mod_p{ - range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin* -}(x: UInt384, y: UInt384, p: UInt384) { - let (_, pc) = get_fp_and_pc(); - - pc_label: - let add_offsets_ptr = pc + (add_offsets - pc_label); - let mul_offsets_ptr = pc + (mul_offsets - pc_label); - - // Const 1. (0) - assert [range_check96_ptr] = 1; - assert [range_check96_ptr + 1] = 0; - assert [range_check96_ptr + 2] = 0; - assert [range_check96_ptr + 3] = 0; - // X limbs. (4) - assert [range_check96_ptr + 4] = x.d0; - assert [range_check96_ptr + 5] = x.d1; - assert [range_check96_ptr + 6] = x.d2; - assert [range_check96_ptr + 7] = x.d3; - // Y limbs. (8) - assert [range_check96_ptr + 8] = y.d0; - assert [range_check96_ptr + 9] = y.d1; - assert [range_check96_ptr + 10] = y.d2; - assert [range_check96_ptr + 11] = y.d3; - - // [X+Y] (12) - // ... - - // [X+Y]^-1 (16) - let sum_inv_d0 = [range_check96_ptr + 16]; - let sum_inv_d1 = [range_check96_ptr + 17]; - let sum_inv_d2 = [range_check96_ptr + 18]; - let sum_inv_d3 = [range_check96_ptr + 19]; - - %{ - from garaga.hints.io import bigint_split, bigint_pack - p = bigint_pack(ids.p, 4, 2**96) - x = bigint_pack(ids.x, 4, 2**96) - y = bigint_pack(ids.y, 4, 2**96) - _sum = (x + y) % p - sum_inv = pow(_sum, -1, p) - limbs = bigint_split(sum_inv) - ids.sum_inv_d0 = limbs[0] - ids.sum_inv_d1 = limbs[1] - ids.sum_inv_d2 = limbs[2] - ids.sum_inv_d3 = limbs[3] - %} - - assert add_mod_ptr[0] = ModBuiltin( - p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=add_offsets_ptr, n=1 - ); - assert mul_mod_ptr[0] = ModBuiltin( - p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=mul_offsets_ptr, n=1 - ); - %{ - from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner - assert builtin_runners["add_mod_builtin"].instance_def.batch_size == 1 - assert builtin_runners["mul_mod_builtin"].instance_def.batch_size == 1 - - ModBuiltinRunner.fill_memory( - memory=memory, - add_mod=(ids.add_mod_ptr.address_, builtin_runners["add_mod_builtin"], 1), - mul_mod=(ids.mul_mod_ptr.address_, builtin_runners["mul_mod_builtin"], 1), - ) - %} - let range_check96_ptr = range_check96_ptr + 20; - let add_mod_ptr = add_mod_ptr + ModBuiltin.SIZE; - let mul_mod_ptr = mul_mod_ptr + ModBuiltin.SIZE; - return (); - - // Compute X - Y - add_offsets: - dw 4; // X - dw 8; // Y - dw 12; - - mul_offsets: - // Assert (X+Y)*(X+Y)^-1 == 1 ==> (X+Y) != 0 - dw 12; // [X+Y] - dw 16; // [X+Y]^-1 - dw 0; -} - -// Returns 1 if X == -Y mod p, 0 otherwise. -func is_opposite_mod_p{ - range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin* -}(x: UInt384, y: UInt384, p: UInt384) -> (res: felt) { - %{ - from garaga.hints.io import bigint_pack - x = bigint_pack(ids.x, 4, 2**96) - y = bigint_pack(ids.y, 4, 2**96) - p = bigint_pack(ids.p, 4, 2**96) - %} - if (nondet %{ x % p == -y % p %} != 0) { - assert_opposite_mod_p(x, y, p); - return (res=1); - } else { - assert_not_opposite_mod_p(x, y, p); - return (res=0); - } -} diff --git a/cairo/src/utils/circuit_utils.cairo b/cairo/src/utils/circuit_utils.cairo index 5bb08fdf..5f0c68d1 100644 --- a/cairo/src/utils/circuit_utils.cairo +++ b/cairo/src/utils/circuit_utils.cairo @@ -6,19 +6,12 @@ from starkware.cairo.common.registers import get_fp_and_pc, get_label_location from starkware.cairo.common.math import assert_le_felt const N_LIMBS = 4; -const STARK_MIN_ONE_D2 = 0x800000000000011; func hash_full_transcript_and_get_Z_3_LIMBS{poseidon_ptr: PoseidonBuiltin*}( limbs_ptr: felt*, n: felt ) -> (_s0: felt, _s1: felt, _s2: felt) { alloc_locals; local BASE = 2 ** 96; - // %{ - // from garaga.hints.io import pack_bigint_ptr - // to_hash=pack_bigint_ptr(memory, ids.limbs_ptr, ids.N_LIMBS, ids.BASE, ids.n) - // for e in to_hash: - // print(f"Will Hash {hex(e)}") - // %} let elements_end = &limbs_ptr[n * N_LIMBS]; @@ -27,13 +20,6 @@ func hash_full_transcript_and_get_Z_3_LIMBS{poseidon_ptr: PoseidonBuiltin*}( loop: if (nondet %{ ids.elements_end - ids.elements >= 6*ids.N_LIMBS %} != 0) { - // %{ - // from garaga.hints.io import pack_bigint_ptr - // to_hash=pack_bigint_ptr(memory, ids.elements, ids.N_LIMBS, ids.BASE, 6) - // for e in to_hash: - // print(f"\t Will Hash {hex(e)}") - // %} - assert [pos_ptr + 0] = [pos_ptr - 3] + elements[0] + (BASE) * elements[1]; assert [pos_ptr + 1] = [pos_ptr - 2] + elements[2]; assert [pos_ptr + 2] = [pos_ptr - 1]; @@ -65,12 +51,6 @@ func hash_full_transcript_and_get_Z_3_LIMBS{poseidon_ptr: PoseidonBuiltin*}( } if (nondet %{ ids.elements_end - ids.elements >= ids.N_LIMBS %} != 0) { - // %{ - // from garaga.hints.io import pack_bigint_ptr - // to_hash=pack_bigint_ptr(memory, ids.elements, ids.N_LIMBS, ids.BASE, 1) - // for e in to_hash: - // print(f"\t\t Will Hash {e}") - // %} assert [pos_ptr + 0] = [pos_ptr - 3] + elements[0] + (BASE) * elements[1]; assert [pos_ptr + 1] = [pos_ptr - 2] + elements[2]; assert [pos_ptr + 2] = [pos_ptr - 1]; @@ -194,31 +174,6 @@ func scalar_to_epns{range_check_ptr}(scalar: felt) -> ( return (p_sign * sum_p, n_sign * sum_n, p_sign, n_sign); } -func felt_to_UInt384{range_check96_ptr: felt*}(x: felt) -> (res: UInt384) { - let d0 = [range_check96_ptr]; - let d1 = [range_check96_ptr + 1]; - let d2 = [range_check96_ptr + 2]; - %{ - from garaga.hints.io import bigint_split - limbs = bigint_split(ids.x, 4, 2 ** 96) - assert limbs[3] == 0 - ids.d0, ids.d1, ids.d2 = limbs[0], limbs[1], limbs[2] - %} - assert [range_check96_ptr + 3] = STARK_MIN_ONE_D2 - d2; - assert x = d0 + d1 * 2 ** 96 + d2 * 2 ** 192; - - if (d2 == STARK_MIN_ONE_D2) { - // STARK_MIN_ONE = 0x800000000000011000000000000000000000000000000000000000000000000 - // So d0 = 0, d1 = 0, d2 = 0x800000000000011 - // If d2 == STARK_MIN_ONE_D2, then d0 == 0 and d1 == 0 - assert d0 = 0; - assert d1 = 0; - } - - tempvar range_check96_ptr = range_check96_ptr + 4; - return (res=UInt384(d0, d1, d2, 0)); -} - func run_modulo_circuit_basic{ range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin* }( diff --git a/cairo/src/utils/signature.cairo b/cairo/src/utils/signature.cairo index 30611609..f80fedcc 100644 --- a/cairo/src/utils/signature.cairo +++ b/cairo/src/utils/signature.cairo @@ -15,13 +15,10 @@ from starkware.cairo.common.uint256 import Uint256 from starkware.cairo.common.alloc import alloc from src.utils.maths import unsigned_div_rem -from src.interfaces.interfaces import ICairo1Helpers -from src.utils.circuit_basic_field_ops import div_mod_p, neg_mod_p, is_opposite_mod_p, is_eq_mod_p from src.utils.circuit_utils import ( N_LIMBS, hash_full_transcript_and_get_Z_3_LIMBS, scalar_to_epns, - felt_to_UInt384, run_modulo_circuit_basic, ) from src.utils.ecdsa_circuit import ( @@ -30,7 +27,15 @@ from src.utils.ecdsa_circuit import ( get_DOUBLE_EC_POINT_circuit, ) from src.utils.uint256 import assert_uint256_le -from src.utils.uint384 import uint384_to_uint256, uint256_to_uint384 +from src.utils.uint384 import ( + uint384_to_uint256, + uint256_to_uint384, + uint384_eq_mod_p, + uint384_is_neg_mod_p, + uint384_div_mod_p, + uint384_neg_mod_p, + felt_to_uint384, +) from src.curve.secp256k1 import secp256k1, get_generator_point from src.curve.g1_point import G1Point @@ -186,7 +191,7 @@ func get_point_from_x_secp256k1{ }(x: felt, attempt: felt) -> (res: G1Point) { alloc_locals; let (local res: G1Point*) = alloc(); - let (x_384: UInt384) = felt_to_UInt384(x); + let (x_384: UInt384) = felt_to_uint384(x); let (is_on_curve) = try_get_point_from_x_secp256k1(x=x_384, v=0, result=res); @@ -299,9 +304,9 @@ namespace Signature { let N = UInt384(secp256k1.N0, secp256k1.N1, secp256k1.N2, secp256k1.N3); let N_min_one = Uint256(secp256k1.N_LOW_128 - 1, secp256k1.N_HIGH_128); - let (_u1: UInt384) = div_mod_p(msg_hash, r, N); - let (_u1: UInt384) = neg_mod_p(_u1, N); - let (_u2: UInt384) = div_mod_p(s, r, N); + let _u1 = uint384_div_mod_p(msg_hash, r, N); + let _u1 = uint384_neg_mod_p(_u1, N); + let _u2 = uint384_div_mod_p(s, r, N); let u1 = uint384_to_uint256(_u1); assert_uint256_le(u1, N_min_one); @@ -311,26 +316,26 @@ namespace Signature { let (ep1_low, en1_low, sp1_low, sn1_low) = scalar_to_epns(u1.low); let (ep1_high, en1_high, sp1_high, sn1_high) = scalar_to_epns(u1.high); - let (ep1_low_384) = felt_to_UInt384(ep1_low); - let (en1_low_384) = felt_to_UInt384(en1_low); + let (ep1_low_384) = felt_to_uint384(ep1_low); + let (en1_low_384) = felt_to_uint384(en1_low); let sp1_low_384 = sign_to_uint384_mod_secp256k1(sp1_low); let sn1_low_384 = sign_to_uint384_mod_secp256k1(sn1_low); - let (ep1_high_384) = felt_to_UInt384(ep1_high); - let (en1_high_384) = felt_to_UInt384(en1_high); + let (ep1_high_384) = felt_to_uint384(ep1_high); + let (en1_high_384) = felt_to_uint384(en1_high); let sp1_high_384 = sign_to_uint384_mod_secp256k1(sp1_high); let sn1_high_384 = sign_to_uint384_mod_secp256k1(sn1_high); let (ep2_low, en2_low, sp2_low, sn2_low) = scalar_to_epns(u2.low); - let (ep2_low_384) = felt_to_UInt384(ep2_low); - let (en2_low_384) = felt_to_UInt384(en2_low); + let (ep2_low_384) = felt_to_uint384(ep2_low); + let (en2_low_384) = felt_to_uint384(en2_low); let sp2_low_384 = sign_to_uint384_mod_secp256k1(sp2_low); let sn2_low_384 = sign_to_uint384_mod_secp256k1(sn2_low); let (ep2_high, en2_high, sp2_high, sn2_high) = scalar_to_epns(u2.high); - let (ep2_high_384) = felt_to_UInt384(ep2_high); - let (en2_high_384) = felt_to_UInt384(en2_high); + let (ep2_high_384) = felt_to_uint384(ep2_high); + let (en2_high_384) = felt_to_uint384(en2_high); let sp2_high_384 = sign_to_uint384_mod_secp256k1(sp2_high); let sn2_high_384 = sign_to_uint384_mod_secp256k1(sn2_high); let generator_point = get_generator_point(); @@ -414,7 +419,7 @@ namespace Signature { tempvar rlc_coeff = poseidon_ptr[1].output.s1 + 0; let poseidon_ptr = poseidon_ptr + 2 * PoseidonBuiltin.SIZE; %{ print(f"CAIRORLC: {hex(ids.rlc_coeff)}") %} - let (rlc_coeff_u384) = felt_to_UInt384(rlc_coeff); + let (rlc_coeff_u384) = felt_to_uint384(rlc_coeff); // Hash sumdlogdiv 2 points : (4-29) let (_random_x_coord, _, _) = hash_full_transcript_and_get_Z_3_LIMBS( @@ -581,10 +586,10 @@ func add_ec_points_secp256k1{ alloc_locals; let (__fp__, _) = get_fp_and_pc(); let modulus = UInt384(secp256k1.P0, secp256k1.P1, secp256k1.P2, secp256k1.P3); - let (same_x) = is_eq_mod_p(P.x, Q.x, modulus); + let same_x = uint384_eq_mod_p(P.x, Q.x, modulus); if (same_x != 0) { - let (opposite_y) = is_opposite_mod_p(P.y, Q.y, modulus); + let opposite_y = uint384_is_neg_mod_p(P.y, Q.y, modulus); if (opposite_y != 0) { // P + (-P) = O (point at infinity) diff --git a/cairo/src/utils/uint384.cairo b/cairo/src/utils/uint384.cairo index 4b48c2e2..cf045a2c 100644 --- a/cairo/src/utils/uint384.cairo +++ b/cairo/src/utils/uint384.cairo @@ -1,7 +1,36 @@ -from starkware.cairo.common.cairo_builtins import UInt384 +from starkware.cairo.common.cairo_builtins import UInt384, ModBuiltin +from starkware.cairo.lang.compiler.lib.registers import get_fp_and_pc from starkware.cairo.common.uint256 import Uint256 from ethereum.utils.numeric import divmod +const STARK_MIN_ONE_D2 = 0x800000000000011; + +func felt_to_uint384{range_check96_ptr: felt*}(x: felt) -> UInt384 { + let d0 = [range_check96_ptr]; + let d1 = [range_check96_ptr + 1]; + let d2 = [range_check96_ptr + 2]; + %{ + from garaga.hints.io import bigint_split + limbs = bigint_split(ids.x, 4, 2 ** 96) + assert limbs[3] == 0 + ids.d0, ids.d1, ids.d2 = limbs[0], limbs[1], limbs[2] + %} + assert [range_check96_ptr + 3] = STARK_MIN_ONE_D2 - d2; + assert x = d0 + d1 * 2 ** 96 + d2 * 2 ** 192; + + if (d2 == STARK_MIN_ONE_D2) { + // STARK_MIN_ONE = 0x800000000000011000000000000000000000000000000000000000000000000 + // So d0 = 0, d1 = 0, d2 = 0x800000000000011 + // If d2 == STARK_MIN_ONE_D2, then d0 == 0 and d1 == 0 + assert d0 = 0; + assert d1 = 0; + } + + tempvar range_check96_ptr = range_check96_ptr + 4; + let res = UInt384(d0, d1, d2, 0); + return res; +} + // @notice Converts a 256-bit unsigned integer to a 384-bit unsigned integer. // @param a The 256-bit unsigned integer. // @return res The resulting 384-bit unsigned integer. @@ -28,7 +57,7 @@ func uint384_to_uint256{range_check_ptr}(a: UInt384) -> Uint256 { // @notice Asserts that a 384-bit unsigned integer is less than or equal to another 384-bit unsigned integer. // @param a The first 384-bit unsigned integer. // @param b The second 384-bit unsigned integer. -func assert_uint384_le{range_check96_ptr: felt*}(a: UInt384, b: UInt384) { +func uint384_assert_le{range_check96_ptr: felt*}(a: UInt384, b: UInt384) { assert [range_check96_ptr + 0] = b.d3 - a.d3; if (b.d3 != a.d3) { let range_check96_ptr = range_check96_ptr + 1; @@ -48,3 +77,351 @@ func assert_uint384_le{range_check96_ptr: felt*}(a: UInt384, b: UInt384) { let range_check96_ptr = range_check96_ptr + 4; return (); } + +// Assert X == Y mod p by asserting X + 0 == Y +func uint384_assert_eq_mod_p{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*}( + x: UInt384, y: UInt384, p: UInt384 +) { + let (_, pc) = get_fp_and_pc(); + + pc_label: + let add_offsets_ptr = pc + (add_offsets - pc_label); + + // 0 (4) + assert [range_check96_ptr + 0] = 0; + assert [range_check96_ptr + 1] = 0; + assert [range_check96_ptr + 2] = 0; + assert [range_check96_ptr + 3] = 0; + // X limbs (4) + assert [range_check96_ptr + 4] = x.d0; + assert [range_check96_ptr + 5] = x.d1; + assert [range_check96_ptr + 6] = x.d2; + assert [range_check96_ptr + 7] = x.d3; + // Y limbs (8) + assert [range_check96_ptr + 8] = y.d0; + assert [range_check96_ptr + 9] = y.d1; + assert [range_check96_ptr + 10] = y.d2; + assert [range_check96_ptr + 11] = y.d3; + + assert add_mod_ptr[0] = ModBuiltin( + p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=add_offsets_ptr, n=1 + ); + %{ + from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner + assert builtin_runners["add_mod_builtin"].instance_def.batch_size == 1 + + ModBuiltinRunner.fill_memory( + memory=memory, + add_mod=(ids.add_mod_ptr.address_, builtin_runners["add_mod_builtin"], 1), + mul_mod=None, + ) + %} + let range_check96_ptr = range_check96_ptr + 12; + let add_mod_ptr = add_mod_ptr + ModBuiltin.SIZE; + return (); + + add_offsets: + dw 0; // X + dw 4; // 0 + dw 8; // X + 0 = Y +} + +// @notice assert X != Y mod p by asserting (X-Y) != 0 +// @dev Uses the add_mod builtin to compute X-Y % P, then mul_mod builtin to compute (X-Y)^-1 % P +func uint384_assert_neq_mod_p{ + range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin* +}(x: UInt384, y: UInt384, p: UInt384) { + let (_, pc) = get_fp_and_pc(); + + pc_label: + let add_offsets_ptr = pc + (add_offsets - pc_label); + let mul_offsets_ptr = pc + (mul_offsets - pc_label); + // X limbs. (0) + assert [range_check96_ptr + 0] = x.d0; + assert [range_check96_ptr + 1] = x.d1; + assert [range_check96_ptr + 2] = x.d2; + assert [range_check96_ptr + 3] = x.d3; + // Y limbs. (4) + assert [range_check96_ptr + 4] = y.d0; + assert [range_check96_ptr + 5] = y.d1; + assert [range_check96_ptr + 6] = y.d2; + assert [range_check96_ptr + 7] = y.d3; + // X-Y % P (8) + + // 1 (12) + assert [range_check96_ptr + 12] = 1; + assert [range_check96_ptr + 13] = 0; + assert [range_check96_ptr + 14] = 0; + assert [range_check96_ptr + 15] = 0; + // [X-Y]^-1 (16) + + assert add_mod_ptr[0] = ModBuiltin( + p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=add_offsets_ptr, n=1 + ); + assert mul_mod_ptr[0] = ModBuiltin( + p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=mul_offsets_ptr, n=1 + ); + %{ + from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner + assert builtin_runners["add_mod_builtin"].instance_def.batch_size == 1 + assert builtin_runners["mul_mod_builtin"].instance_def.batch_size == 1 + + ModBuiltinRunner.fill_memory( + memory=memory, + add_mod=(ids.add_mod_ptr.address_, builtin_runners["add_mod_builtin"], 1), + mul_mod=(ids.mul_mod_ptr.address_, builtin_runners["mul_mod_builtin"], 1), + ) + %} + let range_check96_ptr = range_check96_ptr + 20; + let add_mod_ptr = add_mod_ptr + ModBuiltin.SIZE; + let mul_mod_ptr = mul_mod_ptr + ModBuiltin.SIZE; + return (); + + add_offsets: + dw 4; // a = Y + dw 8; // b = X - Y + dw 0; // a + b = X + + mul_offsets: + dw 8; // a = X-Y + dw 16; // b = (X-Y)^-1 + dw 12; // a * b = 1 +} + +// Returns 1 if X == Y mod p, 0 otherwise. +func uint384_eq_mod_p{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin*}( + x: UInt384, y: UInt384, p: UInt384 +) -> felt { + %{ + from garaga.hints.io import bigint_pack + x = bigint_pack(ids.x, 4, 2**96) + y = bigint_pack(ids.y, 4, 2**96) + p = bigint_pack(ids.p, 4, 2**96) + %} + + if (nondet %{ x % p == y % p %} != 0) { + uint384_assert_eq_mod_p(x, y, p); + return 1; + } else { + uint384_assert_neq_mod_p(x, y, p); + return 0; + } +} + +// Assert X == - Y mod p by asserting X + Y == 0 +func uint384_assert_neg_mod_p{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*}( + x: UInt384, y: UInt384, p: UInt384 +) { + let (_, pc) = get_fp_and_pc(); + + pc_label: + let add_offsets_ptr = pc + (add_offsets - pc_label); + + // X limbs. + assert [range_check96_ptr + 0] = x.d0; + assert [range_check96_ptr + 1] = x.d1; + assert [range_check96_ptr + 2] = x.d2; + assert [range_check96_ptr + 3] = x.d3; + // Y limbs. + assert [range_check96_ptr + 4] = y.d0; + assert [range_check96_ptr + 5] = y.d1; + assert [range_check96_ptr + 6] = y.d2; + assert [range_check96_ptr + 7] = y.d3; + // 0 + assert [range_check96_ptr + 8] = 0; + assert [range_check96_ptr + 9] = 0; + assert [range_check96_ptr + 10] = 0; + assert [range_check96_ptr + 11] = 0; + + assert add_mod_ptr[0] = ModBuiltin( + p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=add_offsets_ptr, n=1 + ); + %{ + from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner + assert builtin_runners["add_mod_builtin"].instance_def.batch_size == 1 + + ModBuiltinRunner.fill_memory( + memory=memory, + add_mod=(ids.add_mod_ptr.address_, builtin_runners["add_mod_builtin"], 1), + mul_mod=None, + ) + %} + + let range_check96_ptr = range_check96_ptr + 12; + let add_mod_ptr = add_mod_ptr + ModBuiltin.SIZE; + return (); + + add_offsets: + dw 0; // X + dw 4; // Y + dw 8; // 0 +} + +// assert X != -Y mod p by asserting X + Y != 0 +func uint384_assert_not_neg_mod_p{ + range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin* +}(x: UInt384, y: UInt384, p: UInt384) { + let (_, pc) = get_fp_and_pc(); + + pc_label: + let add_offsets_ptr = pc + (add_offsets - pc_label); + let mul_offsets_ptr = pc + (mul_offsets - pc_label); + + // X limbs. (0) + assert [range_check96_ptr + 0] = x.d0; + assert [range_check96_ptr + 1] = x.d1; + assert [range_check96_ptr + 2] = x.d2; + assert [range_check96_ptr + 3] = x.d3; + // Y limbs. (4) + assert [range_check96_ptr + 4] = y.d0; + assert [range_check96_ptr + 5] = y.d1; + assert [range_check96_ptr + 6] = y.d2; + assert [range_check96_ptr + 7] = y.d3; + // X + Y (8) + // [X+Y]^-1 (12) + + // 1 (16) + assert [range_check96_ptr + 16] = 1; + assert [range_check96_ptr + 17] = 0; + assert [range_check96_ptr + 18] = 0; + assert [range_check96_ptr + 19] = 0; + + assert add_mod_ptr[0] = ModBuiltin( + p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=add_offsets_ptr, n=1 + ); + assert mul_mod_ptr[0] = ModBuiltin( + p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=mul_offsets_ptr, n=1 + ); + %{ + from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner + assert builtin_runners["add_mod_builtin"].instance_def.batch_size == 1 + assert builtin_runners["mul_mod_builtin"].instance_def.batch_size == 1 + + ModBuiltinRunner.fill_memory( + memory=memory, + add_mod=(ids.add_mod_ptr.address_, builtin_runners["add_mod_builtin"], 1), + mul_mod=(ids.mul_mod_ptr.address_, builtin_runners["mul_mod_builtin"], 1), + ) + %} + let range_check96_ptr = range_check96_ptr + 20; + let add_mod_ptr = add_mod_ptr + ModBuiltin.SIZE; + let mul_mod_ptr = mul_mod_ptr + ModBuiltin.SIZE; + return (); + + add_offsets: + dw 0; // X + dw 4; // Y + dw 8; // X + Y + + mul_offsets: + dw 8; // X + Y + dw 12; // [X+Y]^-1 + dw 16; // 1 +} + +// Returns 1 if X == -Y mod p, 0 otherwise. +func uint384_is_neg_mod_p{ + range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin* +}(x: UInt384, y: UInt384, p: UInt384) -> felt { + %{ + from garaga.hints.io import bigint_pack + x = bigint_pack(ids.x, 4, 2**96) + y = bigint_pack(ids.y, 4, 2**96) + p = bigint_pack(ids.p, 4, 2**96) + %} + if (nondet %{ x % p == -y % p %} != 0) { + uint384_assert_neg_mod_p(x, y, p); + return 1; + } else { + uint384_assert_not_neg_mod_p(x, y, p); + return 0; + } +} + +// Compute X / Y mod p. +func uint384_div_mod_p{range_check96_ptr: felt*, mul_mod_ptr: ModBuiltin*}( + x: UInt384, y: UInt384, p: UInt384 +) -> UInt384 { + let (_, pc) = get_fp_and_pc(); + + pc_label: + let mul_offsets_ptr = pc + (mul_offsets - pc_label); + + // X limbs (offset 0) + assert [range_check96_ptr + 0] = x.d0; + assert [range_check96_ptr + 1] = x.d1; + assert [range_check96_ptr + 2] = x.d2; + assert [range_check96_ptr + 3] = x.d3; + // Y limbs (offset 4) + assert [range_check96_ptr + 4] = y.d0; + assert [range_check96_ptr + 5] = y.d1; + assert [range_check96_ptr + 6] = y.d2; + assert [range_check96_ptr + 7] = y.d3; + + assert mul_mod_ptr[0] = ModBuiltin( + p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=mul_offsets_ptr, n=1 + ); + %{ + from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner + assert builtin_runners["mul_mod_builtin"].instance_def.batch_size == 1 + + ModBuiltinRunner.fill_memory( + memory=memory, + add_mod=None, + mul_mod=(ids.mul_mod_ptr.address_, builtin_runners["mul_mod_builtin"], 1), + ) + %} + + let range_check96_ptr = range_check96_ptr + 12; + let mul_mod_ptr = mul_mod_ptr + ModBuiltin.SIZE; + return [cast(range_check96_ptr - 4, UInt384*)]; + + mul_offsets: + dw 4; // Y + dw 8; // X/Y + dw 0; // X +} + +// Compute - Y mod p. +func uint384_neg_mod_p{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*}( + y: UInt384, p: UInt384 +) -> UInt384 { + let (_, pc) = get_fp_and_pc(); + + pc_label: + let add_offsets_ptr = pc + (add_offsets - pc_label); + + // X limbs (offset 0) + assert [range_check96_ptr] = 0; + assert [range_check96_ptr + 1] = 0; + assert [range_check96_ptr + 2] = 0; + assert [range_check96_ptr + 3] = 0; + // Y limbs (offset 4) + assert [range_check96_ptr + 4] = y.d0; + assert [range_check96_ptr + 5] = y.d1; + assert [range_check96_ptr + 6] = y.d2; + assert [range_check96_ptr + 7] = y.d3; + + assert add_mod_ptr[0] = ModBuiltin( + p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=add_offsets_ptr, n=1 + ); + %{ + from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner + assert builtin_runners["add_mod_builtin"].instance_def.batch_size == 1 + + ModBuiltinRunner.fill_memory( + memory=memory, + add_mod=(ids.add_mod_ptr.address_, builtin_runners["add_mod_builtin"], 1), + mul_mod=None, + ) + %} + + let range_check96_ptr = range_check96_ptr + 12; + let add_mod_ptr = add_mod_ptr + ModBuiltin.SIZE; + return [cast(range_check96_ptr - 4, UInt384*)]; + + add_offsets: + dw 4; // Y + dw 8; // -Y + dw 0; // 0 +} diff --git a/cairo/tests/src/utils/test_uint384.cairo b/cairo/tests/src/utils/test_uint384.cairo index 0104c7f6..1eae51ff 100644 --- a/cairo/tests/src/utils/test_uint384.cairo +++ b/cairo/tests/src/utils/test_uint384.cairo @@ -1,8 +1,21 @@ -from starkware.cairo.common.cairo_builtins import HashBuiltin, UInt384 +from starkware.cairo.common.cairo_builtins import HashBuiltin, UInt384, ModBuiltin from starkware.cairo.common.uint256 import Uint256 from starkware.cairo.common.alloc import alloc -from src.utils.uint384 import assert_uint384_le, uint384_to_uint256, uint256_to_uint384 +from src.utils.uint384 import ( + uint384_assert_le, + uint384_to_uint256, + uint256_to_uint384, + uint384_assert_neq_mod_p, + uint384_assert_eq_mod_p, + uint384_eq_mod_p, + uint384_assert_neg_mod_p, + uint384_assert_not_neg_mod_p, + uint384_is_neg_mod_p, + uint384_div_mod_p, + uint384_neg_mod_p, + felt_to_uint384, +) func test__uint256_to_uint384{range_check_ptr}() -> UInt384 { alloc_locals; @@ -21,7 +34,7 @@ func test__uint384_to_uint256{range_check_ptr}() -> Uint256 { return res; } -func test__assert_uint384_le{range_check96_ptr: felt*}() { +func test__uint384_assert_le{range_check96_ptr: felt*}() { alloc_locals; let (a_ptr) = alloc(); let (b_ptr) = alloc(); @@ -29,7 +42,147 @@ func test__assert_uint384_le{range_check96_ptr: felt*}() { segments.write_arg(ids.a_ptr, program_input["a"]) segments.write_arg(ids.b_ptr, program_input["b"]) %} - assert_uint384_le([cast(a_ptr, UInt384*)], [cast(b_ptr, UInt384*)]); + uint384_assert_le([cast(a_ptr, UInt384*)], [cast(b_ptr, UInt384*)]); return (); } + +func test__uint384_assert_eq_mod_p{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*}() { + alloc_locals; + let (x_ptr) = alloc(); + let (y_ptr) = alloc(); + let (p_ptr) = alloc(); + %{ + segments.write_arg(ids.x_ptr, program_input["x"]) + segments.write_arg(ids.y_ptr, program_input["y"]) + segments.write_arg(ids.p_ptr, program_input["p"]) + %} + uint384_assert_eq_mod_p( + [cast(x_ptr, UInt384*)], [cast(y_ptr, UInt384*)], [cast(p_ptr, UInt384*)] + ); + return (); +} + +func test__uint384_assert_neq_mod_p{ + range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin* +}() { + alloc_locals; + let (x_ptr) = alloc(); + let (y_ptr) = alloc(); + let (p_ptr) = alloc(); + %{ + segments.write_arg(ids.x_ptr, program_input["x"]) + segments.write_arg(ids.y_ptr, program_input["y"]) + segments.write_arg(ids.p_ptr, program_input["p"]) + %} + uint384_assert_neq_mod_p( + [cast(x_ptr, UInt384*)], [cast(y_ptr, UInt384*)], [cast(p_ptr, UInt384*)] + ); + return (); +} + +func test__uint384_eq_mod_p{ + range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin* +}() -> felt { + alloc_locals; + let (x_ptr) = alloc(); + let (y_ptr) = alloc(); + let (p_ptr) = alloc(); + %{ + segments.write_arg(ids.x_ptr, program_input["x"]) + segments.write_arg(ids.y_ptr, program_input["y"]) + segments.write_arg(ids.p_ptr, program_input["p"]) + %} + let res = uint384_eq_mod_p( + [cast(x_ptr, UInt384*)], [cast(y_ptr, UInt384*)], [cast(p_ptr, UInt384*)] + ); + return res; +} + +func test__uint384_assert_neg_mod_p{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*}() { + alloc_locals; + let (x_ptr) = alloc(); + let (y_ptr) = alloc(); + let (p_ptr) = alloc(); + %{ + segments.write_arg(ids.x_ptr, program_input["x"]) + segments.write_arg(ids.y_ptr, program_input["y"]) + segments.write_arg(ids.p_ptr, program_input["p"]) + %} + uint384_assert_neg_mod_p( + [cast(x_ptr, UInt384*)], [cast(y_ptr, UInt384*)], [cast(p_ptr, UInt384*)] + ); + return (); +} + +func test__uint384_assert_not_neg_mod_p{ + range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin* +}() { + alloc_locals; + let (x_ptr) = alloc(); + let (y_ptr) = alloc(); + let (p_ptr) = alloc(); + %{ + segments.write_arg(ids.x_ptr, program_input["x"]) + segments.write_arg(ids.y_ptr, program_input["y"]) + segments.write_arg(ids.p_ptr, program_input["p"]) + %} + uint384_assert_not_neg_mod_p( + [cast(x_ptr, UInt384*)], [cast(y_ptr, UInt384*)], [cast(p_ptr, UInt384*)] + ); + return (); +} + +func test__uint384_is_neg_mod_p{ + range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin* +}() -> felt { + alloc_locals; + let (x_ptr) = alloc(); + let (y_ptr) = alloc(); + let (p_ptr) = alloc(); + %{ + segments.write_arg(ids.x_ptr, program_input["x"]) + segments.write_arg(ids.y_ptr, program_input["y"]) + segments.write_arg(ids.p_ptr, program_input["p"]) + %} + let res = uint384_is_neg_mod_p( + [cast(x_ptr, UInt384*)], [cast(y_ptr, UInt384*)], [cast(p_ptr, UInt384*)] + ); + return res; +} + +func test__uint384_div_mod_p{range_check96_ptr: felt*, mul_mod_ptr: ModBuiltin*}() -> UInt384 { + alloc_locals; + let (x_ptr) = alloc(); + let (y_ptr) = alloc(); + let (p_ptr) = alloc(); + %{ + segments.write_arg(ids.x_ptr, program_input["x"]) + segments.write_arg(ids.y_ptr, program_input["y"]) + segments.write_arg(ids.p_ptr, program_input["p"]) + %} + let res = uint384_div_mod_p( + [cast(x_ptr, UInt384*)], [cast(y_ptr, UInt384*)], [cast(p_ptr, UInt384*)] + ); + return res; +} + +func test__uint384_neg_mod_p{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*}() -> UInt384 { + alloc_locals; + let (y_ptr) = alloc(); + let (p_ptr) = alloc(); + %{ + segments.write_arg(ids.y_ptr, program_input["y"]) + segments.write_arg(ids.p_ptr, program_input["p"]) + %} + let res = uint384_neg_mod_p([cast(y_ptr, UInt384*)], [cast(p_ptr, UInt384*)]); + return res; +} + +func test__felt_to_uint384{range_check96_ptr: felt*}() -> UInt384 { + alloc_locals; + tempvar x; + %{ ids.x = program_input["x"] %} + let res = felt_to_uint384(x); + return res; +} diff --git a/cairo/tests/src/utils/test_uint384.py b/cairo/tests/src/utils/test_uint384.py index 63c50846..befa232f 100644 --- a/cairo/tests/src/utils/test_uint384.py +++ b/cairo/tests/src/utils/test_uint384.py @@ -1,7 +1,9 @@ import pytest -from hypothesis import given -from hypothesis.strategies import integers +from hypothesis import assume, given +from hypothesis import strategies as st +from starkware.cairo.lang.cairo_constants import DEFAULT_PRIME +from ethereum.crypto.elliptic_curve import SECP256K1N from src.utils.uint256 import int_to_uint256, uint256_to_int from src.utils.uint384 import int_to_uint384, uint384_to_int @@ -11,36 +13,242 @@ class TestUint384: class TestUint256ToUint384: - @given(a=integers(min_value=0, max_value=2**256 - 1)) - def test_should_pass_if_fits_in_256_bits(self, cairo_run, a): + @given(a=st.integers(min_value=0, max_value=2**256 - 1)) + def test_should_pass(self, cairo_run, a): res = cairo_run("test__uint256_to_uint384", a=int_to_uint256(a)) assert uint384_to_int(res["d0"], res["d1"], res["d2"], res["d3"]) == a class TestUint384ToUint256: - @given(a=integers(min_value=0, max_value=2**256 - 1)) + @given(a=st.integers(min_value=0, max_value=2**256 - 1)) def test_should_pass_if_fits_in_256_bits(self, cairo_run, a): res = cairo_run("test__uint384_to_uint256", a=int_to_uint384(a)) assert uint256_to_int(res["low"], res["high"]) == a - @given(a=integers(min_value=2**256, max_value=2**384 - 1)) + @given(a=st.integers(min_value=2**256, max_value=2**384 - 1)) def test_should_fail_if_does_not_fit_in_256_bits(self, cairo_run, a): with pytest.raises(Exception): cairo_run("test__uint384_to_uint256", a=int_to_uint384(a)) class TestAssertUint384Le: @given( - a=integers(min_value=0, max_value=2**384 - 1), - b=integers(min_value=0, max_value=2**384 - 1), + a=st.integers(min_value=0, max_value=2**384 - 1), + b=st.integers(min_value=0, max_value=2**384 - 1), ) - def test_assert_uint384_le(self, cairo_run, a, b): + def test_uint384_assert_le(self, cairo_run, a, b): if a > b: with pytest.raises(Exception): cairo_run( - "test__assert_uint384_le", + "test__uint384_assert_le", a=int_to_uint384(a), b=int_to_uint384(b), ) else: cairo_run( - "test__assert_uint384_le", a=int_to_uint384(a), b=int_to_uint384(b) + "test__uint384_assert_le", a=int_to_uint384(a), b=int_to_uint384(b) + ) + + class TestAssertNeqModP: + @given( + x=st.integers(min_value=0, max_value=2**384 - 1), + y=st.integers(min_value=0, max_value=2**384 - 1), + p=st.one_of(st.just(DEFAULT_PRIME), st.just(int(SECP256K1N))), + ) + def test_should_pass_if_x_neq_y_mod_p(self, cairo_run, x, y, p): + diff = (x - y) % p + assume(diff != 0) + assume(pow(diff, -1, p)) + cairo_run( + "test__uint384_assert_neq_mod_p", + x=int_to_uint384(x % p), + y=int_to_uint384(y % p), + p=int_to_uint384(p), + ) + + @given( + x=st.integers(min_value=0, max_value=2**384 - 1), + p=st.one_of(st.just(DEFAULT_PRIME), st.just(int(SECP256K1N))), + ) + def test_should_fail_if_x_eq_y_mod_p(self, cairo_run, x, p): + with pytest.raises(Exception): + cairo_run( + "test__uint384_assert_neq_mod_p", + x=int_to_uint384(x % p), + y=int_to_uint384(x % p), + p=int_to_uint384(p), + ) + + class TestAssertEqModP: + @given( + x=st.integers(min_value=0, max_value=2**384 - 1), + y=st.integers(min_value=0, max_value=2**384 - 1), + p=st.one_of(st.just(DEFAULT_PRIME), st.just(int(SECP256K1N))), + ) + def test_should_fail_if_x_neq_y_mod_p(self, cairo_run, x, y, p): + diff = (x - y) % p + assume(diff != 0) + assume(pow(diff, -1, p)) + with pytest.raises(Exception): + cairo_run( + "test__uint384_assert_eq_mod_p", + x=int_to_uint384(x % p), + y=int_to_uint384(y % p), + p=int_to_uint384(p), + ) + + @given( + x=st.integers(min_value=0, max_value=2**384 - 1), + p=st.one_of(st.just(DEFAULT_PRIME), st.just(int(SECP256K1N))), + ) + def test_should_pass_if_x_eq_y_mod_p(self, cairo_run, x, p): + cairo_run( + "test__uint384_assert_eq_mod_p", + x=int_to_uint384(x % p), + y=int_to_uint384(x % p), + p=int_to_uint384(p), + ) + + class TestEqModP: + @given( + x=st.integers(min_value=0, max_value=2**384 - 1), + y=st.integers(min_value=0, max_value=2**384 - 1), + p=st.one_of(st.just(DEFAULT_PRIME), st.just(int(SECP256K1N))), + ) + def test_should_return_false_if_x_neq_y_mod_p(self, cairo_run, x, y, p): + assume(x % p != y % p) + assert not cairo_run( + "test__uint384_eq_mod_p", + x=int_to_uint384(x % p), + y=int_to_uint384(y % p), + p=int_to_uint384(p), + ) + + @given( + x=st.integers(min_value=0, max_value=2**384 - 1), + p=st.one_of(st.just(DEFAULT_PRIME), st.just(int(SECP256K1N))), + ) + def test_should_return_true_if_x_eq_y_mod_p(self, cairo_run, x, p): + assert cairo_run( + "test__uint384_eq_mod_p", + x=int_to_uint384(x % p), + y=int_to_uint384(x % p), + p=int_to_uint384(p), + ) + + class TestAssertNegModP: + @given( + x=st.integers(min_value=0, max_value=2**384 - 1), + p=st.one_of(st.just(DEFAULT_PRIME), st.just(int(SECP256K1N))), + ) + def test_should_pass_if_x_eq_neg_y_mod_p(self, cairo_run, x, p): + cairo_run( + "test__uint384_assert_neg_mod_p", + x=int_to_uint384(x % p), + y=int_to_uint384(-x % p), + p=int_to_uint384(p), + ) + + @given( + x=st.integers(min_value=0, max_value=2**384 - 1), + y=st.integers(min_value=0, max_value=2**384 - 1), + p=st.one_of(st.just(DEFAULT_PRIME), st.just(int(SECP256K1N))), + ) + def test_should_fail_if_x_neq_neg_y_mod_p(self, cairo_run, x, y, p): + assume(x % p != -y % p) + with pytest.raises(Exception): + cairo_run( + "test__uint384_assert_neg_mod_p", + x=int_to_uint384(x % p), + y=int_to_uint384(y % p), + p=int_to_uint384(p), + ) + + class TestAssertNotNegModP: + @given( + x=st.integers(min_value=0, max_value=2**384 - 1), + y=st.integers(min_value=0, max_value=2**384 - 1), + p=st.one_of(st.just(DEFAULT_PRIME), st.just(int(SECP256K1N))), + ) + def test_should_pass_if_x_neq_neg_y_mod_p(self, cairo_run, x, y, p): + assume(x % p != -y % p) + cairo_run( + "test__uint384_assert_not_neg_mod_p", + x=int_to_uint384(x % p), + y=int_to_uint384(y % p), + p=int_to_uint384(p), + ) + + @given( + x=st.integers(min_value=0, max_value=2**384 - 1), + p=st.one_of(st.just(DEFAULT_PRIME), st.just(int(SECP256K1N))), + ) + def test_should_fail_if_x_eq_neg_y_mod_p(self, cairo_run, x, p): + with pytest.raises(Exception): + cairo_run( + "test__uint384_assert_not_neg_mod_p", + x=int_to_uint384(x % p), + y=int_to_uint384(-x % p), + p=int_to_uint384(p), ) + + class TestIsNegModP: + @given( + x=st.integers(min_value=0, max_value=2**384 - 1), + p=st.one_of(st.just(DEFAULT_PRIME), st.just(int(SECP256K1N))), + ) + def test_should_return_true_if_x_eq_neg_y_mod_p(self, cairo_run, x, p): + assert cairo_run( + "test__uint384_is_neg_mod_p", + x=int_to_uint384(x % p), + y=int_to_uint384(-x % p), + p=int_to_uint384(p), + ) + + @given( + x=st.integers(min_value=0, max_value=2**384 - 1), + y=st.integers(min_value=0, max_value=2**384 - 1), + p=st.one_of(st.just(DEFAULT_PRIME), st.just(int(SECP256K1N))), + ) + def test_should_return_false_if_x_neq_neg_y_mod_p(self, cairo_run, x, y, p): + assume(x % p != -y % p) + assert not cairo_run( + "test__uint384_is_neg_mod_p", + x=int_to_uint384(x % p), + y=int_to_uint384(y % p), + p=int_to_uint384(p), + ) + + class TestDivModP: + @given( + x=st.integers(min_value=0, max_value=2**384 - 1), + y=st.integers(min_value=1, max_value=2**384 - 1), + p=st.one_of(st.just(DEFAULT_PRIME), st.just(int(SECP256K1N))), + ) + def test_should_pass(self, cairo_run, x, y, p): + res = cairo_run( + "test__uint384_div_mod_p", + x=int_to_uint384(x % p), + y=int_to_uint384(y % p), + p=int_to_uint384(p), + ) + y_inv = pow(y, -1, p) + assert ( + uint384_to_int(res["d0"], res["d1"], res["d2"], res["d3"]) + == (x * y_inv) % p + ) + + class TestNegModP: + @given( + y=st.integers(min_value=0, max_value=2**384 - 1), + p=st.one_of(st.just(DEFAULT_PRIME), st.just(int(SECP256K1N))), + ) + def test_should_pass(self, cairo_run, y, p): + res = cairo_run( + "test__uint384_neg_mod_p", y=int_to_uint384(y % p), p=int_to_uint384(p) + ) + assert uint384_to_int(res["d0"], res["d1"], res["d2"], res["d3"]) == -y % p + + class TestFeltToUint384: + @given(x=st.integers(min_value=0, max_value=DEFAULT_PRIME - 1)) + def test_should_pass(self, cairo_run, x): + res = cairo_run("test__felt_to_uint384", x=x) + assert uint384_to_int(res["d0"], res["d1"], res["d2"], res["d3"]) == x From aa3f1af1995672dc1964031ceda4a6929247d2a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Walter?= Date: Wed, 22 Jan 2025 15:19:40 +0100 Subject: [PATCH 10/17] Refacto try_get_point_from_x --- .vscode/settings.json | 1 + cairo/src/curve/secp256k1.cairo | 147 +++++++++++++++- cairo/src/utils/signature.cairo | 190 +++------------------ cairo/src/utils/uint256.cairo | 1 - cairo/tests/src/curve/test_secp256k1.cairo | 25 ++- cairo/tests/src/curve/test_secp256k1.py | 33 ++++ 6 files changed, 225 insertions(+), 172 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index c623d2ff..d15e2d79 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -35,6 +35,7 @@ "nodeid", "nondet", "norecursedirs", + "ntheory", "numprocesses", "ommers", "patricialization", diff --git a/cairo/src/curve/secp256k1.cairo b/cairo/src/curve/secp256k1.cairo index 3c2c95df..78c81b41 100644 --- a/cairo/src/curve/secp256k1.cairo +++ b/cairo/src/curve/secp256k1.cairo @@ -1,7 +1,10 @@ -from starkware.cairo.common.cairo_builtins import UInt384 +from starkware.cairo.common.cairo_builtins import UInt384, ModBuiltin, PoseidonBuiltin from starkware.cairo.lang.compiler.lib.registers import get_fp_and_pc +from starkware.cairo.common.registers import get_label_location +from starkware.cairo.common.modulo import run_mod_p_circuit from src.curve.g1_point import G1Point +from src.utils.uint384 import felt_to_uint384 namespace secp256k1 { const CURVE_ID = 2; @@ -58,3 +61,145 @@ func get_generator_point() -> G1Point* { dw 0x483ada7726a3c465; // y.d2 dw 0x0; // y.d3 } + +// @notice Try to get the point from x. +// @return y The y point such that (x, y) is on the curve if success is 1, otherwise (g*h, y) is on the curve +// @return is_on_curve 1 if the point is on the curve, 0 otherwise +// @dev g is the generator point and h is the hash of the message +func try_get_point_from_x{ + range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin* +}(x: UInt384, v: felt) -> (y: UInt384, is_on_curve: felt) { + alloc_locals; + let add_mod_n = 5; + let (add_offsets_ptr) = get_label_location(add_offsets_ptr_loc); + let mul_mod_n = 7; + let (mul_offsets_ptr) = get_label_location(mul_offsets_ptr_loc); + + local is_on_curve: felt; + local y_try: UInt384; + %{ + from starkware.python.math_utils import is_quad_residue + from sympy import sqrt_mod + from garaga.definitions import CURVES, CurveID + from garaga.hints.io import bigint_pack, bigint_fill + curve_id = CurveID.SECP256K1.value + a = CURVES[curve_id].a + b = CURVES[curve_id].b + p = CURVES[curve_id].p + x = bigint_pack(ids.x, 4, 2**96) + rhs = (x**3 + a*x + b) % p + ids.is_on_curve = is_quad_residue(rhs, p) + if ids.is_on_curve == 1: + square_root = sqrt_mod(rhs, p) + if ids.v % 2 == square_root % 2: + pass + else: + square_root = - square_root % p + else: + square_root = sqrt_mod(rhs*CURVES[curve_id].fp_generator, p) + + bigint_fill(square_root, ids.y_try, 4, 2**96) + %} + + assert 0 = is_on_curve * (1 - is_on_curve); // assert it's a bool + let input: UInt384* = cast(range_check96_ptr, UInt384*); + assert input[0] = UInt384(1, 0, 0, 0); // constant + assert input[1] = UInt384(0, 0, 0, 0); // constant + assert input[2] = x; + assert input[3] = UInt384(secp256k1.A0, secp256k1.A1, secp256k1.A2, secp256k1.A3); + assert input[4] = UInt384(secp256k1.B0, secp256k1.B1, secp256k1.B2, secp256k1.B3); + assert input[5] = UInt384(secp256k1.G0, secp256k1.G1, secp256k1.G2, secp256k1.G3); + assert input[6] = y_try; + assert input[7] = UInt384(is_on_curve, 0, 0, 0); + + let p = UInt384(secp256k1.P0, secp256k1.P1, secp256k1.P2, secp256k1.P3); + assert add_mod_ptr[0] = ModBuiltin( + p=p, values_ptr=input, offsets_ptr=add_offsets_ptr, n=add_mod_n + ); + assert mul_mod_ptr[0] = ModBuiltin( + p=p, values_ptr=input, offsets_ptr=mul_offsets_ptr, n=mul_mod_n + ); + + %{ + from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner + assert builtin_runners["add_mod_builtin"].instance_def.batch_size == 1 + assert builtin_runners["mul_mod_builtin"].instance_def.batch_size == 1 + + ModBuiltinRunner.fill_memory( + memory=memory, + add_mod=(ids.add_mod_ptr.address_, builtin_runners["add_mod_builtin"], ids.add_mod_n), + mul_mod=(ids.mul_mod_ptr.address_, builtin_runners["mul_mod_builtin"], ids.mul_mod_n), + ) + %} + + let add_mod_ptr = &add_mod_ptr[add_mod_n]; + let mul_mod_ptr = &mul_mod_ptr[mul_mod_n]; + let range_check96_ptr = range_check96_ptr + 76; // 72 is the last start index in the offset_ptr array + + return (y=y_try, is_on_curve=is_on_curve); + + add_offsets_ptr_loc: + dw 40; // ax + dw 16; // b + dw 44; // ax + b + dw 36; // x^3 + dw 44; // ax + b + dw 48; // x^3 + ax + b (:= rhs) + dw 28; // is_on_curve + dw 60; // 1 - is_on_curve + dw 0; // 1 + dw 56; // is_on_curve * rhs + dw 64; // (1 - is_on_curve) * g * rhs + dw 68; // is_on_curve * rhs + (1-is_on_curve) * g * rhs + dw 4; // 0 + dw 72; // y_try^2 + dw 68; // is_on_curve * rhs + (1-is_on_curve) * g * rhs + + mul_offsets_ptr_loc: + dw 8; // x + dw 8; // x + dw 32; // x^2 + dw 8; // x + dw 32; // x^2 + dw 36; // x^3 + dw 12; // a + dw 8; // x + dw 40; // ax + dw 20; // g + dw 48; // rhs + dw 52; // g * rhs + dw 28; // is_on_curve + dw 48; // rhs + dw 56; // is_on_curve * rhs + dw 60; // 1 - is_on_curve + dw 52; // g * rhs + dw 64; // (1 - is_on_curve) * g * rhs + dw 24; // y_try + dw 24; // y_try + dw 72; // y_try^2 +} + +// @notice Get a random point from x +func get_point_from_x{ + range_check96_ptr: felt*, + add_mod_ptr: ModBuiltin*, + mul_mod_ptr: ModBuiltin*, + poseidon_ptr: PoseidonBuiltin*, +}(x: felt, attempt: felt) -> G1Point { + alloc_locals; + let x_384 = felt_to_uint384(x); + + let (y, is_on_curve) = try_get_point_from_x(x=x_384, v=0); + + if (is_on_curve != 0) { + let point = G1Point(x=x_384, y=y); + return point; + } else { + assert poseidon_ptr[0].input.s0 = x; + assert poseidon_ptr[0].input.s1 = attempt; + assert poseidon_ptr[0].input.s2 = 2; + let new_x = poseidon_ptr[0].output.s0; + tempvar poseidon_ptr = poseidon_ptr + PoseidonBuiltin.SIZE; + return get_point_from_x(x=new_x, attempt=attempt + 1); + } +} diff --git a/cairo/src/utils/signature.cairo b/cairo/src/utils/signature.cairo index f80fedcc..c4b03ae2 100644 --- a/cairo/src/utils/signature.cairo +++ b/cairo/src/utils/signature.cairo @@ -7,7 +7,6 @@ from starkware.cairo.common.cairo_builtins import ( ) from starkware.cairo.common.poseidon_state import PoseidonBuiltinState from starkware.cairo.common.registers import get_fp_and_pc, get_label_location -from ethereum.utils.numeric import divmod from starkware.cairo.common.math_cmp import RC_BOUND from starkware.cairo.common.builtin_keccak.keccak import keccak_uint256s_bigend @@ -36,7 +35,12 @@ from src.utils.uint384 import ( uint384_neg_mod_p, felt_to_uint384, ) -from src.curve.secp256k1 import secp256k1, get_generator_point +from src.curve.secp256k1 import ( + secp256k1, + get_generator_point, + try_get_point_from_x, + get_point_from_x, +) from src.curve.g1_point import G1Point @known_ap_change @@ -64,149 +68,6 @@ struct FunctionFelt { b_den: UInt384*, } -func try_get_point_from_x_secp256k1{ - range_check96_ptr: felt*, - add_mod_ptr: ModBuiltin*, - mul_mod_ptr: ModBuiltin*, - poseidon_ptr: PoseidonBuiltin*, -}(x: UInt384, v: felt, result: G1Point*) -> (is_on_curve: felt) { - alloc_locals; - let (__fp__, _) = get_fp_and_pc(); - let (add_offsets_ptr: felt*) = get_label_location(add_offsets_ptr_loc); - let (mul_offsets_ptr: felt*) = get_label_location(mul_offsets_ptr_loc); - let constants_ptr_len = 2; - let input_len = 6; - let add_mod_n = 5; - let mul_mod_n = 7; - let n_assert_eq = 1; - - local rhs_from_x_is_a_square_residue: felt; - local y_try: UInt384; - %{ - from starkware.python.math_utils import is_quad_residue - from sympy import sqrt_mod - from garaga.definitions import CURVES, CurveID - from garaga.hints.io import bigint_pack, bigint_fill - curve_id = CurveID.SECP256K1.value - a = CURVES[curve_id].a - b = CURVES[curve_id].b - p = CURVES[curve_id].p - x = bigint_pack(ids.x, 4, 2**96) - rhs = (x**3 + a*x + b) % p - ids.rhs_from_x_is_a_square_residue = is_quad_residue(rhs, p) - if ids.rhs_from_x_is_a_square_residue == 1: - square_root = sqrt_mod(rhs, p) - if ids.v % 2 == square_root % 2: - pass - else: - square_root = - square_root % p - else: - square_root = sqrt_mod(rhs*CURVES[curve_id].fp_generator, p) - - bigint_fill(square_root, ids.y_try, 4, 2**96) - %} - - let P: UInt384 = UInt384(secp256k1.P0, secp256k1.P1, secp256k1.P2, secp256k1.P3); - - let input: UInt384* = cast(range_check96_ptr, UInt384*); - - assert input[0] = UInt384(1, 0, 0, 0); // constant - assert input[1] = UInt384(0, 0, 0, 0); // constant - assert input[2] = x; - assert input[3] = UInt384(secp256k1.A0, secp256k1.A1, secp256k1.A2, secp256k1.A3); - assert input[4] = UInt384(secp256k1.B0, secp256k1.B1, secp256k1.B2, secp256k1.B3); - assert input[5] = UInt384(secp256k1.G0, secp256k1.G1, secp256k1.G2, secp256k1.G3); - assert input[6] = y_try; - - if (rhs_from_x_is_a_square_residue != 0) { - assert input[7] = UInt384(1, 0, 0, 0); // True - } else { - assert input[7] = UInt384(0, 0, 0, 0); // False - } - - run_modulo_circuit_basic( - P, - add_offsets_ptr, - add_mod_n, - mul_offsets_ptr, - mul_mod_n, - input_len + constants_ptr_len, - n_assert_eq, - ); - - if (rhs_from_x_is_a_square_residue != 0) { - assert [result] = G1Point(x=x, y=y_try); - return (is_on_curve=1); - } else { - assert [result] = G1Point(x=UInt384(0, 0, 0, 0), y=UInt384(0, 0, 0, 0)); - return (is_on_curve=0); - } - - add_offsets_ptr_loc: - dw 40; // (ax)+b - dw 16; - dw 44; - dw 36; // (x3+ax)+b=rhs - dw 44; - dw 48; - dw 28; // (1-is_on_curve) - dw 60; - dw 0; - dw 56; // is_on_curve*rhs + (1-is_on_curve)*g*rhs - dw 64; - dw 68; - dw 4; // assert rhs_or_grhs == should_be_rhs_or_grhs - dw 72; - dw 68; - - mul_offsets_ptr_loc: - dw 8; // x2 - dw 8; - dw 32; - dw 8; // x3 - dw 32; - dw 36; - dw 12; // ax - dw 8; - dw 40; - dw 20; // g*rhs - dw 48; - dw 52; - dw 28; // is_on_curve*rhs - dw 48; - dw 56; - dw 60; // (1-is_on_curve)*grhs - dw 52; - dw 64; - dw 24; // y_try^2=should_be_rhs_or_grhs - dw 24; - dw 72; -} - -func get_point_from_x_secp256k1{ - range_check96_ptr: felt*, - add_mod_ptr: ModBuiltin*, - mul_mod_ptr: ModBuiltin*, - poseidon_ptr: PoseidonBuiltin*, -}(x: felt, attempt: felt) -> (res: G1Point) { - alloc_locals; - let (local res: G1Point*) = alloc(); - let (x_384: UInt384) = felt_to_uint384(x); - - let (is_on_curve) = try_get_point_from_x_secp256k1(x=x_384, v=0, result=res); - - if (is_on_curve != 0) { - return (res=[res]); - } else { - assert poseidon_ptr[0].input.s0 = x; - assert poseidon_ptr[0].input.s1 = attempt; - assert poseidon_ptr[0].input.s2 = 2; - let new_x = poseidon_ptr[0].output.s0; - tempvar poseidon_ptr = poseidon_ptr + PoseidonBuiltin.SIZE; - return get_point_from_x_secp256k1(x=new_x, attempt=attempt + 1); - } -} - namespace Signature { // A version of verify_eth_signature that uses the keccak builtin. @@ -289,14 +150,13 @@ namespace Signature { ) { alloc_locals; let (__fp__, _) = get_fp_and_pc(); - let (local r_point: G1Point*) = alloc(); - let (is_on_curve) = try_get_point_from_x_secp256k1(x=r, v=y_parity, result=r_point); + let (y, is_on_curve) = try_get_point_from_x(x=r, v=y_parity); if (is_on_curve == 0) { - assert 1 = 0; return ( public_key_point=G1Point(x=UInt384(0, 0, 0, 0), y=UInt384(0, 0, 0, 0)), success=0 ); } + let r_point = G1Point(x=r, y=y); // The result is given by // -(msg_hash / r) * gen + (s / r) * r_point // where the division by r is modulo N. @@ -316,32 +176,30 @@ namespace Signature { let (ep1_low, en1_low, sp1_low, sn1_low) = scalar_to_epns(u1.low); let (ep1_high, en1_high, sp1_high, sn1_high) = scalar_to_epns(u1.high); - let (ep1_low_384) = felt_to_uint384(ep1_low); - let (en1_low_384) = felt_to_uint384(en1_low); + let ep1_low_384 = felt_to_uint384(ep1_low); + let en1_low_384 = felt_to_uint384(en1_low); let sp1_low_384 = sign_to_uint384_mod_secp256k1(sp1_low); let sn1_low_384 = sign_to_uint384_mod_secp256k1(sn1_low); - let (ep1_high_384) = felt_to_uint384(ep1_high); - let (en1_high_384) = felt_to_uint384(en1_high); + let ep1_high_384 = felt_to_uint384(ep1_high); + let en1_high_384 = felt_to_uint384(en1_high); let sp1_high_384 = sign_to_uint384_mod_secp256k1(sp1_high); let sn1_high_384 = sign_to_uint384_mod_secp256k1(sn1_high); let (ep2_low, en2_low, sp2_low, sn2_low) = scalar_to_epns(u2.low); - let (ep2_low_384) = felt_to_uint384(ep2_low); - let (en2_low_384) = felt_to_uint384(en2_low); + let ep2_low_384 = felt_to_uint384(ep2_low); + let en2_low_384 = felt_to_uint384(en2_low); let sp2_low_384 = sign_to_uint384_mod_secp256k1(sp2_low); let sn2_low_384 = sign_to_uint384_mod_secp256k1(sn2_low); let (ep2_high, en2_high, sp2_high, sn2_high) = scalar_to_epns(u2.high); - let (ep2_high_384) = felt_to_uint384(ep2_high); - let (en2_high_384) = felt_to_uint384(en2_high); + let ep2_high_384 = felt_to_uint384(ep2_high); + let en2_high_384 = felt_to_uint384(en2_high); let sp2_high_384 = sign_to_uint384_mod_secp256k1(sp2_high); let sn2_high_384 = sign_to_uint384_mod_secp256k1(sn2_high); let generator_point = get_generator_point(); - // _hash_inputs_points_scalars_and_result_points - %{ from garaga.hints.io import pack_bigint_ptr, pack_felt_ptr, fill_sum_dlog_div, fill_g1_point, bigint_split from garaga.starknet.tests_and_calldata_generators.msm import MSMCalldataBuilder @@ -397,11 +255,9 @@ namespace Signature { s2=poseidon_ptr[0].output.s2, ); - // tempvar init_s0 = poseidon_ptr[1].output.s0 + 0; - // // %{ print(f"CAIROS0: {hex(ids.init_s0)}") %} let poseidon_ptr = poseidon_ptr + 2 * PoseidonBuiltin.SIZE; - let (_, _, _) = hash_full_transcript_and_get_Z_3_LIMBS(cast(generator_point, felt*), 2); - let (_, _, _) = hash_full_transcript_and_get_Z_3_LIMBS(cast(r_point, felt*), 2); + hash_full_transcript_and_get_Z_3_LIMBS(cast(generator_point, felt*), 2); + hash_full_transcript_and_get_Z_3_LIMBS(cast(&r_point, felt*), 2); // Q_low, Q_high, Q_high_shifted (filled by prover) (50 - 55). let (_s0, _s1, _s2) = hash_full_transcript_and_get_Z_3_LIMBS( cast(range_check96_ptr + 4 + 50 * N_LIMBS, felt*), 3 * 2 @@ -418,22 +274,20 @@ namespace Signature { tempvar rlc_coeff = poseidon_ptr[1].output.s1 + 0; let poseidon_ptr = poseidon_ptr + 2 * PoseidonBuiltin.SIZE; - %{ print(f"CAIRORLC: {hex(ids.rlc_coeff)}") %} - let (rlc_coeff_u384) = felt_to_uint384(rlc_coeff); + let rlc_coeff_u384 = felt_to_uint384(rlc_coeff); // Hash sumdlogdiv 2 points : (4-29) let (_random_x_coord, _, _) = hash_full_transcript_and_get_Z_3_LIMBS( cast(range_check96_ptr + 4 * N_LIMBS, felt*), 26 ); - %{ print(f"CAIROX: {hex(ids._random_x_coord)}") %} tempvar range_check96_ptr_init = range_check96_ptr; tempvar range_check96_ptr_after_circuit = range_check96_ptr + 224 + (4 + 117 + 108 - 1) * N_LIMBS; - let (random_point: G1Point) = get_point_from_x_secp256k1{ - range_check96_ptr=range_check96_ptr_after_circuit - }(x=_random_x_coord, attempt=0); + let random_point = get_point_from_x{range_check96_ptr=range_check96_ptr_after_circuit}( + x=_random_x_coord, attempt=0 + ); tempvar range_check96_ptr_final = range_check96_ptr_after_circuit; let range_check96_ptr = range_check96_ptr_init; diff --git a/cairo/src/utils/uint256.cairo b/cairo/src/utils/uint256.cairo index 134f6924..ec172ee1 100644 --- a/cairo/src/utils/uint256.cairo +++ b/cairo/src/utils/uint256.cairo @@ -11,7 +11,6 @@ from starkware.cairo.common.uint256 import ( from starkware.cairo.common.cairo_builtins import UInt384 from starkware.cairo.common.bool import FALSE from starkware.cairo.common.math_cmp import is_nn -from ethereum.utils.numeric import divmod from src.utils.maths import unsigned_div_rem diff --git a/cairo/tests/src/curve/test_secp256k1.cairo b/cairo/tests/src/curve/test_secp256k1.cairo index 293a2680..565b1420 100644 --- a/cairo/tests/src/curve/test_secp256k1.cairo +++ b/cairo/tests/src/curve/test_secp256k1.cairo @@ -1,5 +1,8 @@ -from starkware.cairo.common.cairo_builtins import UInt384 -from src.curve.secp256k1 import get_generator_point +from starkware.cairo.common.cairo_builtins import UInt384, ModBuiltin +from starkware.cairo.common.alloc import alloc + +from src.curve.secp256k1 import get_generator_point, try_get_point_from_x +from src.curve.g1_point import G1Point func test__get_generator_point() { let generator = get_generator_point(); @@ -15,3 +18,21 @@ func test__get_generator_point() { return (); } + +func test__try_get_point_from_x{ + range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin* +}() -> (y: UInt384*, is_on_curve: felt) { + alloc_locals; + let (x_ptr) = alloc(); + tempvar v; + %{ + segments.write_arg(ids.x_ptr, program_input["x"]) + ids.v = program_input["v"] + %} + + let x = [cast(x_ptr, UInt384*)]; + let (y, is_on_curve) = try_get_point_from_x(x=x, v=v); + // serde doesn't handle non pointer types in tuples + tempvar y_ptr = new UInt384(y.d0, y.d1, y.d2, y.d3); + return (y_ptr, is_on_curve); +} diff --git a/cairo/tests/src/curve/test_secp256k1.py b/cairo/tests/src/curve/test_secp256k1.py index b85f5731..db628d28 100644 --- a/cairo/tests/src/curve/test_secp256k1.py +++ b/cairo/tests/src/curve/test_secp256k1.py @@ -1,5 +1,38 @@ +import hypothesis.strategies as st +import pytest +from hypothesis import given +from starkware.cairo.lang.cairo_constants import DEFAULT_PRIME +from sympy import sqrt_mod + +from src.utils.uint384 import int_to_uint384, uint384_to_int + +pytestmark = pytest.mark.python_vm +A = 0 +B = 7 +G = 3 +P = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F +N = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 + + class TestSecp256k1: class TestGetGeneratorPoint: def test_get_generator_point(self, cairo_run): cairo_run("test__get_generator_point") + + class TestTryGetPointFromX: + @given( + x=st.integers(min_value=0, max_value=2**384 - 1), + v=st.integers(min_value=0, max_value=DEFAULT_PRIME - 1), + ) + def test_try_get_point_from_x(self, cairo_run, x, v): + y_try, is_on_curve = cairo_run( + "test__try_get_point_from_x", x=int_to_uint384(x % P), v=v + ) + + square_root = sqrt_mod(x**3 + A * x + B, P) + assert (square_root is not None) == is_on_curve + if square_root is not None: + assert ( + square_root if (v % 2 == square_root % 2) else (-square_root % P) + ) == uint384_to_int(y_try["d0"], y_try["d1"], y_try["d2"], y_try["d3"]) From 2f42253cfc8acb64502c22f4a4c4aad68c63fe53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Walter?= Date: Thu, 23 Jan 2025 11:35:15 +0100 Subject: [PATCH 11/17] ec ops --- cairo/src/curve/secp256k1.cairo | 196 +++++- cairo/src/utils/ecdsa_circuit.cairo | 663 +++++++-------------- cairo/src/utils/ecdsa_circuit.py | 350 ----------- cairo/src/utils/signature.cairo | 151 +---- cairo/tests/src/curve/test_secp256k1.cairo | 63 +- cairo/tests/src/curve/test_secp256k1.py | 168 +++++- cairo/tests/src/utils/test_signature.cairo | 4 +- 7 files changed, 661 insertions(+), 934 deletions(-) delete mode 100644 cairo/src/utils/ecdsa_circuit.py diff --git a/cairo/src/curve/secp256k1.cairo b/cairo/src/curve/secp256k1.cairo index 78c81b41..bcc5fb95 100644 --- a/cairo/src/curve/secp256k1.cairo +++ b/cairo/src/curve/secp256k1.cairo @@ -4,7 +4,7 @@ from starkware.cairo.common.registers import get_label_location from starkware.cairo.common.modulo import run_mod_p_circuit from src.curve.g1_point import G1Point -from src.utils.uint384 import felt_to_uint384 +from src.utils.uint384 import felt_to_uint384, uint384_is_neg_mod_p, uint384_eq_mod_p namespace secp256k1 { const CURVE_ID = 2; @@ -180,26 +180,200 @@ func try_get_point_from_x{ } // @notice Get a random point from x -func get_point_from_x{ +func get_random_point{ range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin*, poseidon_ptr: PoseidonBuiltin*, -}(x: felt, attempt: felt) -> G1Point { +}(seed: felt) -> G1Point { alloc_locals; - let x_384 = felt_to_uint384(x); + let x_384 = felt_to_uint384(seed); let (y, is_on_curve) = try_get_point_from_x(x=x_384, v=0); if (is_on_curve != 0) { let point = G1Point(x=x_384, y=y); return point; - } else { - assert poseidon_ptr[0].input.s0 = x; - assert poseidon_ptr[0].input.s1 = attempt; - assert poseidon_ptr[0].input.s2 = 2; - let new_x = poseidon_ptr[0].output.s0; - tempvar poseidon_ptr = poseidon_ptr + PoseidonBuiltin.SIZE; - return get_point_from_x(x=new_x, attempt=attempt + 1); } + + assert poseidon_ptr[0].input.s0 = seed; + assert poseidon_ptr[0].input.s1 = y.d0; // salt + assert poseidon_ptr[0].input.s2 = 2; + let seed = poseidon_ptr[0].output.s0; + tempvar poseidon_ptr = poseidon_ptr + PoseidonBuiltin.SIZE; + + return get_random_point(seed=seed); +} + +// Add Double an EC point. Doesn't check if the input is on curve nor if it's the point at infinity. +func ec_double{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin*}( + p: G1Point +) -> G1Point { + alloc_locals; + + let add_mod_n = 6; + let (add_offsets_ptr) = get_label_location(ec_double_add_offsets_label); + let mul_mod_n = 5; + let (mul_offsets_ptr) = get_label_location(ec_double_mul_offsets_label); + + let input: UInt384* = cast(range_check96_ptr, UInt384*); + assert input[0] = UInt384(3, 0, 0, 0); + assert input[1] = p.x; + assert input[2] = p.y; + assert input[3] = UInt384(secp256k1.A0, secp256k1.A1, secp256k1.A2, secp256k1.A3); + + let modulus = UInt384(secp256k1.P0, secp256k1.P1, secp256k1.P2, secp256k1.P3); + assert add_mod_ptr[0] = ModBuiltin( + p=modulus, values_ptr=input, offsets_ptr=add_offsets_ptr, n=add_mod_n + ); + assert mul_mod_ptr[0] = ModBuiltin( + p=modulus, values_ptr=input, offsets_ptr=mul_offsets_ptr, n=mul_mod_n + ); + + %{ + from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner + assert builtin_runners["add_mod_builtin"].instance_def.batch_size == 1 + assert builtin_runners["mul_mod_builtin"].instance_def.batch_size == 1 + + ModBuiltinRunner.fill_memory( + memory=memory, + add_mod=(ids.add_mod_ptr.address_, builtin_runners["add_mod_builtin"], ids.add_mod_n), + mul_mod=(ids.mul_mod_ptr.address_, builtin_runners["mul_mod_builtin"], ids.mul_mod_n), + ) + %} + + let add_mod_ptr = &add_mod_ptr[add_mod_n]; + let mul_mod_ptr = &mul_mod_ptr[mul_mod_n]; + let res = G1Point( + x=[cast(range_check96_ptr + 44, UInt384*)], y=[cast(range_check96_ptr + 56, UInt384*)] + ); + let range_check96_ptr = range_check96_ptr + 60; // 56 is the last start index in the offset_ptr array + + return res; + + ec_double_add_offsets_label: + dw 20; + dw 12; + dw 24; + dw 8; + dw 8; + dw 28; + dw 4; + dw 40; + dw 36; + dw 4; + dw 44; + dw 40; + dw 44; + dw 48; + dw 4; + dw 8; + dw 56; + dw 52; + + ec_double_mul_offsets_label: + dw 4; + dw 4; + dw 16; + dw 0; + dw 16; + dw 20; + dw 28; + dw 32; + dw 24; + dw 32; + dw 32; + dw 36; + dw 32; + dw 48; + dw 52; +} + +// Add two EC points. Doesn't check if the inputs are on curve nor if they are the point at infinity. +func ec_add{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin*}( + p: G1Point, q: G1Point +) -> G1Point { + alloc_locals; + let modulus = UInt384(secp256k1.P0, secp256k1.P1, secp256k1.P2, secp256k1.P3); + let same_x = uint384_eq_mod_p(p.x, q.x, modulus); + + if (same_x != 0) { + let opposite_y = uint384_is_neg_mod_p(p.y, q.y, modulus); + if (opposite_y != 0) { + // p + (-p) = O (point at infinity) + let res = G1Point(UInt384(0, 0, 0, 0), UInt384(0, 0, 0, 0)); + return res; + } + + return ec_double(p); + } + + let add_mod_n = 6; + let (add_offsets_ptr) = get_label_location(ec_add_add_offsets_label); + let mul_mod_n = 3; + let (mul_offsets_ptr) = get_label_location(ec_add_mul_offsets_label); + let input: UInt384* = cast(range_check96_ptr, UInt384*); + assert input[0] = p.x; + assert input[1] = p.y; + assert input[2] = q.x; + assert input[3] = q.y; + + assert add_mod_ptr[0] = ModBuiltin( + p=modulus, values_ptr=input, offsets_ptr=add_offsets_ptr, n=add_mod_n + ); + assert mul_mod_ptr[0] = ModBuiltin( + p=modulus, values_ptr=input, offsets_ptr=mul_offsets_ptr, n=mul_mod_n + ); + + %{ + from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner + assert builtin_runners["add_mod_builtin"].instance_def.batch_size == 1 + assert builtin_runners["mul_mod_builtin"].instance_def.batch_size == 1 + + ModBuiltinRunner.fill_memory( + memory=memory, + add_mod=(ids.add_mod_ptr.address_, builtin_runners["add_mod_builtin"], ids.add_mod_n), + mul_mod=(ids.mul_mod_ptr.address_, builtin_runners["mul_mod_builtin"], ids.mul_mod_n), + ) + %} + + let add_mod_ptr = &add_mod_ptr[add_mod_n]; + let mul_mod_ptr = &mul_mod_ptr[mul_mod_n]; + let range_check96_ptr = range_check96_ptr + 52; // 48 is the last start index in the offset_ptr array + + let res = G1Point( + x=[cast(cast(input, felt*) + 36, UInt384*)], y=[cast(cast(input, felt*) + 48, UInt384*)] + ); + return res; + + ec_add_add_offsets_label: + dw 12; + dw 16; + dw 4; + dw 8; + dw 20; + dw 0; + dw 0; + dw 32; + dw 28; + dw 8; + dw 36; + dw 32; + dw 36; + dw 40; + dw 0; + dw 4; + dw 48; + dw 44; + + ec_add_mul_offsets_label: + dw 20; + dw 24; + dw 16; + dw 24; + dw 24; + dw 28; + dw 24; + dw 40; + dw 44; } diff --git a/cairo/src/utils/ecdsa_circuit.cairo b/cairo/src/utils/ecdsa_circuit.cairo index 8c4fbac3..855cc8f6 100644 --- a/cairo/src/utils/ecdsa_circuit.cairo +++ b/cairo/src/utils/ecdsa_circuit.cairo @@ -1,898 +1,687 @@ -from starkware.cairo.common.registers import get_fp_and_pc, get_label_location - -func get_ADD_EC_POINT_circuit() -> (add_offsets: felt*, mul_offsets: felt*) { - alloc_locals; - // let (__fp__, _) = get_fp_and_pc(); - // let (constants_ptr: felt*) = get_label_location(constants_ptr_loc); - let (add_offsets_ptr: felt*) = get_label_location(add_offsets_ptr_loc); - let (mul_offsets_ptr: felt*) = get_label_location(mul_offsets_ptr_loc); - // let (output_offsets_ptr: felt*) = get_label_location(output_offsets_ptr_loc); - // let constants_ptr_len = 0; - // let input_len = 16; - // let witnesses_len = 0; - // let output_len = 8; - // let continuous_output = 0; - // let add_mod_n = 6; - // let mul_mod_n = 3; - // let n_assert_eq = 0; - // let name = 'add_ec_point'; - // let curve_id = curve_id; - // local circuit: ModuloCircuit = ModuloCircuit( - // constants_ptr, - // add_offsets_ptr, - // mul_offsets_ptr, - // output_offsets_ptr, - // constants_ptr_len, - // input_len, - // witnesses_len, - // output_len, - // continuous_output, - // add_mod_n, - // mul_mod_n, - // n_assert_eq, - // name, - // curve_id, - // ); - // return (&circuit,); - - // constants_ptr_loc: - - return (add_offsets_ptr, mul_offsets_ptr); - - add_offsets_ptr_loc: - dw 12; // None - dw 16; - dw 4; - dw 8; // None - dw 20; - dw 0; - dw 0; // None - dw 32; - dw 28; - dw 8; // None - dw 36; - dw 32; - dw 36; // None - dw 40; - dw 0; - dw 4; // None - dw 48; - dw 44; - - mul_offsets_ptr_loc: - dw 20; // None - dw 24; - dw 16; - dw 24; // None - dw 24; - dw 28; - dw 24; // None - dw 40; - dw 44; - - output_offsets_ptr_loc: - dw 36; - dw 48; -} - -func get_DOUBLE_EC_POINT_circuit() -> (add_offsets: felt*, mul_offsets: felt*) { - // alloc_locals; - // let (__fp__, _) = get_fp_and_pc(); - // let (constants_ptr: felt*) = get_label_location(constants_ptr_loc); - let (add_offsets_ptr: felt*) = get_label_location(add_offsets_ptr_loc); - let (mul_offsets_ptr: felt*) = get_label_location(mul_offsets_ptr_loc); - // let (output_offsets_ptr: felt*) = get_label_location(output_offsets_ptr_loc); - // let constants_ptr_len = 1; - // let input_len = 12; - // let witnesses_len = 0; - // let output_len = 8; - // let continuous_output = 0; - // let add_mod_n = 6; - // let mul_mod_n = 5; - // let n_assert_eq = 0; - // let name = 'double_ec_point'; - // let curve_id = curve_id; - // local circuit: ModuloCircuit = ModuloCircuit( - // constants_ptr, - // add_offsets_ptr, - // mul_offsets_ptr, - // output_offsets_ptr, - // constants_ptr_len, - // input_len, - // witnesses_len, - // output_len, - // continuous_output, - // add_mod_n, - // mul_mod_n, - // n_assert_eq, - // name, - // curve_id, - // ); - // return (&circuit,); - - // constants_ptr_loc: - // dw 3; - // dw 0; - // dw 0; - // dw 0; - - return (add_offsets_ptr, mul_offsets_ptr); - - add_offsets_ptr_loc: - dw 20; // None - dw 12; - dw 24; - dw 8; // None - dw 8; - dw 28; - dw 4; // None - dw 40; - dw 36; - dw 4; // None - dw 44; - dw 40; - dw 44; // None - dw 48; - dw 4; - dw 8; // None - dw 56; - dw 52; - - mul_offsets_ptr_loc: - dw 4; // None - dw 4; - dw 16; - dw 0; // None - dw 16; - dw 20; - dw 28; // None - dw 32; - dw 24; - dw 32; // None - dw 32; - dw 36; - dw 32; // None - dw 48; - dw 52; - - output_offsets_ptr_loc: - dw 44; - dw 56; -} +from starkware.cairo.common.registers import get_label_location func get_full_ecip_2P_circuit() -> (add_offsets: felt*, mul_offsets: felt*) { - // alloc_locals; - // let (__fp__, _) = get_fp_and_pc(); - // let (constants_ptr: felt*) = get_label_location(constants_ptr_loc); let (add_offsets_ptr: felt*) = get_label_location(add_offsets_ptr_loc); let (mul_offsets_ptr: felt*) = get_label_location(mul_offsets_ptr_loc); - // let (output_offsets_ptr: felt*) = get_label_location(output_offsets_ptr_loc); - // let constants_ptr_len = 4; - // let input_len = 224; - // let witnesses_len = 0; - // let output_len = 4; - // let continuous_output = 1; - // let add_mod_n = 117; - // let mul_mod_n = 108; - // let n_assert_eq = 1; - // let name = 'full_ecip_2P'; - // let curve_id = curve_id; - // local circuit: ModuloCircuit = ModuloCircuit( - // constants_ptr, - // add_offsets_ptr, - // mul_offsets_ptr, - // output_offsets_ptr, - // constants_ptr_len, - // input_len, - // witnesses_len, - // output_len, - // continuous_output, - // add_mod_n, - // mul_mod_n, - // n_assert_eq, - // name, - // curve_id, - // ); - // return (&circuit,); - // constants_ptr_loc: - // dw 3; - // dw 0; - // dw 0; - // dw 0; - // dw 0; - // dw 0; - // dw 0; - // dw 0; - // dw 12528508628158887531275213211; - // dw 66632300; - // dw 0; - // dw 0; - // dw 12528508628158887531275213211; - // dw 4361599596; - // dw 0; - // dw 0; return (add_offsets_ptr, mul_offsets_ptr); add_offsets_ptr_loc: - dw 244; // None + dw 244; dw 232; dw 248; - dw 228; // None + dw 228; dw 228; dw 252; - dw 260; // None + dw 260; dw 264; dw 228; - dw 224; // None + dw 224; dw 224; dw 272; - dw 272; // None + dw 272; dw 276; dw 268; - dw 276; // None + dw 276; dw 280; dw 224; - dw 228; // None + dw 228; dw 288; dw 284; - dw 288; // None + dw 288; dw 292; dw 4; - dw 228; // None + dw 228; dw 296; dw 292; - dw 224; // None + dw 224; dw 300; dw 276; - dw 292; // None + dw 292; dw 292; dw 312; - dw 276; // None + dw 276; dw 316; dw 224; - dw 308; // None dw 308; + dw 308; + dw 332; dw 332; - dw 332; // None dw 336; dw 232; - dw 328; // None + dw 328; dw 336; dw 340; - dw 304; // None + dw 304; dw 304; dw 348; - dw 344; // None + dw 344; dw 348; dw 352; - dw 28; // Eval sumdlogdiv_a_num Horner step: add coefficient_3 + dw 28; dw 356; dw 360; - dw 24; // Eval sumdlogdiv_a_num Horner step: add coefficient_2 + dw 24; dw 364; dw 368; - dw 20; // Eval sumdlogdiv_a_num Horner step: add coefficient_1 + dw 20; dw 372; dw 376; - dw 16; // Eval sumdlogdiv_a_num Horner step: add coefficient_0 + dw 16; dw 380; dw 384; - dw 52; // Eval sumdlogdiv_a_den Horner step: add coefficient_4 + dw 52; dw 388; dw 392; - dw 48; // Eval sumdlogdiv_a_den Horner step: add coefficient_3 + dw 48; dw 396; dw 400; - dw 44; // Eval sumdlogdiv_a_den Horner step: add coefficient_2 + dw 44; dw 404; dw 408; - dw 40; // Eval sumdlogdiv_a_den Horner step: add coefficient_1 + dw 40; dw 412; dw 416; - dw 36; // Eval sumdlogdiv_a_den Horner step: add coefficient_0 + dw 36; dw 420; dw 424; - dw 76; // Eval sumdlogdiv_b_num Horner step: add coefficient_4 + dw 76; dw 432; dw 436; - dw 72; // Eval sumdlogdiv_b_num Horner step: add coefficient_3 + dw 72; dw 440; dw 444; - dw 68; // Eval sumdlogdiv_b_num Horner step: add coefficient_2 + dw 68; dw 448; dw 452; - dw 64; // Eval sumdlogdiv_b_num Horner step: add coefficient_1 + dw 64; dw 456; dw 460; - dw 60; // Eval sumdlogdiv_b_num Horner step: add coefficient_0 + dw 60; dw 464; dw 468; - dw 112; // Eval sumdlogdiv_b_den Horner step: add coefficient_7 + dw 112; dw 472; dw 476; - dw 108; // Eval sumdlogdiv_b_den Horner step: add coefficient_6 + dw 108; dw 480; dw 484; - dw 104; // Eval sumdlogdiv_b_den Horner step: add coefficient_5 + dw 104; dw 488; dw 492; - dw 100; // Eval sumdlogdiv_b_den Horner step: add coefficient_4 + dw 100; dw 496; dw 500; - dw 96; // Eval sumdlogdiv_b_den Horner step: add coefficient_3 + dw 96; dw 504; dw 508; - dw 92; // Eval sumdlogdiv_b_den Horner step: add coefficient_2 + dw 92; dw 512; dw 516; - dw 88; // Eval sumdlogdiv_b_den Horner step: add coefficient_1 + dw 88; dw 520; dw 524; - dw 84; // Eval sumdlogdiv_b_den Horner step: add coefficient_0 + dw 84; dw 528; dw 532; - dw 428; // None + dw 428; dw 540; dw 544; - dw 28; // Eval sumdlogdiv_a_num Horner step: add coefficient_3 + dw 28; dw 548; dw 552; - dw 24; // Eval sumdlogdiv_a_num Horner step: add coefficient_2 + dw 24; dw 556; dw 560; - dw 20; // Eval sumdlogdiv_a_num Horner step: add coefficient_1 + dw 20; dw 564; dw 568; - dw 16; // Eval sumdlogdiv_a_num Horner step: add coefficient_0 + dw 16; dw 572; dw 576; - dw 52; // Eval sumdlogdiv_a_den Horner step: add coefficient_4 + dw 52; dw 580; dw 584; - dw 48; // Eval sumdlogdiv_a_den Horner step: add coefficient_3 + dw 48; dw 588; dw 592; - dw 44; // Eval sumdlogdiv_a_den Horner step: add coefficient_2 + dw 44; dw 596; dw 600; - dw 40; // Eval sumdlogdiv_a_den Horner step: add coefficient_1 + dw 40; dw 604; dw 608; - dw 36; // Eval sumdlogdiv_a_den Horner step: add coefficient_0 + dw 36; dw 612; dw 616; - dw 76; // Eval sumdlogdiv_b_num Horner step: add coefficient_4 + dw 76; dw 624; dw 628; - dw 72; // Eval sumdlogdiv_b_num Horner step: add coefficient_3 + dw 72; dw 632; dw 636; - dw 68; // Eval sumdlogdiv_b_num Horner step: add coefficient_2 + dw 68; dw 640; dw 644; - dw 64; // Eval sumdlogdiv_b_num Horner step: add coefficient_1 + dw 64; dw 648; dw 652; - dw 60; // Eval sumdlogdiv_b_num Horner step: add coefficient_0 + dw 60; dw 656; dw 660; - dw 112; // Eval sumdlogdiv_b_den Horner step: add coefficient_7 + dw 112; dw 664; dw 668; - dw 108; // Eval sumdlogdiv_b_den Horner step: add coefficient_6 + dw 108; dw 672; dw 676; - dw 104; // Eval sumdlogdiv_b_den Horner step: add coefficient_5 + dw 104; dw 680; dw 684; - dw 100; // Eval sumdlogdiv_b_den Horner step: add coefficient_4 + dw 100; dw 688; dw 692; - dw 96; // Eval sumdlogdiv_b_den Horner step: add coefficient_3 + dw 96; dw 696; dw 700; - dw 92; // Eval sumdlogdiv_b_den Horner step: add coefficient_2 + dw 92; dw 704; dw 708; - dw 88; // Eval sumdlogdiv_b_den Horner step: add coefficient_1 + dw 88; dw 712; dw 716; - dw 84; // Eval sumdlogdiv_b_den Horner step: add coefficient_0 + dw 84; dw 720; dw 724; - dw 620; // None + dw 620; dw 732; dw 736; - dw 744; // None + dw 744; dw 748; dw 740; - dw 120; // None + dw 120; dw 752; dw 224; - dw 756; // None + dw 756; dw 264; dw 760; - dw 760; // None + dw 760; dw 764; dw 124; - dw 124; // None + dw 124; dw 768; dw 4; - dw 760; // None + dw 760; dw 772; dw 768; - dw 784; // None + dw 784; dw 796; dw 800; - dw 4; // None + dw 4; dw 800; dw 804; - dw 128; // None + dw 128; dw 808; dw 224; - dw 812; // None + dw 812; dw 264; dw 816; - dw 816; // None + dw 816; dw 820; dw 132; - dw 132; // None + dw 132; dw 824; dw 4; - dw 816; // None + dw 816; dw 828; dw 824; - dw 840; // None + dw 840; dw 852; dw 856; - dw 804; // None + dw 804; dw 856; dw 860; - dw 200; // None + dw 200; dw 864; dw 224; - dw 868; // None + dw 868; dw 264; dw 872; - dw 204; // None + dw 204; dw 876; dw 4; - dw 872; // None + dw 872; dw 880; dw 876; - dw 860; // None + dw 860; dw 884; dw 888; - dw 120; // None + dw 120; dw 892; dw 224; - dw 896; // None + dw 896; dw 264; dw 900; - dw 900; // None + dw 900; dw 904; dw 124; - dw 124; // None + dw 124; dw 908; dw 4; - dw 900; // None + dw 900; dw 912; dw 908; - dw 924; // None + dw 924; dw 936; dw 940; - dw 4; // None + dw 4; dw 940; dw 944; - dw 128; // None + dw 128; dw 948; dw 224; - dw 952; // None + dw 952; dw 264; dw 956; - dw 956; // None + dw 956; dw 960; dw 132; - dw 132; // None + dw 132; dw 964; dw 4; - dw 956; // None + dw 956; dw 968; dw 964; - dw 980; // None + dw 980; dw 992; dw 996; - dw 944; // None + dw 944; dw 996; dw 1000; - dw 208; // None + dw 208; dw 1004; dw 224; - dw 1008; // None + dw 1008; dw 264; dw 1012; - dw 212; // None + dw 212; dw 1016; dw 4; - dw 1012; // None + dw 1012; dw 1020; dw 1016; - dw 1000; // None + dw 1000; dw 1024; dw 1028; - dw 208; // None + dw 208; dw 1032; dw 224; - dw 1036; // None + dw 1036; dw 264; dw 1040; - dw 1040; // None + dw 1040; dw 1044; dw 212; - dw 212; // None + dw 212; dw 1048; dw 4; - dw 1040; // None + dw 1040; dw 1052; dw 1048; - dw 8; // None + dw 8; dw 1056; dw 4; - dw 1072; // None + dw 1072; dw 1076; dw 1064; - dw 216; // None + dw 216; dw 1080; dw 224; - dw 1084; // None + dw 1084; dw 264; dw 1088; - dw 220; // None + dw 220; dw 1092; dw 4; - dw 1088; // None + dw 1088; dw 1096; dw 1092; - dw 1076; // None + dw 1076; dw 1100; dw 1104; - dw 1116; // Sum of rhs_low * c0, rhs_high * c1, rhs_high_shifted * c2 + dw 1116; dw 1120; dw 1128; - dw 1128; // Sum of rhs_low * c0, rhs_high * c1, rhs_high_shifted * c2 + dw 1128; dw 1124; dw 1132; - dw 4; // Assert lhs - rhs = 0 + dw 4; dw 1132; dw 748; mul_offsets_ptr_loc: - dw 224; // None + dw 224; dw 224; dw 240; - dw 0; // None + dw 0; dw 240; dw 244; - dw 252; // None + dw 252; dw 256; dw 248; - dw 224; // None + dw 224; dw 256; dw 260; - dw 256; // None + dw 256; dw 256; dw 268; - dw 256; // None + dw 256; dw 280; dw 284; - dw 300; // None + dw 300; dw 304; dw 296; - dw 304; // None + dw 304; dw 292; dw 308; - dw 312; // None + dw 312; dw 316; dw 320; - dw 276; // None + dw 276; dw 276; dw 324; - dw 0; // None + dw 0; dw 324; dw 328; - dw 340; // None + dw 340; dw 344; dw 320; - dw 32; // Eval sumdlogdiv_a_num Horner step: multiply by xA0 + dw 32; dw 224; dw 356; - dw 360; // Eval sumdlogdiv_a_num Horner step: multiply by xA0 + dw 360; dw 224; dw 364; - dw 368; // Eval sumdlogdiv_a_num Horner step: multiply by xA0 + dw 368; dw 224; dw 372; - dw 376; // Eval sumdlogdiv_a_num Horner step: multiply by xA0 + dw 376; dw 224; dw 380; - dw 56; // Eval sumdlogdiv_a_den Horner step: multiply by xA0 + dw 56; dw 224; dw 388; - dw 392; // Eval sumdlogdiv_a_den Horner step: multiply by xA0 + dw 392; dw 224; dw 396; - dw 400; // Eval sumdlogdiv_a_den Horner step: multiply by xA0 + dw 400; dw 224; dw 404; - dw 408; // Eval sumdlogdiv_a_den Horner step: multiply by xA0 + dw 408; dw 224; dw 412; - dw 416; // Eval sumdlogdiv_a_den Horner step: multiply by xA0 + dw 416; dw 224; dw 420; - dw 424; // None + dw 424; dw 428; dw 384; - dw 80; // Eval sumdlogdiv_b_num Horner step: multiply by xA0 + dw 80; dw 224; dw 432; - dw 436; // Eval sumdlogdiv_b_num Horner step: multiply by xA0 + dw 436; dw 224; dw 440; - dw 444; // Eval sumdlogdiv_b_num Horner step: multiply by xA0 + dw 444; dw 224; dw 448; - dw 452; // Eval sumdlogdiv_b_num Horner step: multiply by xA0 + dw 452; dw 224; dw 456; - dw 460; // Eval sumdlogdiv_b_num Horner step: multiply by xA0 + dw 460; dw 224; dw 464; - dw 116; // Eval sumdlogdiv_b_den Horner step: multiply by xA0 + dw 116; dw 224; dw 472; - dw 476; // Eval sumdlogdiv_b_den Horner step: multiply by xA0 + dw 476; dw 224; dw 480; - dw 484; // Eval sumdlogdiv_b_den Horner step: multiply by xA0 + dw 484; dw 224; dw 488; - dw 492; // Eval sumdlogdiv_b_den Horner step: multiply by xA0 + dw 492; dw 224; dw 496; - dw 500; // Eval sumdlogdiv_b_den Horner step: multiply by xA0 + dw 500; dw 224; dw 504; - dw 508; // Eval sumdlogdiv_b_den Horner step: multiply by xA0 + dw 508; dw 224; dw 512; - dw 516; // Eval sumdlogdiv_b_den Horner step: multiply by xA0 + dw 516; dw 224; dw 520; - dw 524; // Eval sumdlogdiv_b_den Horner step: multiply by xA0 + dw 524; dw 224; dw 528; - dw 532; // None + dw 532; dw 536; dw 468; - dw 228; // None + dw 228; dw 536; dw 540; - dw 32; // Eval sumdlogdiv_a_num Horner step: multiply by xA2 + dw 32; dw 276; dw 548; - dw 552; // Eval sumdlogdiv_a_num Horner step: multiply by xA2 + dw 552; dw 276; dw 556; - dw 560; // Eval sumdlogdiv_a_num Horner step: multiply by xA2 + dw 560; dw 276; dw 564; - dw 568; // Eval sumdlogdiv_a_num Horner step: multiply by xA2 + dw 568; dw 276; dw 572; - dw 56; // Eval sumdlogdiv_a_den Horner step: multiply by xA2 + dw 56; dw 276; dw 580; - dw 584; // Eval sumdlogdiv_a_den Horner step: multiply by xA2 + dw 584; dw 276; dw 588; - dw 592; // Eval sumdlogdiv_a_den Horner step: multiply by xA2 + dw 592; dw 276; dw 596; - dw 600; // Eval sumdlogdiv_a_den Horner step: multiply by xA2 + dw 600; dw 276; dw 604; - dw 608; // Eval sumdlogdiv_a_den Horner step: multiply by xA2 + dw 608; dw 276; dw 612; - dw 616; // None + dw 616; dw 620; dw 576; - dw 80; // Eval sumdlogdiv_b_num Horner step: multiply by xA2 + dw 80; dw 276; dw 624; - dw 628; // Eval sumdlogdiv_b_num Horner step: multiply by xA2 + dw 628; dw 276; dw 632; - dw 636; // Eval sumdlogdiv_b_num Horner step: multiply by xA2 + dw 636; dw 276; dw 640; - dw 644; // Eval sumdlogdiv_b_num Horner step: multiply by xA2 + dw 644; dw 276; dw 648; - dw 652; // Eval sumdlogdiv_b_num Horner step: multiply by xA2 + dw 652; dw 276; dw 656; - dw 116; // Eval sumdlogdiv_b_den Horner step: multiply by xA2 + dw 116; dw 276; dw 664; - dw 668; // Eval sumdlogdiv_b_den Horner step: multiply by xA2 + dw 668; dw 276; dw 672; - dw 676; // Eval sumdlogdiv_b_den Horner step: multiply by xA2 + dw 676; dw 276; dw 680; - dw 684; // Eval sumdlogdiv_b_den Horner step: multiply by xA2 + dw 684; dw 276; dw 688; - dw 692; // Eval sumdlogdiv_b_den Horner step: multiply by xA2 + dw 692; dw 276; dw 696; - dw 700; // Eval sumdlogdiv_b_den Horner step: multiply by xA2 + dw 700; dw 276; dw 704; - dw 708; // Eval sumdlogdiv_b_den Horner step: multiply by xA2 + dw 708; dw 276; dw 712; - dw 716; // Eval sumdlogdiv_b_den Horner step: multiply by xA2 + dw 716; dw 276; dw 720; - dw 724; // None + dw 724; dw 728; dw 660; - dw 292; // None + dw 292; dw 728; dw 732; - dw 352; // None + dw 352; dw 544; dw 740; - dw 344; // None + dw 344; dw 736; dw 744; - dw 256; // None + dw 256; dw 120; dw 756; - dw 144; // None + dw 144; dw 136; dw 776; - dw 764; // None + dw 764; dw 780; dw 752; - dw 776; // None + dw 776; dw 780; dw 784; - dw 148; // None + dw 148; dw 140; dw 788; - dw 772; // None + dw 772; dw 792; dw 752; - dw 788; // None + dw 788; dw 792; dw 796; - dw 256; // None + dw 256; dw 128; dw 812; - dw 160; // None + dw 160; dw 152; dw 832; - dw 820; // None + dw 820; dw 836; dw 808; - dw 832; // None + dw 832; dw 836; dw 840; - dw 164; // None + dw 164; dw 156; dw 844; - dw 828; // None + dw 828; dw 848; dw 808; - dw 844; // None + dw 844; dw 848; dw 852; - dw 256; // None + dw 256; dw 200; dw 868; - dw 880; // None + dw 880; dw 884; dw 864; - dw 256; // None + dw 256; dw 120; dw 896; - dw 176; // None + dw 176; dw 168; dw 916; - dw 904; // None + dw 904; dw 920; dw 892; - dw 916; // None + dw 916; dw 920; dw 924; - dw 180; // None + dw 180; dw 172; dw 928; - dw 912; // None + dw 912; dw 932; dw 892; - dw 928; // None + dw 928; dw 932; dw 936; - dw 256; // None + dw 256; dw 128; dw 952; - dw 192; // None + dw 192; dw 184; dw 972; - dw 960; // None + dw 960; dw 976; dw 948; - dw 972; // None + dw 972; dw 976; dw 980; - dw 196; // None + dw 196; dw 188; dw 984; - dw 968; // None + dw 968; dw 988; dw 948; - dw 984; // None + dw 984; dw 988; dw 992; - dw 256; // None + dw 256; dw 208; dw 1008; - dw 1020; // None + dw 1020; dw 1024; dw 1004; - dw 256; // None + dw 256; dw 208; dw 1036; - dw 1044; // None + dw 1044; dw 1060; dw 1032; - dw 1056; // None + dw 1056; dw 1060; dw 1064; - dw 1052; // None + dw 1052; dw 1068; dw 1032; - dw 12; // None + dw 12; dw 1068; dw 1072; - dw 256; // None + dw 256; dw 216; dw 1084; - dw 1096; // None + dw 1096; dw 1100; dw 1080; - dw 236; // c1 = c0^2 dw 236; + dw 236; + dw 1108; dw 1108; - dw 1108; // c2 = c0^3 dw 236; dw 1112; - dw 888; // rhs_low * c0 + dw 888; dw 236; dw 1116; - dw 1028; // rhs_high * c1 + dw 1028; dw 1108; dw 1120; - dw 1104; // rhs_high_shifted * c2 + dw 1104; dw 1112; dw 1124; - - output_offsets_ptr_loc: - dw 4; } diff --git a/cairo/src/utils/ecdsa_circuit.py b/cairo/src/utils/ecdsa_circuit.py deleted file mode 100644 index 77e8bc44..00000000 --- a/cairo/src/utils/ecdsa_circuit.py +++ /dev/null @@ -1,350 +0,0 @@ -import garaga.hints.io as io -import garaga.modulo_circuit_structs as structs -from garaga.definitions import CURVES, CurveID, G1Point -from garaga.hints import neg_3 -from garaga.hints.ecip import n_coeffs_from_n_points -from garaga.modulo_circuit import WriteOps -from garaga.modulo_circuit_structs import G1PointCircuit, u384 -from garaga.precompiled_circuits.compilable_circuits.base import ( - BaseModuloCircuit, - ModuloCircuit, - PyFelt, -) -from garaga.precompiled_circuits.ec import ECIPCircuits -from garaga.starknet.tests_and_calldata_generators.msm import MSMCalldataBuilder - - -class FullEcdsaCircuitBatched(BaseModuloCircuit): - def __init__( - self, - curve_id: int, - n_points: int = 2, - auto_run: bool = True, - compilation_mode: int = 0, - ) -> None: - self.n_points = n_points - super().__init__( - name=f"full_ecip_{n_points}P", - curve_id=curve_id, - auto_run=auto_run, - compilation_mode=compilation_mode, - ) - - def build_input(self) -> list[PyFelt]: - input = [] - n_coeffs = n_coeffs_from_n_points(self.n_points, batched=True) - - # RLCSumDlogDiv - for _ in range(sum(n_coeffs)): - input.append(self.field.random()) - - for _ in range(self.n_points): - input.append(self.field.random()) # x - input.append(self.field.random()) # y - input.append(self.field.random()) # ep_low - input.append(self.field.random()) # en_low - input.append(self.field.random()) # sp_low - input.append(self.field.random()) # sn_low - input.append(self.field.random()) # ep_high - input.append(self.field.random()) # en_high - input.append(self.field.random()) # sp_high - input.append(self.field.random()) # sn_high - - # Q_low/high/high_shifted + A0 - for i in range(4): - input.append(self.field.random()) # x - input.append(self.field.random()) # y - - input.append(self.field(CURVES[self.curve_id].a)) # A_weirstrass - input.append(self.field.random()) # base_rlc. - - return input - - def sample_input(self): - cid = CurveID(self.curve_id) - pts = [ - G1Point.get_nG(cid, 1), - G1Point( - x=111354266934415748707439662129962068258185897787462436790090135304890680225071, - y=7955571364956903103447762143713116749685657035734622395391095226875188998922, - curve_id=CurveID.SECP256K1, - ), - ] - scalars = [ - 0xF6F935191273414ADA91071ED97A8A31347F85D5FAC890148FDAC827E0426B68, - 0x4FDA889C1E0B2F466819231FBF731EBFF91B507CC44A0C810B0DECDEAA99B7D2, - ] - builder = MSMCalldataBuilder(cid, pts, scalars) - (msm_hint, derive_point_from_x_hint) = builder.build_msm_hints() - scalars_low, scalars_high = builder.scalars_split() - epns_low, epns_high = [neg_3.scalar_to_base_neg3_le(s) for s in scalars_low], [ - neg_3.scalar_to_base_neg3_le(s) for s in scalars_high - ] - - Q_low, Q_high, Q_high_shifted, RLCSumDlogDiv = msm_hint.elmts - - rlc_sum_dlog_div_coeffs = ( - RLCSumDlogDiv.a_num - + RLCSumDlogDiv.a_den - + RLCSumDlogDiv.b_num - + RLCSumDlogDiv.b_den - ) - - assert len(rlc_sum_dlog_div_coeffs) == sum( - n_coeffs_from_n_points(self.n_points, batched=True) - ) - - input = [] - input.extend(rlc_sum_dlog_div_coeffs) - - def sign(x): - return 1 if x >= 0 else -1 - - for i in range(self.n_points): - input.append(self.field(pts[i].x)) - input.append(self.field(pts[i].y)) - print(f"pt_{i}: epns_low: {epns_low[i]}") - input.append(self.field(epns_low[i][0])) - input.append(self.field(epns_low[i][1])) - input.append(self.field(epns_low[i][2])) - input.append(self.field(epns_low[i][3])) - print(f"pt_{i}: epns_high: {epns_high[i]}") - input.append(self.field(epns_high[i][0])) - input.append(self.field(epns_high[i][1])) - input.append(self.field(epns_high[i][2])) - input.append(self.field(epns_high[i][3])) - - input.extend(Q_low.elmts) - input.extend(Q_high.elmts) - input.extend(Q_high_shifted.elmts) - _random = builder.A0 - print(f"A0 : {_random.to_cairo_1()}") - input.extend([self.field(_random.x), self.field(_random.y)]) - input.append(self.field(CURVES[self.curve_id].a)) # A_weirstrass - input.append(self.field(builder.rlc_coeff)) # base_rlc - - return input - - def _run_circuit_inner(self, input: list[PyFelt]) -> ModuloCircuit: - circuit = ECIPCircuits( - self.name, self.curve_id, compilation_mode=self.compilation_mode - ) - n_coeffs = n_coeffs_from_n_points(self.n_points, batched=True) - ff_coeffs = input[: sum(n_coeffs)] - - def split_list(input_list, lengths): - start_idx, result = 0, [] - for length in lengths: - result.append(input_list[start_idx : start_idx + length]) - start_idx += length - return result - - def get_log_div_coeffs(circuit, ff_coeffs): - _log_div_a_num, _log_div_a_den, _log_div_b_num, _log_div_b_den = split_list( - ff_coeffs, n_coeffs_from_n_points(self.n_points, batched=True) - ) - log_div_a_num, log_div_a_den, log_div_b_num, log_div_b_den = ( - circuit.write_struct( - structs.FunctionFeltCircuit( - name="SumDlogDiv", - elmts=[ - structs.u384Span("log_div_a_num", _log_div_a_num), - structs.u384Span("log_div_a_den", _log_div_a_den), - structs.u384Span("log_div_b_num", _log_div_b_num), - structs.u384Span("log_div_b_den", _log_div_b_den), - ], - ), - WriteOps.INPUT, - ) - ) - - return log_div_a_num, log_div_a_den, log_div_b_num, log_div_b_den - - log_div_a_num_low, log_div_a_den_low, log_div_b_num_low, log_div_b_den_low = ( - get_log_div_coeffs(circuit, ff_coeffs) - ) - - all_points = input[sum(n_coeffs) :] - - points = [] - ep_lows = [] - en_lows = [] - sp_lows = [] - sn_lows = [] - ep_highs = [] - en_highs = [] - sp_highs = [] - sn_highs = [] - for i in range(self.n_points): - print(f"i: {i}") - base_idx = i * 10 - pt_circuit = G1PointCircuit(f"p_{i}", all_points[base_idx : base_idx + 2]) - pt_circuit.validate(self.curve_id) - points.append(circuit.write_struct(pt_circuit)) - ep_lows.append(all_points[base_idx + 2]) - en_lows.append(all_points[base_idx + 3]) - sp_lows.append(all_points[base_idx + 4]) - sn_lows.append(all_points[base_idx + 5]) - ep_highs.append(all_points[base_idx + 6]) - en_highs.append(all_points[base_idx + 7]) - sp_highs.append(all_points[base_idx + 8]) - sn_highs.append(all_points[base_idx + 9]) - - epns_low = circuit.write_struct( - structs.StructSpan( - "epns_low", - [ - structs.Tuple( - f"epn_{i}", - elmts=[ - structs.u384("ep", [ep_lows[i]]), - structs.u384("en", [en_lows[i]]), - structs.u384("sp", [sp_lows[i]]), - structs.u384("sn", [sn_lows[i]]), - ], - ) - for i in range(self.n_points) - ], - ) - ) - - print(f"epns_low: {epns_low} (n_points: {self.n_points})") - - epns_high = circuit.write_struct( - structs.StructSpan( - "epns_high", - [ - structs.Tuple( - f"epn_{i}", - elmts=[ - structs.u384("ep", [ep_highs[i]]), - structs.u384("en", [en_highs[i]]), - structs.u384("sp", [sp_highs[i]]), - structs.u384("sn", [sn_highs[i]]), - ], - ) - for i in range(self.n_points) - ], - ) - ) - - rest_points = all_points[self.n_points * 10 :] - q_low = circuit.write_struct( - structs.G1PointCircuit("q_low", elmts=rest_points[0:2]) - ) - q_high = circuit.write_struct( - structs.G1PointCircuit("q_high", elmts=rest_points[2:4]) - ) - - q_high_shifted = circuit.write_struct( - structs.G1PointCircuit("q_high_shifted", elmts=rest_points[4:6]), - ) - random_point = structs.G1PointCircuit("a0", elmts=rest_points[6:8]) - random_point.validate(self.curve_id) - a0 = circuit.write_struct(random_point) - - A_weirstrass = circuit.write_struct( - structs.u384("A_weirstrass", elmts=[rest_points[8]]) - ) - base_rlc = circuit.write_struct( - structs.u384("base_rlc", elmts=[rest_points[9]]) - ) - - m_A0, b_A0, xA0, yA0, xA2, yA2, coeff0, coeff2 = ( - circuit._slope_intercept_same_point(a0, A_weirstrass) - ) - - lhs = circuit._eval_function_challenge_dupl( - (xA0, yA0), - (xA2, yA2), - coeff0, - coeff2, - log_div_a_num_low, - log_div_a_den_low, - log_div_b_num_low, - log_div_b_den_low, - ) - - def compute_base_rhs(circuit: ECIPCircuits, points, epns, m_A0, b_A0, xA0): - acc = circuit.set_or_get_constant(0) - for i, (pt, _epns) in enumerate(zip(points, epns)): - _epns = io.flatten(_epns) - print(f"i: {i}, _epns: {_epns}") - acc = circuit._accumulate_eval_point_challenge_signed_same_point( - eval_accumulator=acc, - slope_intercept=(m_A0, b_A0), - xA=xA0, - P=pt, - ep=_epns[0], - en=_epns[1], - sign_ep=_epns[2], - sign_en=_epns[3], - ) - return acc - - base_rhs_low = compute_base_rhs(circuit, points, epns_low, m_A0, b_A0, xA0) - rhs_low = circuit._RHS_finalize_acc( - base_rhs_low, - (m_A0, b_A0), - xA0, - (q_low[0], q_low[1]), - ) - - base_rhs_high = compute_base_rhs(circuit, points, epns_high, m_A0, b_A0, xA0) - rhs_high = circuit._RHS_finalize_acc( - base_rhs_high, (m_A0, b_A0), xA0, (q_high[0], q_high[1]) - ) - - base_rhs_high_shifted = ( - circuit._compute_eval_point_challenge_signed_same_point_2_pow_128( - (m_A0, b_A0), - xA0, - q_high, - ) - ) - rhs_high_shifted = circuit._RHS_finalize_acc( - base_rhs_high_shifted, - (m_A0, b_A0), - xA0, - (q_high_shifted[0], q_high_shifted[1]), - ) - - c0 = base_rlc - c1 = circuit.mul(c0, c0, "c1 = c0^2") - c2 = circuit.mul(c1, c0, "c2 = c0^3") - - rhs = circuit.sum( - [ - circuit.mul(rhs_low, c0, "rhs_low * c0"), - circuit.mul(rhs_high, c1, "rhs_high * c1"), - circuit.mul(rhs_high_shifted, c2, "rhs_high_shifted * c2"), - ], - "Sum of rhs_low * c0, rhs_high * c1, rhs_high_shifted * c2", - ) - - final_check = circuit.sub_and_assert( - lhs, rhs, circuit.set_or_get_constant(0), "Assert lhs - rhs = 0" - ) - - assert lhs.value == rhs.value, "lhs and rhs must be equal" - circuit.extend_struct_output(u384("final_check", [final_check])) - - return circuit - - -if __name__ == "__main__": - circuit = FullEcdsaCircuitBatched( - CurveID.SECP256K1.value, n_points=2, auto_run=False - ) - input = circuit.sample_input() - print(f"input = {[hex(v.value) for v in input]} len : {len(input)}") - circuit.circuit = circuit._run_circuit_inner(input) - - code, _ = circuit.circuit.compile_circuit() - - # # Print constants : - # print(circuit.circuit.constants) - - print(circuit.circuit.print_value_segment(base=16)) - - # print(code) diff --git a/cairo/src/utils/signature.cairo b/cairo/src/utils/signature.cairo index c4b03ae2..4371d89b 100644 --- a/cairo/src/utils/signature.cairo +++ b/cairo/src/utils/signature.cairo @@ -20,11 +20,7 @@ from src.utils.circuit_utils import ( scalar_to_epns, run_modulo_circuit_basic, ) -from src.utils.ecdsa_circuit import ( - get_full_ecip_2P_circuit, - get_ADD_EC_POINT_circuit, - get_DOUBLE_EC_POINT_circuit, -) +from src.utils.ecdsa_circuit import get_full_ecip_2P_circuit from src.utils.uint256 import assert_uint256_le from src.utils.uint384 import ( uint384_to_uint256, @@ -39,7 +35,8 @@ from src.curve.secp256k1 import ( secp256k1, get_generator_point, try_get_point_from_x, - get_point_from_x, + get_random_point, + ec_add, ) from src.curve.g1_point import G1Point @@ -56,21 +53,7 @@ func sign_to_uint384_mod_secp256k1(sign: felt) -> UInt384 { } } -// A function field element of the form : -// F(x,y) = a(x) + y b(x) -// Where a, b are rational functions of x. -// The rational functions are represented as polynomials in x with coefficients in F_p, starting from the constant term. -// No information about the degrees of the polynomials is stored here as they are derived implicitly from the MSM size. -struct FunctionFelt { - a_num: UInt384*, - a_den: UInt384*, - b_num: UInt384*, - b_den: UInt384*, -} - namespace Signature { - // A version of verify_eth_signature that uses the keccak builtin. - // Assert 1 <= x < N. Assumes valid Uint256. func validate_signature_entry{range_check_ptr}(x: Uint256) { if (x.high == 0) { @@ -103,14 +86,13 @@ namespace Signature { poseidon_ptr: PoseidonBuiltin*, }(msg_hash: Uint256, r: Uint256, s: Uint256, y_parity: felt, eth_address: felt) { alloc_locals; - let msg_hash_uint384: UInt384 = uint256_to_uint384(msg_hash); - // Todo :fix with UInt384 with_attr error_message("Signature out of range.") { validate_signature_entry(r); validate_signature_entry(s); } - let r_uint384: UInt384 = uint256_to_uint384(r); - let s_uint384: UInt384 = uint256_to_uint384(s); + let msg_hash_uint384 = uint256_to_uint384(msg_hash); + let r_uint384 = uint256_to_uint384(r); + let s_uint384 = uint256_to_uint384(s); with_attr error_message("Invalid y_parity") { assert (1 - y_parity) * y_parity = 0; @@ -121,9 +103,9 @@ namespace Signature { msg_hash=msg_hash_uint384, r=r_uint384, s=s_uint384, y_parity=y_parity ); assert success = 1; + assert eth_address = recovered_address; } - assert eth_address = recovered_address; return (); } @@ -277,7 +259,7 @@ namespace Signature { let rlc_coeff_u384 = felt_to_uint384(rlc_coeff); // Hash sumdlogdiv 2 points : (4-29) - let (_random_x_coord, _, _) = hash_full_transcript_and_get_Z_3_LIMBS( + let (seed, _, _) = hash_full_transcript_and_get_Z_3_LIMBS( cast(range_check96_ptr + 4 * N_LIMBS, felt*), 26 ); @@ -285,8 +267,8 @@ namespace Signature { tempvar range_check96_ptr_after_circuit = range_check96_ptr + 224 + (4 + 117 + 108 - 1) * N_LIMBS; - let random_point = get_point_from_x{range_check96_ptr=range_check96_ptr_after_circuit}( - x=_random_x_coord, attempt=0 + let random_point = get_random_point{range_check96_ptr=range_check96_ptr_after_circuit}( + seed=seed ); tempvar range_check96_ptr_final = range_check96_ptr_after_circuit; @@ -341,7 +323,7 @@ namespace Signature { assert ecip_input[56] = random_point.x; assert ecip_input[57] = random_point.y; - // a_weirstrass + // a_Weierstrass assert ecip_input[58] = UInt384(secp256k1.A0, secp256k1.A1, secp256k1.A2, secp256k1.A3); // base_rlc assert ecip_input[59] = rlc_coeff_u384; @@ -372,12 +354,31 @@ namespace Signature { tempvar range_check96_ptr = range_check96_ptr_final; let add_mod_ptr = add_mod_ptr + 117 * ModBuiltin.SIZE; let mul_mod_ptr = mul_mod_ptr + 108 * ModBuiltin.SIZE; - let (res) = add_ec_points_secp256k1( + let res = ec_add( G1Point(x=ecip_input[50], y=ecip_input[51]), G1Point(x=ecip_input[54], y=ecip_input[55]) ); return (public_key_point=res, success=1); } + // @notice Converts a public key point to the corresponding Ethereum address. + // @param x The x coordinate of the public key point. + // @param y The y coordinate of the public key point. + // @return The Ethereum address. + func public_key_point_to_eth_address{ + range_check_ptr, bitwise_ptr: BitwiseBuiltin*, keccak_ptr: KeccakBuiltin* + }(x: Uint256, y: Uint256) -> felt { + alloc_locals; + let (local elements: Uint256*) = alloc(); + assert elements[0] = x; + assert elements[1] = y; + let (point_hash: Uint256) = keccak_uint256s_bigend(n_elements=2, elements=elements); + + // The Ethereum address is the 20 least significant bytes of the keccak of the public key. + let (_, high_low) = unsigned_div_rem(point_hash.high, 2 ** 32); + let eth_address = point_hash.low + RC_BOUND * high_low; + return eth_address; + } + // @notice Recovers the Ethereum address from a signature. // @dev If the public key point is not on the curve, the function returns success=0. // @dev: This function does not validate the r, s values. @@ -407,95 +408,7 @@ namespace Signature { assert_uint256_le(x_uint256, max_value); let y_uint256 = uint384_to_uint256(public_key_point.y); assert_uint256_le(y_uint256, max_value); - let address = Internals.public_key_point_to_eth_address(x=x_uint256, y=y_uint256); + let address = public_key_point_to_eth_address(x=x_uint256, y=y_uint256); return (success=success, address=address); } } - -namespace Internals { - // @notice Converts a public key point to the corresponding Ethereum address. - // @param x The x coordinate of the public key point. - // @param y The y coordinate of the public key point. - // @return The Ethereum address. - func public_key_point_to_eth_address{ - range_check_ptr, bitwise_ptr: BitwiseBuiltin*, keccak_ptr: KeccakBuiltin* - }(x: Uint256, y: Uint256) -> felt { - alloc_locals; - let (local elements: Uint256*) = alloc(); - assert elements[0] = x; - assert elements[1] = y; - let (point_hash: Uint256) = keccak_uint256s_bigend(n_elements=2, elements=elements); - - // The Ethereum address is the 20 least significant bytes of the keccak of the public key. - let (_, high_low) = unsigned_div_rem(point_hash.high, 2 ** 32); - let eth_address = point_hash.low + RC_BOUND * high_low; - return eth_address; - } -} - -// Add two EC points. Doesn't check if the inputs are on curve nor if they are the point at infinity. -func add_ec_points_secp256k1{ - range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin* -}(P: G1Point, Q: G1Point) -> (res: G1Point) { - alloc_locals; - let (__fp__, _) = get_fp_and_pc(); - let modulus = UInt384(secp256k1.P0, secp256k1.P1, secp256k1.P2, secp256k1.P3); - let same_x = uint384_eq_mod_p(P.x, Q.x, modulus); - - if (same_x != 0) { - let opposite_y = uint384_is_neg_mod_p(P.y, Q.y, modulus); - - if (opposite_y != 0) { - // P + (-P) = O (point at infinity) - return (res=G1Point(UInt384(0, 0, 0, 0), UInt384(0, 0, 0, 0))); - } else { - // P = Q, so we need to double the point - let (add_offsets, mul_offsets) = get_DOUBLE_EC_POINT_circuit(); - let input: UInt384* = cast(range_check96_ptr, UInt384*); - assert input[0] = UInt384(3, 0, 0, 0); - assert input[1] = P.x; - assert input[2] = P.y; - assert input[3] = UInt384(secp256k1.A0, secp256k1.A1, secp256k1.A2, secp256k1.A3); - - run_modulo_circuit_basic( - p=modulus, - add_offsets_ptr=add_offsets, - add_n=6, - mul_offsets_ptr=mul_offsets, - mul_n=5, - input_len=4, - n_assert_eq=0, - ); - return ( - res=G1Point( - x=[cast(cast(input, felt*) + 44, UInt384*)], - y=[cast(cast(input, felt*) + 56, UInt384*)], - ), - ); - } - } else { - // P and Q have different x-coordinates, perform regular addition - let (add_offsets, mul_offsets) = get_ADD_EC_POINT_circuit(); - let input: UInt384* = cast(range_check96_ptr, UInt384*); - assert input[0] = P.x; - assert input[1] = P.y; - assert input[2] = Q.x; - assert input[3] = Q.y; - - run_modulo_circuit_basic( - p=modulus, - add_offsets_ptr=add_offsets, - add_n=6, - mul_offsets_ptr=mul_offsets, - mul_n=3, - input_len=4, - n_assert_eq=0, - ); - return ( - res=G1Point( - x=[cast(cast(input, felt*) + 36, UInt384*)], - y=[cast(cast(input, felt*) + 48, UInt384*)], - ), - ); - } -} diff --git a/cairo/tests/src/curve/test_secp256k1.cairo b/cairo/tests/src/curve/test_secp256k1.cairo index 565b1420..330b4e04 100644 --- a/cairo/tests/src/curve/test_secp256k1.cairo +++ b/cairo/tests/src/curve/test_secp256k1.cairo @@ -1,7 +1,13 @@ -from starkware.cairo.common.cairo_builtins import UInt384, ModBuiltin +from starkware.cairo.common.cairo_builtins import UInt384, ModBuiltin, PoseidonBuiltin from starkware.cairo.common.alloc import alloc -from src.curve.secp256k1 import get_generator_point, try_get_point_from_x +from src.curve.secp256k1 import ( + get_generator_point, + try_get_point_from_x, + get_random_point, + ec_double, + ec_add, +) from src.curve.g1_point import G1Point func test__get_generator_point() { @@ -36,3 +42,56 @@ func test__try_get_point_from_x{ tempvar y_ptr = new UInt384(y.d0, y.d1, y.d2, y.d3); return (y_ptr, is_on_curve); } + +func test__get_random_point{ + range_check96_ptr: felt*, + add_mod_ptr: ModBuiltin*, + mul_mod_ptr: ModBuiltin*, + poseidon_ptr: PoseidonBuiltin*, +}() -> G1Point* { + alloc_locals; + tempvar seed; + %{ ids.seed = program_input["seed"] %} + + let point = get_random_point(seed); + tempvar point_ptr = new G1Point( + UInt384(point.x.d0, point.x.d1, point.x.d2, point.x.d3), + UInt384(point.y.d0, point.y.d1, point.y.d2, point.y.d3), + ); + return point_ptr; +} + +func test__ec_double{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin*}( + ) -> G1Point* { + alloc_locals; + let (p_ptr) = alloc(); + %{ segments.write_arg(ids.p_ptr, program_input["p"]) %} + + let p = [cast(p_ptr, G1Point*)]; + let res = ec_double(p); + tempvar res_ptr = new G1Point( + UInt384(res.x.d0, res.x.d1, res.x.d2, res.x.d3), + UInt384(res.y.d0, res.y.d1, res.y.d2, res.y.d3), + ); + return res_ptr; +} + +func test__ec_add{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin*}( + ) -> G1Point* { + alloc_locals; + let (p_ptr) = alloc(); + let (q_ptr) = alloc(); + %{ + segments.write_arg(ids.p_ptr, program_input["p"]) + segments.write_arg(ids.q_ptr, program_input["q"]) + %} + + let p = [cast(p_ptr, G1Point*)]; + let q = [cast(q_ptr, G1Point*)]; + let res = ec_add(p, q); + tempvar res_ptr = new G1Point( + UInt384(res.x.d0, res.x.d1, res.x.d2, res.x.d3), + UInt384(res.y.d0, res.y.d1, res.y.d2, res.y.d3), + ); + return res_ptr; +} diff --git a/cairo/tests/src/curve/test_secp256k1.py b/cairo/tests/src/curve/test_secp256k1.py index db628d28..db7d7f51 100644 --- a/cairo/tests/src/curve/test_secp256k1.py +++ b/cairo/tests/src/curve/test_secp256k1.py @@ -1,17 +1,27 @@ import hypothesis.strategies as st import pytest from hypothesis import given -from starkware.cairo.lang.cairo_constants import DEFAULT_PRIME from sympy import sqrt_mod +from ethereum.crypto.elliptic_curve import EllipticCurve +from ethereum.crypto.finite_field import PrimeField from src.utils.uint384 import int_to_uint384, uint384_to_int +from tests.utils.strategies import felt pytestmark = pytest.mark.python_vm -A = 0 -B = 7 -G = 3 -P = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F -N = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 + + +class Secp256k1P(PrimeField): + PRIME = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F + + +class Secp256k1(EllipticCurve): + FIELD = Secp256k1P + A = Secp256k1P(0) + B = Secp256k1P(7) + + +uint384 = st.integers(min_value=0, max_value=2**384 - 1) class TestSecp256k1: @@ -21,18 +31,150 @@ def test_get_generator_point(self, cairo_run): cairo_run("test__get_generator_point") class TestTryGetPointFromX: - @given( - x=st.integers(min_value=0, max_value=2**384 - 1), - v=st.integers(min_value=0, max_value=DEFAULT_PRIME - 1), - ) + @given(x=uint384, v=felt) def test_try_get_point_from_x(self, cairo_run, x, v): y_try, is_on_curve = cairo_run( - "test__try_get_point_from_x", x=int_to_uint384(x % P), v=v + "test__try_get_point_from_x", + x=int_to_uint384(x % Secp256k1.FIELD.PRIME), + v=v, ) - square_root = sqrt_mod(x**3 + A * x + B, P) + square_root = sqrt_mod( + x**3 + Secp256k1.A * x + Secp256k1.B, Secp256k1.FIELD.PRIME + ) assert (square_root is not None) == is_on_curve if square_root is not None: assert ( - square_root if (v % 2 == square_root % 2) else (-square_root % P) + square_root + if (v % 2 == square_root % 2) + else (-square_root % Secp256k1.FIELD.PRIME) ) == uint384_to_int(y_try["d0"], y_try["d1"], y_try["d2"], y_try["d3"]) + + class TestGetRandomPoint: + @given(seed=felt) + def test_should_return_a_point_on_the_curve(self, cairo_run, seed): + point = cairo_run("test__get_random_point", seed=seed) + x = uint384_to_int( + point["x"]["d0"], + point["x"]["d1"], + point["x"]["d2"], + point["x"]["d3"], + ) + y = uint384_to_int( + point["y"]["d0"], + point["y"]["d1"], + point["y"]["d2"], + point["y"]["d3"], + ) + assert ( + x**3 + Secp256k1.A * x + Secp256k1.B + ) % Secp256k1.FIELD.PRIME == y**2 % Secp256k1.FIELD.PRIME + + class TestEcDouble: + @given(seed=felt) + def test_ec_double(self, cairo_run, seed): + point = cairo_run("test__get_random_point", seed=seed) + x = Secp256k1P( + uint384_to_int( + point["x"]["d0"], + point["x"]["d1"], + point["x"]["d2"], + point["x"]["d3"], + ) + ) + y = Secp256k1P( + uint384_to_int( + point["y"]["d0"], + point["y"]["d1"], + point["y"]["d2"], + point["y"]["d3"], + ) + ) + double = cairo_run( + "test__ec_double", + p=( + point["x"]["d0"], + point["x"]["d1"], + point["x"]["d2"], + point["x"]["d3"], + point["y"]["d0"], + point["y"]["d1"], + point["y"]["d2"], + point["y"]["d3"], + ), + ) + assert Secp256k1(x, y).double() == Secp256k1( + uint384_to_int( + double["x"]["d0"], + double["x"]["d1"], + double["x"]["d2"], + double["x"]["d3"], + ), + uint384_to_int( + double["y"]["d0"], + double["y"]["d1"], + double["y"]["d2"], + double["y"]["d3"], + ), + ) + + class TestEcAdd: + @given(seed=felt) + def test_ec_add(self, cairo_run, seed): + p = cairo_run("test__get_random_point", seed=seed) + q = cairo_run("test__get_random_point", seed=p["x"]["d0"]) + res = cairo_run( + "test__ec_add", + p=( + p["x"]["d0"], + p["x"]["d1"], + p["x"]["d2"], + p["x"]["d3"], + p["y"]["d0"], + p["y"]["d1"], + p["y"]["d2"], + p["y"]["d3"], + ), + q=( + q["x"]["d0"], + q["x"]["d1"], + q["x"]["d2"], + q["x"]["d3"], + q["y"]["d0"], + q["y"]["d1"], + q["y"]["d2"], + q["y"]["d3"], + ), + ) + assert Secp256k1( + Secp256k1P( + uint384_to_int( + p["x"]["d0"], p["x"]["d1"], p["x"]["d2"], p["x"]["d3"] + ) + ), + Secp256k1P( + uint384_to_int( + p["y"]["d0"], p["y"]["d1"], p["y"]["d2"], p["y"]["d3"] + ) + ), + ) + ( + Secp256k1( + Secp256k1P( + uint384_to_int( + q["x"]["d0"], q["x"]["d1"], q["x"]["d2"], q["x"]["d3"] + ) + ), + Secp256k1P( + uint384_to_int( + q["y"]["d0"], q["y"]["d1"], q["y"]["d2"], q["y"]["d3"] + ) + ), + ) + ) == Secp256k1( + uint384_to_int( + res["x"]["d0"], res["x"]["d1"], res["x"]["d2"], res["x"]["d3"] + ), + uint384_to_int( + res["y"]["d0"], res["y"]["d1"], res["y"]["d2"], res["y"]["d3"] + ), + ) diff --git a/cairo/tests/src/utils/test_signature.cairo b/cairo/tests/src/utils/test_signature.cairo index 4fc81517..67aceea1 100644 --- a/cairo/tests/src/utils/test_signature.cairo +++ b/cairo/tests/src/utils/test_signature.cairo @@ -8,7 +8,7 @@ from starkware.cairo.common.cairo_builtins import ( ) from starkware.cairo.common.cairo_secp.bigint import uint256_to_bigint -from src.utils.signature import Signature, Internals +from src.utils.signature import Signature from src.utils.uint256 import uint256_eq from src.utils.uint384 import uint256_to_uint384 @@ -21,7 +21,7 @@ func test__public_key_point_to_eth_address{ mul_mod_ptr: ModBuiltin*, poseidon_ptr: PoseidonBuiltin*, }(x: U256, y: U256) -> felt { - let eth_address = Internals.public_key_point_to_eth_address(x=[x.value], y=[y.value]); + let eth_address = Signature.public_key_point_to_eth_address(x=[x.value], y=[y.value]); return eth_address; } From e1b3ad0f53ed343719004771a9fad676b108c429 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Walter?= Date: Thu, 23 Jan 2025 11:39:24 +0100 Subject: [PATCH 12/17] Remove unused util --- cairo/src/utils/circuit_utils.cairo | 37 ----------------------------- cairo/src/utils/signature.cairo | 1 - 2 files changed, 38 deletions(-) diff --git a/cairo/src/utils/circuit_utils.cairo b/cairo/src/utils/circuit_utils.cairo index 5f0c68d1..a19d5a48 100644 --- a/cairo/src/utils/circuit_utils.cairo +++ b/cairo/src/utils/circuit_utils.cairo @@ -173,40 +173,3 @@ func scalar_to_epns{range_check_ptr}(scalar: felt) -> ( return (p_sign * sum_p, n_sign * sum_n, p_sign, n_sign); } - -func run_modulo_circuit_basic{ - range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin* -}( - p: UInt384, - add_offsets_ptr: felt*, - add_n: felt, - mul_offsets_ptr: felt*, - mul_n: felt, - input_len: felt, - n_assert_eq: felt, -) { - assert add_mod_ptr[0] = ModBuiltin( - p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=add_offsets_ptr, n=add_n - ); - - assert mul_mod_ptr[0] = ModBuiltin( - p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=mul_offsets_ptr, n=mul_n - ); - - %{ - from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner - assert builtin_runners["add_mod_builtin"].instance_def.batch_size == 1 - assert builtin_runners["mul_mod_builtin"].instance_def.batch_size == 1 - - ModBuiltinRunner.fill_memory( - memory=memory, - add_mod=(ids.add_mod_ptr.address_, builtin_runners["add_mod_builtin"], ids.add_n), - mul_mod=(ids.mul_mod_ptr.address_, builtin_runners["mul_mod_builtin"], ids.mul_n), - ) - %} - - let range_check96_ptr = range_check96_ptr + (input_len + add_n + mul_n - n_assert_eq) * N_LIMBS; - let add_mod_ptr = &add_mod_ptr[add_n]; - let mul_mod_ptr = &mul_mod_ptr[mul_n]; - return (); -} diff --git a/cairo/src/utils/signature.cairo b/cairo/src/utils/signature.cairo index 4371d89b..dbe1a3b6 100644 --- a/cairo/src/utils/signature.cairo +++ b/cairo/src/utils/signature.cairo @@ -18,7 +18,6 @@ from src.utils.circuit_utils import ( N_LIMBS, hash_full_transcript_and_get_Z_3_LIMBS, scalar_to_epns, - run_modulo_circuit_basic, ) from src.utils.ecdsa_circuit import get_full_ecip_2P_circuit from src.utils.uint256 import assert_uint256_le From d98b31b837965583543517f0dfb2f80efb8843e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Walter?= Date: Thu, 23 Jan 2025 12:09:01 +0100 Subject: [PATCH 13/17] Extract math utils and test --- cairo/src/utils/circuit_utils.cairo | 109 +------------------------ cairo/src/utils/maths.cairo | 105 ++++++++++++++++++++++++ cairo/src/utils/signature.cairo | 8 +- cairo/tests/src/utils/test_maths.cairo | 15 ++++ cairo/tests/src/utils/test_maths.py | 30 +++++++ 5 files changed, 153 insertions(+), 114 deletions(-) create mode 100644 cairo/tests/src/utils/test_maths.cairo create mode 100644 cairo/tests/src/utils/test_maths.py diff --git a/cairo/src/utils/circuit_utils.cairo b/cairo/src/utils/circuit_utils.cairo index a19d5a48..b85c36a4 100644 --- a/cairo/src/utils/circuit_utils.cairo +++ b/cairo/src/utils/circuit_utils.cairo @@ -1,9 +1,4 @@ -from starkware.cairo.common.alloc import alloc -from starkware.cairo.common.cairo_builtins import PoseidonBuiltin, UInt384, ModBuiltin -from starkware.cairo.common.poseidon_state import PoseidonBuiltinState -from starkware.cairo.common.uint256 import Uint256 -from starkware.cairo.common.registers import get_fp_and_pc, get_label_location -from starkware.cairo.common.math import assert_le_felt +from starkware.cairo.common.cairo_builtins import PoseidonBuiltin const N_LIMBS = 4; @@ -71,105 +66,3 @@ func hash_full_transcript_and_get_Z_3_LIMBS{poseidon_ptr: PoseidonBuiltin*}( tempvar s2 = [res_ptr].output.s2; return (_s0=s0, _s1=s1, _s2=s2); } - -// Returns the sign of value: -1 if value < 0, 1 if value > 0. -// value is considered positive if it is in [0, STARK//2[ -// value is considered negative if it is in ]STARK//2, STARK[ -// If value == 0, returned value can be either 0 or 1 (undetermined). -func sign{range_check_ptr}(value) -> felt { - const STARK_DIV_2_PLUS_ONE = (-1) / 2 + 1; // == prime//2 + 1 - const STARK_DIV_2_MIN_ONE = (-1) / 2 - 1; // == prime//2 - 1 - tempvar is_positive: felt; - %{ - from starkware.cairo.common.math_utils import as_int - ids.is_positive = 1 if as_int(ids.value, PRIME) >= 0 else 0 - %} - if (is_positive != 0) { - assert_le_felt(value, STARK_DIV_2_MIN_ONE); - return 1; - } else { - assert_le_felt(STARK_DIV_2_PLUS_ONE, value); - return -1; - } -} - -// From a 128 bit scalar, decomposes it into base (-3) such that -// scalar = sum(digits[i] * (-3)^i for i in [0, 81]) -// digits[i] in {-1, 0, 1} for all i -// scalar = sum_p - sum_n -// sum_p = sum(digits[i] * (-3)^i for i in [0, 81] if digits[i]==1) -// sum_n = sum(digits[i] * (-3)^i for i in [0, 81] if digits[i]==-1) -// Returns (abs(sum_p), abs(sum_n), p_sign, n_sign) -func scalar_to_epns{range_check_ptr}(scalar: felt) -> ( - sum_p: felt, sum_n: felt, p_sign: felt, n_sign: felt -) { - %{ - from garaga.hints.neg_3 import neg_3_base_le, positive_negative_multiplicities - from starkware.cairo.common.math_utils import as_int - assert 0 <= ids.scalar < 2**128 - digits = neg_3_base_le(ids.scalar) - digits = digits + [0] * (82-len(digits)) - i=1 # Loop init - %} - - tempvar d0; - %{ ids.d0 = digits[0] %} - - if (d0 != 0) { - if (d0 == 1) { - tempvar sum_p = 1; - tempvar sum_n = 0; - } else { - tempvar sum_p = 0; - tempvar sum_n = 1; - } - } else { - tempvar sum_p = 0; - tempvar sum_n = 0; - } - - tempvar pow3 = -3; - - loop: - let sum_p = [ap - 3]; - let sum_n = [ap - 2]; - let pow3 = [ap - 1]; - %{ memory[ap] = 1 if i == 82 else 0 %} - jmp end if [ap] != 0, ap++; - - %{ i+=1 %} - - tempvar di; - %{ ids.di = digits[i-1] %} - if (di != 0) { - if (di == 1) { - tempvar sum_p = sum_p + pow3; - tempvar sum_n = sum_n; - tempvar pow3 = pow3 * (-3); - jmp loop; - } else { - tempvar sum_p = sum_p; - tempvar sum_n = sum_n + pow3; - tempvar pow3 = pow3 * (-3); - jmp loop; - } - } else { - tempvar sum_p = sum_p; - tempvar sum_n = sum_n; - tempvar pow3 = pow3 * (-3); - jmp loop; - } - - end: - let pow3 = [ap - 2]; - let sum_n = [ap - 3]; - let sum_p = [ap - 4]; - assert pow3 = (-3) ** 82; - - assert scalar = sum_p - sum_n; - - let p_sign = sign(sum_p); - let n_sign = sign(sum_n); - - return (p_sign * sum_p, n_sign * sum_n, p_sign, n_sign); -} diff --git a/cairo/src/utils/maths.cairo b/cairo/src/utils/maths.cairo index 307f85d2..f9471431 100644 --- a/cairo/src/utils/maths.cairo +++ b/cairo/src/utils/maths.cairo @@ -1,3 +1,5 @@ +from starkware.cairo.common.math import assert_le_felt + // @dev Inlined version of unsigned_div_rem // Returns q and r such that: // 0 <= q < rc_bound, 0 <= r < div and value = q * div + r. @@ -40,3 +42,106 @@ func ceil32{range_check_ptr}(value: felt) -> felt { let (q, r) = unsigned_div_rem(value + 31, 32); return q * 32; } + +// Returns the sign of value: -1 if value < 0, 1 if value > 0. +// value is considered positive if it is in [0, STARK//2[ +// value is considered negative if it is in ]STARK//2, STARK[ +// If value == 0, returned value can be either 0 or 1 (undetermined). +func sign{range_check_ptr}(value) -> felt { + const STARK_DIV_2_PLUS_ONE = (-1) / 2 + 1; // == prime//2 + 1 + const STARK_DIV_2_MIN_ONE = (-1) / 2 - 1; // == prime//2 - 1 + tempvar is_positive: felt; + %{ + from starkware.cairo.common.math_utils import as_int + ids.is_positive = 1 if as_int(ids.value, PRIME) >= 0 else 0 + %} + if (is_positive != 0) { + assert_le_felt(value, STARK_DIV_2_MIN_ONE); + return 1; + } else { + assert_le_felt(STARK_DIV_2_PLUS_ONE, value); + return -1; + } +} + +// @notice Decompose a 128 bit scalar into base (-3) with coefficients in {-1, 0, 1}, +// also called "extended positive-negative sum" representation +// scalar = sum(digits[i] * (-3)^i for i in [0, 81]) +// digits[i] in {-1, 0, 1} for all i +// scalar = sum_p - sum_n +// sum_p = sum(digits[i] * (-3)^i for i in [0, 81] if digits[i]==1) +// sum_n = sum(digits[i] * (-3)^i for i in [0, 81] if digits[i]==-1) +// @returns (abs(sum_p), abs(sum_n), p_sign, n_sign) +func scalar_to_epns{range_check_ptr}(scalar: felt) -> ( + sum_p: felt, sum_n: felt, p_sign: felt, n_sign: felt +) { + %{ + from garaga.hints.neg_3 import neg_3_base_le, positive_negative_multiplicities + from starkware.cairo.common.math_utils import as_int + assert 0 <= ids.scalar < 2**128 + digits = neg_3_base_le(ids.scalar) + digits = digits + [0] * (82-len(digits)) + i=1 # Loop init + %} + + tempvar d0; + %{ ids.d0 = digits[0] %} + + if (d0 != 0) { + if (d0 == 1) { + tempvar sum_p = 1; + tempvar sum_n = 0; + } else { + tempvar sum_p = 0; + tempvar sum_n = 1; + } + } else { + tempvar sum_p = 0; + tempvar sum_n = 0; + } + + tempvar pow3 = -3; + + loop: + let sum_p = [ap - 3]; + let sum_n = [ap - 2]; + let pow3 = [ap - 1]; + %{ memory[ap] = 1 if i == 82 else 0 %} + jmp end if [ap] != 0, ap++; + + %{ i+=1 %} + + tempvar di; + %{ ids.di = digits[i-1] %} + if (di != 0) { + if (di == 1) { + tempvar sum_p = sum_p + pow3; + tempvar sum_n = sum_n; + tempvar pow3 = pow3 * (-3); + jmp loop; + } else { + tempvar sum_p = sum_p; + tempvar sum_n = sum_n + pow3; + tempvar pow3 = pow3 * (-3); + jmp loop; + } + } else { + tempvar sum_p = sum_p; + tempvar sum_n = sum_n; + tempvar pow3 = pow3 * (-3); + jmp loop; + } + + end: + let sum_p = [ap - 4]; + let sum_n = [ap - 3]; + let pow3 = [ap - 2]; + assert pow3 = (-3) ** 82; + + assert scalar = sum_p - sum_n; + + let p_sign = sign(sum_p); + let n_sign = sign(sum_n); + + return (p_sign * sum_p, n_sign * sum_n, p_sign, n_sign); +} diff --git a/cairo/src/utils/signature.cairo b/cairo/src/utils/signature.cairo index dbe1a3b6..91290d9e 100644 --- a/cairo/src/utils/signature.cairo +++ b/cairo/src/utils/signature.cairo @@ -13,12 +13,8 @@ from starkware.cairo.common.builtin_keccak.keccak import keccak_uint256s_bigend from starkware.cairo.common.uint256 import Uint256 from starkware.cairo.common.alloc import alloc -from src.utils.maths import unsigned_div_rem -from src.utils.circuit_utils import ( - N_LIMBS, - hash_full_transcript_and_get_Z_3_LIMBS, - scalar_to_epns, -) +from src.utils.maths import unsigned_div_rem, scalar_to_epns +from src.utils.circuit_utils import N_LIMBS, hash_full_transcript_and_get_Z_3_LIMBS from src.utils.ecdsa_circuit import get_full_ecip_2P_circuit from src.utils.uint256 import assert_uint256_le from src.utils.uint384 import ( diff --git a/cairo/tests/src/utils/test_maths.cairo b/cairo/tests/src/utils/test_maths.cairo new file mode 100644 index 00000000..278c7a7b --- /dev/null +++ b/cairo/tests/src/utils/test_maths.cairo @@ -0,0 +1,15 @@ +from src.utils.maths import scalar_to_epns, sign + +func test__sign{range_check_ptr}() -> felt { + tempvar value; + %{ ids.value = program_input["value"] %} + return sign(value); +} + +func test__scalar_to_epns{range_check_ptr}() -> ( + sum_p: felt, sum_n: felt, p_sign: felt, n_sign: felt +) { + tempvar scalar; + %{ ids.scalar = program_input["scalar"] %} + return scalar_to_epns(scalar); +} diff --git a/cairo/tests/src/utils/test_maths.py b/cairo/tests/src/utils/test_maths.py new file mode 100644 index 00000000..916132a9 --- /dev/null +++ b/cairo/tests/src/utils/test_maths.py @@ -0,0 +1,30 @@ +import pytest +from hypothesis import assume, given +from starkware.cairo.lang.cairo_constants import DEFAULT_PRIME + +from tests.utils.strategies import felt, uint128 + +pytestmark = pytest.mark.python_vm + + +class TestMaths: + + class TestSign: + @given(value=felt) + def test_sign(self, cairo_run, value): + assume(value != 0) + sign = cairo_run("test__sign", value=value) + assert ( + sign % DEFAULT_PRIME + == (2 * (0 <= value < DEFAULT_PRIME // 2) - 1) % DEFAULT_PRIME + ) + + class TestScalarToEpns: + @given(scalar=uint128) + def test_scalar_to_epns(self, cairo_run, scalar): + sum_p, sum_n, p_sign, n_sign = cairo_run( + "test__scalar_to_epns", scalar=scalar + ) + assert ( + sum_p * p_sign - sum_n * n_sign + ) % DEFAULT_PRIME == scalar % DEFAULT_PRIME From 70a9619be3fb3b541e18fbbe44281895341de85e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Walter?= Date: Thu, 23 Jan 2025 13:56:56 +0100 Subject: [PATCH 14/17] Final code reorg --- .vscode/settings.json | 2 + cairo/src/curve/secp256k1.cairo | 13 +++++ cairo/src/utils/circuit_utils.cairo | 15 ++---- cairo/src/utils/signature.cairo | 84 ++++++++++++++--------------- 4 files changed, 60 insertions(+), 54 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index d15e2d79..172c028d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -11,6 +11,8 @@ "dataframe", "defaultdict", "divmod", + "Dlog", + "ecip", "eips", "epns", "exitstatus", diff --git a/cairo/src/curve/secp256k1.cairo b/cairo/src/curve/secp256k1.cairo index bcc5fb95..c35bf156 100644 --- a/cairo/src/curve/secp256k1.cairo +++ b/cairo/src/curve/secp256k1.cairo @@ -377,3 +377,16 @@ func ec_add{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: Mod dw 40; dw 44; } + +@known_ap_change +func sign_to_uint384_mod_secp256k1(sign: felt) -> UInt384 { + if (sign == -1) { + let res = UInt384( + secp256k1.MIN_ONE_D0, secp256k1.MIN_ONE_D1, secp256k1.MIN_ONE_D2, secp256k1.MIN_ONE_D3 + ); + return res; + } else { + let res = UInt384(1, 0, 0, 0); + return res; + } +} diff --git a/cairo/src/utils/circuit_utils.cairo b/cairo/src/utils/circuit_utils.cairo index b85c36a4..1826aa59 100644 --- a/cairo/src/utils/circuit_utils.cairo +++ b/cairo/src/utils/circuit_utils.cairo @@ -1,10 +1,8 @@ -from starkware.cairo.common.cairo_builtins import PoseidonBuiltin +from starkware.cairo.common.cairo_builtins import PoseidonBuiltin, UInt384 -const N_LIMBS = 4; +const N_LIMBS = UInt384.SIZE; -func hash_full_transcript_and_get_Z_3_LIMBS{poseidon_ptr: PoseidonBuiltin*}( - limbs_ptr: felt*, n: felt -) -> (_s0: felt, _s1: felt, _s2: felt) { +func hash_full_transcript{poseidon_ptr: PoseidonBuiltin*}(limbs_ptr: felt*, n: felt) -> () { alloc_locals; local BASE = 2 ** 96; @@ -60,9 +58,6 @@ func hash_full_transcript_and_get_Z_3_LIMBS{poseidon_ptr: PoseidonBuiltin*}( assert cast(elements_end, felt) = cast(elements, felt); tempvar poseidon_ptr = poseidon_ptr + n * PoseidonBuiltin.SIZE; - let res_ptr = poseidon_ptr - PoseidonBuiltin.SIZE; - tempvar s0 = [res_ptr].output.s0; - tempvar s1 = [res_ptr].output.s1; - tempvar s2 = [res_ptr].output.s2; - return (_s0=s0, _s1=s1, _s2=s2); + + return (); } diff --git a/cairo/src/utils/signature.cairo b/cairo/src/utils/signature.cairo index 91290d9e..38467af9 100644 --- a/cairo/src/utils/signature.cairo +++ b/cairo/src/utils/signature.cairo @@ -14,7 +14,7 @@ from starkware.cairo.common.uint256 import Uint256 from starkware.cairo.common.alloc import alloc from src.utils.maths import unsigned_div_rem, scalar_to_epns -from src.utils.circuit_utils import N_LIMBS, hash_full_transcript_and_get_Z_3_LIMBS +from src.utils.circuit_utils import N_LIMBS, hash_full_transcript from src.utils.ecdsa_circuit import get_full_ecip_2P_circuit from src.utils.uint256 import assert_uint256_le from src.utils.uint384 import ( @@ -32,22 +32,10 @@ from src.curve.secp256k1 import ( try_get_point_from_x, get_random_point, ec_add, + sign_to_uint384_mod_secp256k1, ) from src.curve.g1_point import G1Point -@known_ap_change -func sign_to_uint384_mod_secp256k1(sign: felt) -> UInt384 { - if (sign == -1) { - let res = UInt384( - secp256k1.MIN_ONE_D0, secp256k1.MIN_ONE_D1, secp256k1.MIN_ONE_D2, secp256k1.MIN_ONE_D3 - ); - return res; - } else { - let res = UInt384(1, 0, 0, 0); - return res; - } -} - namespace Signature { // Assert 1 <= x < N. Assumes valid Uint256. func validate_signature_entry{range_check_ptr}(x: Uint256) { @@ -151,20 +139,18 @@ namespace Signature { assert_uint256_le(u2, N_min_one); let (ep1_low, en1_low, sp1_low, sn1_low) = scalar_to_epns(u1.low); - let (ep1_high, en1_high, sp1_high, sn1_high) = scalar_to_epns(u1.high); - let ep1_low_384 = felt_to_uint384(ep1_low); let en1_low_384 = felt_to_uint384(en1_low); let sp1_low_384 = sign_to_uint384_mod_secp256k1(sp1_low); let sn1_low_384 = sign_to_uint384_mod_secp256k1(sn1_low); + let (ep1_high, en1_high, sp1_high, sn1_high) = scalar_to_epns(u1.high); let ep1_high_384 = felt_to_uint384(ep1_high); let en1_high_384 = felt_to_uint384(en1_high); let sp1_high_384 = sign_to_uint384_mod_secp256k1(sp1_high); let sn1_high_384 = sign_to_uint384_mod_secp256k1(sn1_high); let (ep2_low, en2_low, sp2_low, sn2_low) = scalar_to_epns(u2.low); - let ep2_low_384 = felt_to_uint384(ep2_low); let en2_low_384 = felt_to_uint384(en2_low); let sp2_low_384 = sign_to_uint384_mod_secp256k1(sp2_low); @@ -175,7 +161,6 @@ namespace Signature { let en2_high_384 = felt_to_uint384(en2_high); let sp2_high_384 = sign_to_uint384_mod_secp256k1(sp2_high); let sn2_high_384 = sign_to_uint384_mod_secp256k1(sn2_high); - let generator_point = get_generator_point(); %{ from garaga.hints.io import pack_bigint_ptr, pack_felt_ptr, fill_sum_dlog_div, fill_g1_point, bigint_split @@ -225,20 +210,38 @@ namespace Signature { fill_elmt_at_index(Q_high_shifted[1], ids.range_check96_ptr, memory, 55, offset) %} + // Interaction with Poseidon, protocol is roughly a sequence of hashing: + // - initial constant 'MSM_G1' + // - curve ID + // - curve generator G + // - user input R point + // + // ==> interaction + // + // - u1 + // - u2 + // > get random linear combination coefficients + // + // ==> interaction + // > get seed for random point + assert poseidon_ptr[0].input = PoseidonBuiltinState(s0='MSM_G1', s1=0, s2=1); assert poseidon_ptr[1].input = PoseidonBuiltinState( s0=secp256k1.CURVE_ID + poseidon_ptr[0].output.s0, s1=2 + poseidon_ptr[0].output.s1, s2=poseidon_ptr[0].output.s2, ); - let poseidon_ptr = poseidon_ptr + 2 * PoseidonBuiltin.SIZE; - hash_full_transcript_and_get_Z_3_LIMBS(cast(generator_point, felt*), 2); - hash_full_transcript_and_get_Z_3_LIMBS(cast(&r_point, felt*), 2); + + let generator_point = get_generator_point(); + hash_full_transcript(cast(generator_point, felt*), 2); + hash_full_transcript(cast(&r_point, felt*), 2); // Q_low, Q_high, Q_high_shifted (filled by prover) (50 - 55). - let (_s0, _s1, _s2) = hash_full_transcript_and_get_Z_3_LIMBS( - cast(range_check96_ptr + 4 + 50 * N_LIMBS, felt*), 3 * 2 - ); + hash_full_transcript(range_check96_ptr + 4 + 50 * N_LIMBS, 3 * 2); + let _s0 = [cast(poseidon_ptr, felt*) - 3]; + let _s1 = [cast(poseidon_ptr, felt*) - 2]; + let _s2 = [cast(poseidon_ptr, felt*) - 1]; + // U1, U2 assert poseidon_ptr[0].input = PoseidonBuiltinState( s0=_s0 + u1.low, s1=_s1 + u1.high, s2=_s2 @@ -248,43 +251,42 @@ namespace Signature { s1=poseidon_ptr[0].output.s1 + u2.high, s2=poseidon_ptr[0].output.s2, ); - - tempvar rlc_coeff = poseidon_ptr[1].output.s1 + 0; + tempvar rlc_coeff = poseidon_ptr[1].output.s1; let poseidon_ptr = poseidon_ptr + 2 * PoseidonBuiltin.SIZE; let rlc_coeff_u384 = felt_to_uint384(rlc_coeff); - // Hash sumdlogdiv 2 points : (4-29) - let (seed, _, _) = hash_full_transcript_and_get_Z_3_LIMBS( - cast(range_check96_ptr + 4 * N_LIMBS, felt*), 26 - ); - + // Hash SumDlogDiv 2 points : (4-29) + hash_full_transcript(range_check96_ptr + 4 * N_LIMBS, 26); tempvar range_check96_ptr_init = range_check96_ptr; tempvar range_check96_ptr_after_circuit = range_check96_ptr + 224 + (4 + 117 + 108 - 1) * N_LIMBS; - let random_point = get_random_point{range_check96_ptr=range_check96_ptr_after_circuit}( - seed=seed + seed=[cast(poseidon_ptr, felt*) - 3] ); tempvar range_check96_ptr_final = range_check96_ptr_after_circuit; let range_check96_ptr = range_check96_ptr_init; + // Circuits inputs + let ecip_input: UInt384* = cast(range_check96_ptr, UInt384*); // Constants (0-3) - assert ecip_input[0] = UInt384(3, 0, 0, 0); + assert ecip_input[0] = UInt384(secp256k1.G0, secp256k1.G1, secp256k1.G2, secp256k1.G3); assert ecip_input[1] = UInt384(0, 0, 0, 0); assert ecip_input[2] = UInt384(12528508628158887531275213211, 66632300, 0, 0); assert ecip_input[3] = UInt384(12528508628158887531275213211, 4361599596, 0, 0); - // RLCSumDlogDiv for 2 points : n_coeffs = 18 + 4 * 2 = 26 (filled by prover) (4-29) + // Random Linear Combination Sum of Discrete Logarithm Division + // RLCSumDlogDiv for 2 points: n_coeffs = 18 + 4 * 2 = 26 (4-29) - // Generator point + // Generator point, same as in get_generator_point() assert ecip_input[30] = UInt384( 0x2dce28d959f2815b16f81798, 0x55a06295ce870b07029bfcdb, 0x79be667ef9dcbbac, 0x0 - ); // x_gen + ); assert ecip_input[31] = UInt384( 0xa68554199c47d08ffb10d4b8, 0x5da4fbfc0e1108a8fd17b448, 0x483ada7726a3c465, 0x0 - ); // y_gen + ); + // R point assert ecip_input[32] = r_point.x; assert ecip_input[33] = r_point.y; @@ -310,10 +312,6 @@ namespace Signature { assert ecip_input[49] = sn2_high_384; // Q_low / Q_high / Q_high_shifted (filled by prover) (50 - 55). - // ... - // Random point A0 - // let a0:G1Point = G1Point {x: u384{limb0:0x24bbb2e640ceea04c582be56, limb1:0x3194a04768eadeb55fc1ba0a, limb2:0x7b7954ea50caf5a, limb3:0x0}, y: u384{limb0:0x48afd5cdf3ea97eb92138b3c, limb1:0x796f538416c264e0d776e0d, limb2:0x6ef4f09165269157, limb3:0x0}}; - // G1Point{x: u384{limb0:0x7fae4cd63658d585d7d8a264, limb1:0x721fe8c75e82c0be38844e0a, limb2:0x5891e91528037ca, limb3:0x0}, y: u384{limb0:0xa06fe9692227dfdc6dd6b4b5, limb1:0xc4330da0e6a11158bce59b92, limb2:0x524aade87df0f5d7, limb3:0x0}} assert ecip_input[56] = random_point.x; assert ecip_input[57] = random_point.y; @@ -324,9 +322,7 @@ namespace Signature { assert ecip_input[59] = rlc_coeff_u384; let (add_offsets_ptr, mul_offsets_ptr) = get_full_ecip_2P_circuit(); - let p = UInt384(secp256k1.P0, secp256k1.P1, secp256k1.P2, secp256k1.P3); - assert add_mod_ptr[0] = ModBuiltin( p=p, values_ptr=cast(range_check96_ptr, UInt384*), offsets_ptr=add_offsets_ptr, n=117 ); From 516fda92f04f344a2d6774bba721aaf8ece73cda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Walter?= Date: Thu, 23 Jan 2025 14:05:41 +0100 Subject: [PATCH 15/17] Remove max example --- cairo/tests/src/utils/test_signature.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cairo/tests/src/utils/test_signature.py b/cairo/tests/src/utils/test_signature.py index d2e8088c..bf1379b6 100644 --- a/cairo/tests/src/utils/test_signature.py +++ b/cairo/tests/src/utils/test_signature.py @@ -2,7 +2,7 @@ from eth_keys.datatypes import PrivateKey from ethereum_types.bytes import Bytes32 from ethereum_types.numeric import U256 -from hypothesis import given, settings +from hypothesis import given from hypothesis import strategies as st from starkware.cairo.lang.cairo_constants import DEFAULT_PRIME @@ -30,7 +30,6 @@ def test__public_key_point_to_eth_address( class TestVerifyEthSignature: @pytest.mark.slow - @settings(max_examples=1) # for max_examples=2, it takes 1934.87s in local @given(private_key=..., message=...) def test__verify_eth_signature_uint256( self, cairo_run, private_key: PrivateKey, message: Bytes32 @@ -126,7 +125,6 @@ def test_should_raise_with_out_of_bounds_s( class TestTryRecoverEthAddress: @pytest.mark.slow - @settings(max_examples=1) # for max_examples=2, it takes 1934.87s in local @given(private_key=..., message=...) def test__try_recover_eth_address( self, cairo_run, private_key: PrivateKey, message: Bytes32 From d6095458ff97c01a38d0c2d524b32a23c9bfd35c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Walter?= Date: Thu, 23 Jan 2025 14:18:07 +0100 Subject: [PATCH 16/17] Redo max_examples=1 for test_os --- cairo/src/utils/uint256.cairo | 1 - cairo/tests/programs/test_os.py | 2 +- cairo/tests/src/utils/test_signature.cairo | 8 +------- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/cairo/src/utils/uint256.cairo b/cairo/src/utils/uint256.cairo index ec172ee1..53206fc6 100644 --- a/cairo/src/utils/uint256.cairo +++ b/cairo/src/utils/uint256.cairo @@ -8,7 +8,6 @@ from starkware.cairo.common.uint256 import ( uint256_lt, uint256_not, ) -from starkware.cairo.common.cairo_builtins import UInt384 from starkware.cairo.common.bool import FALSE from starkware.cairo.common.math_cmp import is_nn diff --git a/cairo/tests/programs/test_os.py b/cairo/tests/programs/test_os.py index f32bd8f0..17bcdee5 100644 --- a/cairo/tests/programs/test_os.py +++ b/cairo/tests/programs/test_os.py @@ -278,7 +278,7 @@ def test_create_tx_returndata(self, cairo_run): ) @pytest.mark.slow - @settings(deadline=None) + @settings(max_examples=1) @given(nonce=integers(min_value=2**64, max_value=2**248 - 1)) def test_should_raise_when_nonce_is_greater_u64(self, cairo_run, nonce): initial_state = { diff --git a/cairo/tests/src/utils/test_signature.cairo b/cairo/tests/src/utils/test_signature.cairo index 67aceea1..ed2597e0 100644 --- a/cairo/tests/src/utils/test_signature.cairo +++ b/cairo/tests/src/utils/test_signature.cairo @@ -13,13 +13,7 @@ from src.utils.uint256 import uint256_eq from src.utils.uint384 import uint256_to_uint384 func test__public_key_point_to_eth_address{ - range_check_ptr, - bitwise_ptr: BitwiseBuiltin*, - keccak_ptr: KeccakBuiltin*, - range_check96_ptr: felt*, - add_mod_ptr: ModBuiltin*, - mul_mod_ptr: ModBuiltin*, - poseidon_ptr: PoseidonBuiltin*, + range_check_ptr, bitwise_ptr: BitwiseBuiltin*, keccak_ptr: KeccakBuiltin* }(x: U256, y: U256) -> felt { let eth_address = Signature.public_key_point_to_eth_address(x=[x.value], y=[y.value]); From bbafe13adbe0172032dd3bfe997467fed572a418 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Walter?= Date: Thu, 23 Jan 2025 14:26:17 +0100 Subject: [PATCH 17/17] Add implicit to test --- cairo/tests/src/precompiles/test_ec_recover.cairo | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/cairo/tests/src/precompiles/test_ec_recover.cairo b/cairo/tests/src/precompiles/test_ec_recover.cairo index 48d585d2..aeb369e3 100644 --- a/cairo/tests/src/precompiles/test_ec_recover.cairo +++ b/cairo/tests/src/precompiles/test_ec_recover.cairo @@ -1,5 +1,11 @@ from starkware.cairo.common.alloc import alloc -from starkware.cairo.common.cairo_builtins import HashBuiltin, BitwiseBuiltin, KeccakBuiltin +from starkware.cairo.common.cairo_builtins import ( + HashBuiltin, + BitwiseBuiltin, + KeccakBuiltin, + ModBuiltin, + PoseidonBuiltin, +) from starkware.cairo.common.math import unsigned_div_rem, assert_not_zero from starkware.cairo.common.memset import memset from starkware.cairo.common.memcpy import memcpy @@ -10,8 +16,12 @@ from src.utils.utils import Helpers func test__ec_recover{ pedersen_ptr: HashBuiltin*, range_check_ptr, + range_check96_ptr: felt*, + add_mod_ptr: ModBuiltin*, + mul_mod_ptr: ModBuiltin*, bitwise_ptr: BitwiseBuiltin*, keccak_ptr: KeccakBuiltin*, + poseidon_ptr: PoseidonBuiltin*, }() -> (output: felt*) { alloc_locals; let (local input) = alloc();