diff --git a/cairo_programs/ec_double_slope.cairo b/cairo_programs/ec_double_slope.cairo new file mode 100644 index 00000000..10177482 --- /dev/null +++ b/cairo_programs/ec_double_slope.cairo @@ -0,0 +1,212 @@ +%builtins range_check + +// Source: https://github.com/rdubois-crypto/efficient-secp256r1/blob/4b74807c5e91f1ed4cb00a1c973be05c63986e61/src/secp256r1/ec.cairo +from starkware.cairo.common.cairo_secp.bigint import BigInt3, UnreducedBigInt3, nondet_bigint3 +from starkware.cairo.common.cairo_secp.ec import EcPoint + +// src.secp256r1.constants +// SECP_REM is defined by the equation: +// secp256r1_prime = 2 ** 256 - SECP_REM. +const SECP_REM = 2 ** 224 - 2 ** 192 - 2 ** 96 + 1; + +const BASE = 2 ** 86; + +// A = 0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc +const A0 = 0x3ffffffffffffffffffffc; +const A1 = 0x3ff; +const A2 = 0xffffffff0000000100000; + +// Constants for unreduced_mul/sqr +const s2 = (-(2 ** 76)) - 2 ** 12; +const s1 = (-(2 ** 66)) + 4; +const s0 = 2 ** 56; + +const r2 = 2 ** 54 - 2 ** 22; +const r1 = -(2 ** 12); +const r0 = 4; + +// src.secp256r1.field +// Adapt from starkware.cairo.common.math's assert_250_bit +func assert_165_bit{range_check_ptr}(value) { + const UPPER_BOUND = 2 ** 165; + const SHIFT = 2 ** 128; + const HIGH_BOUND = UPPER_BOUND / SHIFT; + + let low = [range_check_ptr]; + let high = [range_check_ptr + 1]; + + %{ + from starkware.cairo.common.math_utils import as_int + + # Correctness check. + value = as_int(ids.value, PRIME) % PRIME + assert value < ids.UPPER_BOUND, f'{value} is outside of the range [0, 2**250).' + + # Calculation for the assertion. + ids.high, ids.low = divmod(ids.value, ids.SHIFT) + %} + + assert [range_check_ptr + 2] = HIGH_BOUND - 1 - high; + + assert value = high * SHIFT + low; + + let range_check_ptr = range_check_ptr + 3; + return (); +} + +// src.secp256r1.field +// Computes the multiplication of two big integers, given in BigInt3 representation, modulo the +// secp256r1 prime. +// +// Arguments: +// x, y - the two BigInt3 to operate on. +// +// Returns: +// x * y in an UnreducedBigInt3 representation (the returned limbs may be above 3 * BASE). +// +// This means that if unreduced_mul is called on the result of nondet_bigint3, or the difference +// between two such results, we have: +// Soundness guarantee: the limbs are in the range (). +// Completeness guarantee: the limbs are in the range (). +func unreduced_mul(a: BigInt3, b: BigInt3) -> (res_low: UnreducedBigInt3) { + tempvar twice_d2 = a.d2 * b.d2; + tempvar d1d2 = a.d2 * b.d1 + a.d1 * b.d2; + return ( + UnreducedBigInt3( + d0=a.d0 * b.d0 + s0 * twice_d2 + r0 * d1d2, + d1=a.d1 * b.d0 + a.d0 * b.d1 + s1 * twice_d2 + r1 * d1d2, + d2=a.d2 * b.d0 + a.d1 * b.d1 + a.d0 * b.d2 + s2 * twice_d2 + r2 * d1d2, + ), + ); +} + +// src.secp256r1.field +// Computes the square of a big integer, given in BigInt3 representation, modulo the +// secp256r1 prime. +// +// Has the same guarantees as in unreduced_mul(a, a). +func unreduced_sqr(a: BigInt3) -> (res_low: UnreducedBigInt3) { + tempvar twice_d2 = a.d2 * a.d2; + tempvar twice_d1d2 = a.d2 * a.d1 + a.d1 * a.d2; + tempvar d1d0 = a.d1 * a.d0; + return ( + UnreducedBigInt3( + d0=a.d0 * a.d0 + s0 * twice_d2 + r0 * twice_d1d2, + d1=d1d0 + d1d0 + s1 * twice_d2 + r1 * twice_d1d2, + d2=a.d2 * a.d0 + a.d1 * a.d1 + a.d0 * a.d2 + s2 * twice_d2 + r2 * twice_d1d2, + ), + ); +} + +// src.secp256r1.field +// Verifies that the given unreduced value is equal to zero modulo the secp256r1 prime. +// +// Completeness assumption: val's limbs are in the range (-2**210.99, 2**210.99). +// Soundness assumption: val's limbs are in the range (-2**250, 2**250). +func verify_zero{range_check_ptr}(val: UnreducedBigInt3) { + alloc_locals; + local q; + // local q_sign; + let q_sign = 1; + // original: + // %{ from starkware.cairo.common.cairo_secp.secp_utils import SECP256R1_P as SECP_P %} + // %{ + // from starkware.cairo.common.cairo_secp.secp_utils import pack + + // q, r = divmod(pack(ids.val, PRIME), SECP_P) + // assert r == 0, f"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}." + // if q >= 0: + // ids.q = q % PRIME + // ids.q_sign = 1 + // else: + // ids.q = (0-q) % PRIME + // ids.q_sign = -1 % PRIME + // %} + %{ from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P as SECP_P %} + %{ + from starkware.cairo.common.cairo_secp.secp_utils import pack + + q, r = divmod(pack(ids.val, PRIME), SECP_P) + assert r == 0, f"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}." + ids.q = q % PRIME + %} + // assert_250_bit(q); // 256K steps + // assert_le_felt(q, 2**165); // 275K steps + assert_165_bit(q); + assert q_sign * (val.d2 + val.d1 / BASE + val.d0 / BASE ** 2) = q * ( + (BASE / 4) - SECP_REM / BASE ** 2 + ); + // Multiply by BASE**2 both sides: + // (q_sign) * val = q * (BASE**3 / 4 - SECP_REM) + // = q * (2**256 - SECP_REM) = q * secp256r1_prime = 0 mod secp256r1_prime + return (); +} + +// Computes the slope of the elliptic curve at a given point. +// The slope is used to compute point + point. +// +// Arguments: +// point - the point to operate on. +// +// Returns: +// slope - the slope of the curve at point, in BigInt3 representation. +// +// Assumption: point != 0. +func compute_doubling_slope{range_check_ptr}(point: EcPoint) -> (slope: BigInt3) { + // Note that y cannot be zero: assume that it is, then point = -point, so 2 * point = 0, which + // contradicts the fact that the size of the curve is odd. + // originals: + // %{ from starkware.cairo.common.cairo_secp.secp_utils import SECP256R1_P as SECP_P %} + // %{ from starkware.cairo.common.cairo_secp.secp_utils import SECP256R1_ALPHA as ALPHA %} + %{ from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P as SECP_P %} + %{ from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_ALPHA as ALPHA %} + %{ + from starkware.cairo.common.cairo_secp.secp_utils import pack + from starkware.python.math_utils import ec_double_slope + + # Compute the slope. + x = pack(ids.point.x, PRIME) + y = pack(ids.point.y, PRIME) + value = slope = ec_double_slope(point=(x, y), alpha=ALPHA, p=SECP_P) + %} + let (slope: BigInt3) = nondet_bigint3(); + + let (x_sqr: UnreducedBigInt3) = unreduced_sqr(point.x); + let (slope_y: UnreducedBigInt3) = unreduced_mul(slope, point.y); + verify_zero( + UnreducedBigInt3( + d0=3 * x_sqr.d0 + A0 - 2 * slope_y.d0, + d1=3 * x_sqr.d1 + A1 - 2 * slope_y.d1, + d2=3 * x_sqr.d2 + A2 - 2 * slope_y.d2, + ), + ); + + return (slope=slope); +} + +func test_doubling_slope{range_check_ptr}() { + let point = EcPoint(BigInt3(614323, 5456867, 101208), BigInt3(773712524, 77371252, 5298795)); + + let (slope) = compute_doubling_slope(point); + + assert slope = BigInt3( + 64081873649130491683833713, 34843994309543177837008178, 16548672716077616016846383 + ); + + let point = EcPoint( + BigInt3(51215, 36848548548458, 634734734), BigInt3(26362, 263724839599, 901297012) + ); + + let (slope) = compute_doubling_slope(point); + + assert slope = BigInt3( + 71848883893335852660776740, 75644451964360469099209675, 547087410329256463669633 + ); + + return (); +} + +func main{range_check_ptr}() { + test_doubling_slope(); + return (); +} diff --git a/pkg/hints/bigint_hint.go b/pkg/hints/bigint_hint.go new file mode 100644 index 00000000..a13fc098 --- /dev/null +++ b/pkg/hints/bigint_hint.go @@ -0,0 +1,56 @@ +package hints + +import ( + "errors" + "math/big" + + . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" + "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" + . "github.com/lambdaclass/cairo-vm.go/pkg/types" + . "github.com/lambdaclass/cairo-vm.go/pkg/vm" + "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" +) + +/* +Implements hint: +%{ + from starkware.cairo.common.cairo_secp.secp_utils import split + + segments.write_arg(ids.res.address_, split(value)) +%} +*/ + +func NondetBigInt3(virtual_machine VirtualMachine, execScopes ExecutionScopes, idsData IdsManager) error { + resRelloc, err := idsData.GetAddr("res", &virtual_machine) + if err != nil { + return err + } + + valueUncast, err := execScopes.Get("value") + if err != nil { + return err + } + value, ok := valueUncast.(big.Int) + if !ok { + return errors.New("Could not cast value into big int") + } + + bigint3Split, err := Bigint3Split(value) + if err != nil { + return err + } + + arg := make([]memory.MaybeRelocatable, 0) + + for i := 0; i < 3; i++ { + m := memory.NewMaybeRelocatableFelt(lambdaworks.FeltFromBigInt(&bigint3Split[i])) + arg = append(arg, *m) + } + + _, loadErr := virtual_machine.Segments.LoadData(resRelloc, &arg) + if loadErr != nil { + return loadErr + } + + return nil +} diff --git a/pkg/hints/bigint_hint_test.go b/pkg/hints/bigint_hint_test.go new file mode 100644 index 00000000..27bc55b4 --- /dev/null +++ b/pkg/hints/bigint_hint_test.go @@ -0,0 +1,75 @@ +package hints_test + +import ( + "math/big" + "testing" + + . "github.com/lambdaclass/cairo-vm.go/pkg/hints" + . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_codes" + . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" + "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" + . "github.com/lambdaclass/cairo-vm.go/pkg/types" + . "github.com/lambdaclass/cairo-vm.go/pkg/vm" + . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" +) + +func TestNonDetBigInt3Ok(t *testing.T) { + vm := NewVirtualMachine() + + vm.Segments.AddSegment() + vm.Segments.AddSegment() + vm.Segments.AddSegment() + + vm.RunContext.Pc = NewRelocatable(0, 0) + vm.RunContext.Ap = NewRelocatable(1, 6) + vm.RunContext.Fp = NewRelocatable(1, 6) + + value, _ := new(big.Int).SetString("7737125245533626718119526477371252455336267181195264773712524553362", 10) + execScopes := NewExecutionScopes() + + execScopes.AssignOrUpdateVariable("value", *value) + + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "res": {nil}, + }, + vm, + ) + + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: NONDET_BIGINT3_V1, + }) + err := hintProcessor.ExecuteHint(vm, &hintData, nil, execScopes) + if err != nil { + t.Errorf("Non Det Big Int 3 hint test failed with error: %s", err) + } else { + valueInStruct0, err := idsManager.GetStructFieldFelt("res", 0, vm) + expected0 := lambdaworks.FeltFromDecString("773712524553362") + if err != nil { + t.Errorf("error fetching from ids manager : %s", err) + } + if valueInStruct0 != expected0 { + t.Errorf(" Incorrect field value %s, expected %s", valueInStruct0.ToBigInt().Text(10), expected0.ToBigInt().Text(10)) + } + + valueInStruct1, err := idsManager.GetStructFieldFelt("res", 1, vm) + expected1 := lambdaworks.FeltFromDecString("57408430697461422066401280") + if err != nil { + t.Errorf("error fetching from ids manager : %s", err) + } + if valueInStruct1 != expected1 { + t.Errorf(" Incorrect field value %s, expected %s", valueInStruct1.ToBigInt().Text(10), expected1.ToBigInt().Text(10)) + } + + valueInStruct2, err := idsManager.GetStructFieldFelt("res", 2, vm) + expected2 := lambdaworks.FeltFromDecString("1292469707114105") + if err != nil { + t.Errorf("error fetching from ids manager : %s", err) + } + if valueInStruct2 != expected2 { + t.Errorf(" Incorrect field value %s, expected %s", valueInStruct2.ToBigInt().Text(10), expected2.ToBigInt().Text(10)) + } + } +} diff --git a/pkg/hints/ec_hint.go b/pkg/hints/ec_hint.go index 698011d6..4b0a8ce2 100644 --- a/pkg/hints/ec_hint.go +++ b/pkg/hints/ec_hint.go @@ -1,6 +1,7 @@ package hints import ( + "errors" "math/big" "github.com/lambdaclass/cairo-vm.go/pkg/builtins" @@ -39,6 +40,7 @@ func EcPointFromVarName(name string, vm *VirtualMachine, idsData IdsManager) (Ec /* Implements main logic for `EC_NEGATE` and `EC_NEGATE_EMBEDDED_SECP` hints */ + func ecNegate(vm *vm.VirtualMachine, execScopes types.ExecutionScopes, ids hint_utils.IdsManager, secpP big.Int) error { point, err := ids.GetRelocatable("point", vm) if err != nil { @@ -182,9 +184,85 @@ func computeSlope(vm *VirtualMachine, execScopes ExecutionScopes, idsData IdsMan return nil } +/* +Implements hint: +%{ from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_ALPHA as ALPHA %} +*/ + +func importSecp256r1Alpha(execScopes ExecutionScopes) error { + execScopes.AssignOrUpdateVariable("ALPHA", SECP256R1_ALPHA()) + return nil +} + +/* +Implements hint: +%{ from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_N as N %} +*/ +func importSECP256R1N(execScopes ExecutionScopes) error { + execScopes.AssignOrUpdateVariable("N", SECP256R1_N()) + return nil +} + +/* +Implements hint: +%{ +from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P as SECP_P +%} +*/ + +func importSECP256R1P(execScopes ExecutionScopes) error { + execScopes.AssignOrUpdateVariable("SECP_P", SECP256R1_P()) + return nil +} + /* Implements hint: + %{ + from starkware.cairo.common.cairo_secp.secp_utils import pack + from starkware.python.math_utils import ec_double_slope + # Compute the slope. + x = pack(ids.point.x, PRIME) + y = pack(ids.point.y, PRIME) + value = slope = ec_double_slope(point=(x, y), alpha=ALPHA, p=SECP_P) + +%} +*/ +func computeDoublingSlopeExternalConsts(vm VirtualMachine, execScopes ExecutionScopes, ids_data IdsManager) error { + // ids.point + point, err := EcPointFromVarName("point", &vm, ids_data) + if err != nil { + return err + } + + secpPuncast, err := execScopes.Get("SECP_P") + if err != nil { + return err + } + secpP, ok := secpPuncast.(big.Int) + if !ok { + return errors.New("Could not cast secp into big int") + } + + alphaUncast, err := execScopes.Get("ALPHA") + if err != nil { + return nil + } + + alpha, ok := alphaUncast.(big.Int) + if !ok { + return errors.New("Could not cast alpha into big int") + } + + doublePoint_b := builtins.DoublePointB{X: point.X.Pack86(), Y: point.Y.Pack86()} + + value, err := builtins.EcDoubleSlope(doublePoint_b, alpha, secpP) + execScopes.AssignOrUpdateVariable("value", value) + execScopes.AssignOrUpdateVariable("slope", value) + return nil +} + +/* %{ from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack @@ -194,21 +272,17 @@ Implements hint: y0 = pack(ids.point0.y, PRIME) value = new_x = (pow(slope, 2, SECP_P) - x0 - x1) % SECP_P" - %} + +%} */ func fastEcAddAssignNewX(ids IdsManager, vm *VirtualMachine, execScopes *ExecutionScopes, point0Alias string, point1Alias string, secpP big.Int) error { execScopes.AssignOrUpdateVariable("SECP_P", secpP) point0, err := EcPointFromVarName(point0Alias, vm, ids) - if err != nil { - return err - } - point1, err := EcPointFromVarName(point1Alias, vm, ids) if err != nil { return err } - slopeUnpacked, err := BigInt3FromVarName("slope", ids, vm) if err != nil { return err diff --git a/pkg/hints/field_utils.go b/pkg/hints/field_utils.go new file mode 100644 index 00000000..bb81d791 --- /dev/null +++ b/pkg/hints/field_utils.go @@ -0,0 +1,55 @@ +package hints + +import ( + "errors" + "math/big" + + . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" + "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" + "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" + + . "github.com/lambdaclass/cairo-vm.go/pkg/types" + . "github.com/lambdaclass/cairo-vm.go/pkg/vm" +) + +/* +Implements hint: +%{ + from starkware.cairo.common.cairo_secp.secp_utils import pack + + q, r = divmod(pack(ids.val, PRIME), SECP_P) + assert r == 0, f"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}." + ids.q = q % PRIME +%} +*/ + +func verifyZeroWithExternalConst(vm VirtualMachine, execScopes ExecutionScopes, idsData IdsManager) error { + secpPuncast, err := execScopes.Get("SECP_P") + if err != nil { + return err + } + secpP, ok := secpPuncast.(big.Int) + if !ok { + return errors.New("Could not cast secpP into big int") + } + + addr, err := idsData.GetAddr("val", &vm) + if err != nil { + return err + } + + val, err := BigInt3FromBaseAddr(addr, "val", &vm) + if err != nil { + return err + } + + v := val.Pack86() + q, r := v.DivMod(&v, &secpP, new(big.Int)) + + if r.Cmp(big.NewInt(0)) != 0 { + return errors.New("verify remainder is not zero: Invalid input") + } + + quotient := memory.NewMaybeRelocatableFelt(lambdaworks.FeltFromBigInt(q)) + return idsData.Insert("q", quotient, &vm) +} diff --git a/pkg/hints/field_utils_test.go b/pkg/hints/field_utils_test.go new file mode 100644 index 00000000..534f8eff --- /dev/null +++ b/pkg/hints/field_utils_test.go @@ -0,0 +1,56 @@ +package hints_test + +import ( + "math/big" + "testing" + + . "github.com/lambdaclass/cairo-vm.go/pkg/hints" + . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_codes" + . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" + "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" + . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" + . "github.com/lambdaclass/cairo-vm.go/pkg/types" + . "github.com/lambdaclass/cairo-vm.go/pkg/vm" + . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" +) + +func TestVerifyZeroWithExternalConst(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + vm.Segments.AddSegment() + + vm.RunContext.Pc = NewRelocatable(0, 0) + vm.RunContext.Ap = NewRelocatable(1, 9) + vm.RunContext.Fp = NewRelocatable(1, 9) + + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "val": {NewMaybeRelocatableFelt(lambdaworks.FeltFromUint64(55)), NewMaybeRelocatableFelt(lambdaworks.FeltFromUint64(0)), NewMaybeRelocatableFelt(lambdaworks.FeltFromUint64(0))}, + "q": {nil}, + }, + vm, + ) + + newScepP := big.NewInt(55) + execScopes := NewExecutionScopes() + + execScopes.AssignOrUpdateVariable("SECP_P", *newScepP) + + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: VERIFY_ZERO_EXTERNAL_SECP, + }) + err := hintProcessor.ExecuteHint(vm, &hintData, nil, execScopes) + if err != nil { + t.Errorf("verifyZeroWithExternalConst hint test failed with error: %s", err) + } else { + valueInMemory, err := idsManager.GetFelt("q", vm) + if err != nil { + t.Errorf("could not fetch value with error: %s", err) + } + if valueInMemory != FeltFromUint64(1) { + t.Errorf("value in memory is not the expected") + } + } +} diff --git a/pkg/hints/hint_codes/ec_op_hints.go b/pkg/hints/hint_codes/ec_op_hints.go index 005b055d..fabd0531 100644 --- a/pkg/hints/hint_codes/ec_op_hints.go +++ b/pkg/hints/hint_codes/ec_op_hints.go @@ -4,6 +4,8 @@ const EC_NEGATE = "from starkware.cairo.common.cairo_secp.secp_utils import SECP const EC_NEGATE_EMBEDDED_SECP = "from starkware.cairo.common.cairo_secp.secp_utils import pack\nSECP_P = 2**255-19\n\ny = pack(ids.point.y, PRIME) % SECP_P\n# The modulo operation in python always returns a nonnegative number.\nvalue = (-y) % SECP_P" const EC_DOUBLE_SLOPE_V1 = "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack\nfrom starkware.python.math_utils import ec_double_slope\n\n# Compute the slope.\nx = pack(ids.point.x, PRIME)\ny = pack(ids.point.y, PRIME)\nvalue = slope = ec_double_slope(point=(x, y), alpha=0, p=SECP_P)" const COMPUTE_SLOPE_V1 = "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack\nfrom starkware.python.math_utils import line_slope\n\n# Compute the slope.\nx0 = pack(ids.point0.x, PRIME)\ny0 = pack(ids.point0.y, PRIME)\nx1 = pack(ids.point1.x, PRIME)\ny1 = pack(ids.point1.y, PRIME)\nvalue = slope = line_slope(point1=(x0, y0), point2=(x1, y1), p=SECP_P)" +const EC_DOUBLE_SLOPE_EXTERNAL_CONSTS = "from starkware.cairo.common.cairo_secp.secp_utils import pack\nfrom starkware.python.math_utils import ec_double_slope\n\n# Compute the slope.\nx = pack(ids.point.x, PRIME)\ny = pack(ids.point.y, PRIME)\nvalue = slope = ec_double_slope(point=(x, y), alpha=ALPHA, p=SECP_P)" +const NONDET_BIGINT3_V1 = "from starkware.cairo.common.cairo_secp.secp_utils import split\n\nsegments.write_arg(ids.res.address_, split(value))" const FAST_EC_ADD_ASSIGN_NEW_X = `"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack slope = pack(ids.slope, PRIME) diff --git a/pkg/hints/hint_codes/secp_p_hint.go b/pkg/hints/hint_codes/secp_p_hint.go new file mode 100644 index 00000000..2d6dac14 --- /dev/null +++ b/pkg/hints/hint_codes/secp_p_hint.go @@ -0,0 +1,6 @@ +package hint_codes + +const IMPORT_SECP256R1_ALPHA = "from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_ALPHA as ALPHA" +const IMPORT_SECP256R1_N = "from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_N as N" +const IMPORT_SECP256R1_P = "from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P as SECP_P" +const VERIFY_ZERO_EXTERNAL_SECP = "from starkware.cairo.common.cairo_secp.secp_utils import pack\n\nq, r = divmod(pack(ids.val, PRIME), SECP_P)\nassert r == 0, f\"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}.\"\nids.q = q % PRIME" diff --git a/pkg/hints/hint_processor.go b/pkg/hints/hint_processor.go index 9c5947cd..32cab3b2 100644 --- a/pkg/hints/hint_processor.go +++ b/pkg/hints/hint_processor.go @@ -156,10 +156,22 @@ func (p *CairoVmHintProcessor) ExecuteHint(vm *vm.VirtualMachine, hintData *any, return Assert250Bit(data.Ids, vm, constants) case SPLIT_FELT: return SplitFelt(data.Ids, vm, constants) + case IMPORT_SECP256R1_ALPHA: + return importSecp256r1Alpha(*execScopes) + case IMPORT_SECP256R1_N: + return importSECP256R1N(*execScopes) + case IMPORT_SECP256R1_P: + return importSECP256R1P(*execScopes) + case EC_DOUBLE_SLOPE_EXTERNAL_CONSTS: + return computeDoublingSlopeExternalConsts(*vm, *execScopes, data.Ids) + case NONDET_BIGINT3_V1: + return NondetBigInt3(*vm, *execScopes, data.Ids) case SPLIT_INT: return splitInt(data.Ids, vm) case SPLIT_INT_ASSERT_RANGE: return splitIntAssertRange(data.Ids, vm) + case VERIFY_ZERO_EXTERNAL_SECP: + return verifyZeroWithExternalConst(*vm, *execScopes, data.Ids) case FAST_EC_ADD_ASSIGN_NEW_X: return fastEcAddAssignNewX(data.Ids, vm, execScopes, "point0", "point1", SECP_P()) case FAST_EC_ADD_ASSIGN_NEW_X_V2: diff --git a/pkg/hints/hint_utils/bigint_utils.go b/pkg/hints/hint_utils/bigint_utils.go index 10cff28c..9a900443 100644 --- a/pkg/hints/hint_utils/bigint_utils.go +++ b/pkg/hints/hint_utils/bigint_utils.go @@ -6,6 +6,7 @@ import ( . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" . "github.com/lambdaclass/cairo-vm.go/pkg/vm" . "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" + "github.com/pkg/errors" ) diff --git a/pkg/hints/hint_utils/secp_utils.go b/pkg/hints/hint_utils/secp_utils.go index b673e87c..a125823a 100644 --- a/pkg/hints/hint_utils/secp_utils.go +++ b/pkg/hints/hint_utils/secp_utils.go @@ -1,6 +1,9 @@ package hint_utils -import "math/big" +import ( + "errors" + "math/big" +) func SECP_P() big.Int { secpP, _ := new(big.Int).SetString("115792089237316195423570985008687907853269984665640564039457584007908834671663", 10) @@ -16,3 +19,38 @@ func ALPHA() big.Int { alpha := big.NewInt(0) return *alpha } + +func SECP256R1_ALPHA() big.Int { + secpPalpha, _ := new(big.Int).SetString("115792089210356248762697446949407573530086143415290314195533631308867097853948", 10) + return *secpPalpha +} + +func SECP256R1_N() big.Int { + secp256, _ := new(big.Int).SetString("115792089210356248762697446949407573529996955224135760342422259061068512044369", 10) + return *secp256 +} + +func SECP256R1_P() big.Int { + secp256r1, _ := new(big.Int).SetString("115792089210356248762697446949407573530086143415290314195533631308867097853951", 10) + return *secp256r1 +} + +func BASE_MINUS_ONE() *big.Int { + res, _ := new(big.Int).SetString("77371252455336267181195263", 10) + return res +} + +func Bigint3Split(integer big.Int) ([]big.Int, error) { + canonicalRepr := make([]big.Int, 3) + num := integer + + for i := 0; i < 3; i++ { + canonicalRepr[i] = *new(big.Int).And(&num, BASE_MINUS_ONE()) + num.Rsh(&num, 86) + } + if num.Cmp(big.NewInt(0)) != 0 { + return nil, errors.New("HintError SecpSplitOutOfRange") + } + + return canonicalRepr, nil +} diff --git a/pkg/lambdaworks/lambdaworks.go b/pkg/lambdaworks/lambdaworks.go index d2627b93..3cd29d21 100644 --- a/pkg/lambdaworks/lambdaworks.go +++ b/pkg/lambdaworks/lambdaworks.go @@ -309,10 +309,9 @@ func FeltFromBigInt(n *big.Int) Felt { if n.Cmp(prime) != -1 { n = new(big.Int).Mod(n, prime) } - bytes := n.Bytes() - var bytes32 [32]byte - copy(bytes32[:], bytes) - return FeltFromLeBytes(&bytes32) + + value := n.Text(10) + return FeltFromDecString(value) } const CAIRO_PRIME_HEX = "0x800000000000011000000000000000000000000000000000000000000000001" diff --git a/pkg/vm/cairo_run/cairo_run_test.go b/pkg/vm/cairo_run/cairo_run_test.go index 3046cb5c..47fb4e24 100644 --- a/pkg/vm/cairo_run/cairo_run_test.go +++ b/pkg/vm/cairo_run/cairo_run_test.go @@ -321,6 +321,9 @@ func TestSplitIntHintProofMode(t *testing.T) { testProgramProof("split_int", t) } +func TestIntegrationEcDoubleSlope(t *testing.T) { + testProgram("ec_double_slope", t) +} func TestKeccakIntegrationTests(t *testing.T) { testProgram("keccak_integration_tests", t) }