diff --git a/cairo_programs/cairo_keccak.cairo b/cairo_programs/cairo_keccak.cairo index 8adcd515..b5575e7c 100644 --- a/cairo_programs/cairo_keccak.cairo +++ b/cairo_programs/cairo_keccak.cairo @@ -27,3 +27,4 @@ func main{range_check_ptr: felt, bitwise_ptr: BitwiseBuiltin*}() { return (); } + diff --git a/cairo_programs/ec_double_assign.cairo b/cairo_programs/ec_double_assign.cairo new file mode 100644 index 00000000..16419e72 --- /dev/null +++ b/cairo_programs/ec_double_assign.cairo @@ -0,0 +1,32 @@ +%builtins range_check +from starkware.cairo.common.cairo_secp.bigint import BigInt3, nondet_bigint3 +struct EcPoint { + x: BigInt3, + y: BigInt3, +} + +func ec_double{range_check_ptr}(point: EcPoint, slope: BigInt3) -> (res: BigInt3) { + %{ + from starkware.cairo.common.cairo_secp.secp_utils import pack + SECP_P = 2**255-19 + + slope = pack(ids.slope, PRIME) + x = pack(ids.point.x, PRIME) + y = pack(ids.point.y, PRIME) + + value = new_x = (pow(slope, 2, SECP_P) - 2 * x) % SECP_P + %} + + let (new_x: BigInt3) = nondet_bigint3(); + return (res=new_x); +} + +func main{range_check_ptr}() { + let p = EcPoint(BigInt3(1,2,3), BigInt3(4,5,6)); + let s = BigInt3(7,8,9); + let (res) = ec_double(p, s); + assert res.d0 = 21935; + assert res.d1 = 12420; + assert res.d2 = 184; + return (); +} diff --git a/pkg/hints/ec_hint.go b/pkg/hints/ec_hint.go index 005523e0..04f0587c 100644 --- a/pkg/hints/ec_hint.go +++ b/pkg/hints/ec_hint.go @@ -7,6 +7,7 @@ import ( "github.com/lambdaclass/cairo-vm.go/pkg/builtins" "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" . "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils" + . "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks" "github.com/lambdaclass/cairo-vm.go/pkg/types" . "github.com/lambdaclass/cairo-vm.go/pkg/types" "github.com/lambdaclass/cairo-vm.go/pkg/vm" @@ -184,6 +185,48 @@ func computeSlope(vm *VirtualMachine, execScopes ExecutionScopes, idsData IdsMan return nil } +// Implements hint: +// from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack +// +// slope = pack(ids.slope, PRIME) +// x = pack(ids.point.x, PRIME) +// y = pack(ids.point.y, PRIME) +// +// value = new_x = (pow(slope, 2, SECP_P) - 2 * x) % SECP_P +func ecDoubleAssignNewX(vm *VirtualMachine, execScopes ExecutionScopes, ids IdsManager, secpP big.Int) error { + execScopes.AssignOrUpdateVariable("SECP_P", secpP) + + slope3, err := BigInt3FromVarName("slope", ids, vm) + if err != nil { + return err + } + packedSlope := slope3.Pack86() + slope := new(big.Int).Mod(&packedSlope, Prime()) + point, err := EcPointFromVarName("point", vm, ids) + if err != nil { + return err + } + + xPacked := point.X.Pack86() + x := new(big.Int).Mod(&xPacked, Prime()) + yPacked := point.Y.Pack86() + y := new(big.Int).Mod(&yPacked, Prime()) + + value := new(big.Int).Mul(slope, slope) + value = value.Mod(value, &secpP) + + value = value.Sub(value, x) + value = value.Sub(value, x) + value = value.Mod(value, &secpP) + + execScopes.AssignOrUpdateVariable("slope", slope) + execScopes.AssignOrUpdateVariable("x", x) + execScopes.AssignOrUpdateVariable("y", y) + execScopes.AssignOrUpdateVariable("value", *value) + execScopes.AssignOrUpdateVariable("new_x", *value) + return nil +} + /* Implements hint: %{ from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_ALPHA as ALPHA %} diff --git a/pkg/hints/ec_hint_test.go b/pkg/hints/ec_hint_test.go index 3cf08a82..974576b4 100644 --- a/pkg/hints/ec_hint_test.go +++ b/pkg/hints/ec_hint_test.go @@ -235,6 +235,75 @@ func TestRunComputeSlopeOk(t *testing.T) { } } +func TestEcDoubleAssignNewXOk(t *testing.T) { + vm := NewVirtualMachine() + vm.Segments.AddSegment() + idsManager := SetupIdsForTest( + map[string][]*MaybeRelocatable{ + "slope": { + NewMaybeRelocatableFelt(FeltFromUint64(3)), + NewMaybeRelocatableFelt(FeltFromUint64(0)), + NewMaybeRelocatableFelt(FeltFromUint64(0)), + }, + "point": { + // X + NewMaybeRelocatableFelt(FeltFromUint64(2)), + NewMaybeRelocatableFelt(FeltFromUint64(0)), + NewMaybeRelocatableFelt(FeltFromUint64(0)), + // Y + NewMaybeRelocatableFelt(FeltFromUint64(4)), + NewMaybeRelocatableFelt(FeltFromUint64(0)), + NewMaybeRelocatableFelt(FeltFromUint64(0)), + }, + }, + vm, + ) + + hintProcessor := CairoVmHintProcessor{} + hintData := any(HintData{ + Ids: idsManager, + Code: EC_DOUBLE_ASSIGN_NEW_X_V1, + }) + + execScopes := types.NewExecutionScopes() + err := hintProcessor.ExecuteHint(vm, &hintData, nil, execScopes) + + if err != nil { + t.Errorf("EC_DOUBLE_ASSIGN_NEW_X hint failed with error: %s", err) + } + + slopeUncast, _ := execScopes.Get("slope") + slope := slopeUncast.(*big.Int) + xUncast, _ := execScopes.Get("x") + x := xUncast.(*big.Int) + yUncast, _ := execScopes.Get("y") + y := yUncast.(*big.Int) + valueUncast, _ := execScopes.Get("value") + value := valueUncast.(big.Int) + new_xUncast, _ := execScopes.Get("new_x") + new_x := new_xUncast.(big.Int) + + if value.Cmp(&new_x) != 0 { + t.Errorf("EC_DOUBLE_ASSIGN_NEW_X hint failed: new_x != value. %v != %v", new_x, value) + } + expectedRes := big.NewInt(5) + if value.Cmp(expectedRes) != 0 { + t.Errorf("EC_DOUBLE_ASSIGN_NEW_X hint failed: expected value (%v) to be 6", value) + } + expectedSlope := big.NewInt(3) + if slope.Cmp(expectedSlope) != 0 { + t.Errorf("EC_DOUBLE_ASSIGN_NEW_X hint failed: expected slope (%v) to be 3", slope) + } + expectedX := big.NewInt(2) + if x.Cmp(expectedX) != 0 { + t.Errorf("EC_DOUBLE_ASSIGN_NEW_X hint failed: expected x (%v) to be 2", x) + } + expectedY := big.NewInt(4) + if y.Cmp(expectedY) != 0 { + t.Errorf("EC_DOUBLE_ASSIGN_NEW_X hint failed: expected y (%v) to be 4", y) + } +} + func TestRunComputeSlopeV2Ok(t *testing.T) { vm := NewVirtualMachine() diff --git a/pkg/hints/hint_codes/ec_op_hints.go b/pkg/hints/hint_codes/ec_op_hints.go index 471246db..e8ab665c 100644 --- a/pkg/hints/hint_codes/ec_op_hints.go +++ b/pkg/hints/hint_codes/ec_op_hints.go @@ -4,10 +4,39 @@ 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 EC_DOUBLE_ASSIGN_NEW_X_V1 = `from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack + +slope = pack(ids.slope, PRIME) +x = pack(ids.point.x, PRIME) +y = pack(ids.point.y, PRIME) + +value = new_x = (pow(slope, 2, SECP_P) - 2 * x) % SECP_P` +const EC_DOUBLE_ASSIGN_NEW_X_V2 = `from starkware.cairo.common.cairo_secp.secp_utils import pack + +slope = pack(ids.slope, PRIME) +x = pack(ids.point.x, PRIME) +y = pack(ids.point.y, PRIME) + +value = new_x = (pow(slope, 2, SECP_P) - 2 * x) % SECP_P` +const EC_DOUBLE_ASSIGN_NEW_X_V3 = `from starkware.cairo.common.cairo_secp.secp_utils import pack +SECP_P = 2**255-19 + +slope = pack(ids.slope, PRIME) +x = pack(ids.point.x, PRIME) +y = pack(ids.point.y, PRIME) + +value = new_x = (pow(slope, 2, SECP_P) - 2 * x) % SECP_P` +const EC_DOUBLE_ASSIGN_NEW_X_V4 = `from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack + +slope = pack(ids.slope, PRIME) +x = pack(ids.pt.x, PRIME) +y = pack(ids.pt.y, PRIME) + +value = new_x = (pow(slope, 2, SECP_P) - 2 * x) % SECP_P` const COMPUTE_SLOPE_V2 = "from starkware.python.math_utils import line_slope\nfrom starkware.cairo.common.cairo_secp.secp_utils import pack\nSECP_P = 2**255-19\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 COMPUTE_SLOPE_WHITELIST = "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack\nfrom starkware.python.math_utils import div_mod\n\n# Compute the slope.\nx0 = pack(ids.pt0.x, PRIME)\ny0 = pack(ids.pt0.y, PRIME)\nx1 = pack(ids.pt1.x, PRIME)\ny1 = pack(ids.pt1.y, PRIME)\nvalue = slope = div_mod(y0 - y1, x0 - x1, 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 COMPUTE_SLOPE_SECP256R1 = "from starkware.cairo.common.cairo_secp.secp_utils import 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 FAST_EC_ADD_ASSIGN_NEW_X = `"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack diff --git a/pkg/hints/hint_processor.go b/pkg/hints/hint_processor.go index a43c76ef..ccac7bd2 100644 --- a/pkg/hints/hint_processor.go +++ b/pkg/hints/hint_processor.go @@ -92,6 +92,8 @@ func (p *CairoVmHintProcessor) ExecuteHint(vm *vm.VirtualMachine, hintData *any, return ecNegateImportSecpP(vm, *execScopes, data.Ids) case EC_NEGATE_EMBEDDED_SECP: return ecNegateEmbeddedSecpP(vm, *execScopes, data.Ids) + case EC_DOUBLE_ASSIGN_NEW_X_V1, EC_DOUBLE_ASSIGN_NEW_X_V2, EC_DOUBLE_ASSIGN_NEW_X_V3, EC_DOUBLE_ASSIGN_NEW_X_V4: + return ecDoubleAssignNewX(vm, *execScopes, data.Ids, SECP_P_V2()) case POW: return pow(data.Ids, vm) case SQRT: diff --git a/pkg/vm/cairo_run/cairo_run_test.go b/pkg/vm/cairo_run/cairo_run_test.go index f2921821..845a3076 100644 --- a/pkg/vm/cairo_run/cairo_run_test.go +++ b/pkg/vm/cairo_run/cairo_run_test.go @@ -329,6 +329,10 @@ func TestSplitIntHintProofMode(t *testing.T) { testProgramProof("split_int", t) } +func TestEcDoubleAssign(t *testing.T) { + testProgram("ec_double_assign", t) +} + func TestIntegrationEcDoubleSlope(t *testing.T) { testProgram("ec_double_slope", t) }