Skip to content

Commit

Permalink
Add ec hints (#225)
Browse files Browse the repository at this point in the history
* Add ec hints

* Implement hints

* Add the hints to the processor

* Test pack86 function

* Test hint

* Delete debug info, Test ec negative op

* Second hint test

* Test embedded hint

* Change to Camel case
  • Loading branch information
mmsc2 authored Sep 19, 2023
1 parent 60d7b72 commit 462f462
Show file tree
Hide file tree
Showing 12 changed files with 267 additions and 4 deletions.
1 change: 1 addition & 0 deletions pkg/hints/dict_hints_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

. "github.com/lambdaclass/cairo-vm.go/pkg/hints"
"github.com/lambdaclass/cairo-vm.go/pkg/hints/dict_manager"
. "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"
Expand Down
116 changes: 116 additions & 0 deletions pkg/hints/ec_hint.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
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"
)

type BigInt3 struct {
Limbs []lambdaworks.Felt
}

type EcPoint struct {
X BigInt3
Y BigInt3
}

func (val *BigInt3) Pack86() big.Int {
sum := big.NewInt(0)
for i := 0; i < 3; i++ {
felt := val.Limbs[i]
signed := felt.ToSigned()
shifed := new(big.Int).Lsh(signed, uint(i*86))
sum.Add(sum, shifed)
}
return *sum
}

func BigInt3FromBaseAddr(addr memory.Relocatable, virtual_machine vm.VirtualMachine) (BigInt3, error) {
limbs := make([]lambdaworks.Felt, 0)
for i := 0; i < 3; i++ {
felt, err := virtual_machine.Segments.Memory.GetFelt(addr.AddUint(uint(i)))
if err == nil {
limbs = append(limbs, felt)
} else {
return BigInt3{}, errors.New("Identifier has no member")
}
}
return BigInt3{Limbs: limbs}, nil
}

func BigInt3FromVarName(name string, virtual_machine vm.VirtualMachine, ids_data hint_utils.IdsManager) (EcPoint, error) {
point_addr, err := ids_data.GetAddr(name, &virtual_machine)
if err != nil {
return EcPoint{}, err
}

x, err := BigInt3FromBaseAddr(point_addr, virtual_machine)
if err != nil {
return EcPoint{}, err
}

y, err := BigInt3FromBaseAddr(point_addr.AddUint(3), virtual_machine)
if err != nil {
return EcPoint{}, err
}

return EcPoint{X: x, Y: y}, nil
}

/*
Implements main logic for `EC_NEGATE` and `EC_NEGATE_EMBEDDED_SECP` hints
*/
func ecNegate(virtual_machine vm.VirtualMachine, exec_scopes types.ExecutionScopes, ids_data hint_utils.IdsManager, secp_p big.Int) error {
point, err := ids_data.GetRelocatable("point", &virtual_machine)
if err != nil {
return err
}

point_y, err := point.AddInt(3)
if err != nil {
return err
}

y_bigint3, err := BigInt3FromBaseAddr(point_y, virtual_machine)
if err != nil {
return err
}

y := y_bigint3.Pack86()
value := new(big.Int).Neg(&y)
value.Mod(value, &secp_p)

exec_scopes.AssignOrUpdateVariable("value", value)
exec_scopes.AssignOrUpdateVariable("SECP_P", secp_p)
return nil
}

func ecNegateImportSecpP(virtual_machine vm.VirtualMachine, exec_scopes types.ExecutionScopes, ids_data hint_utils.IdsManager) error {
secp_p, _ := new(big.Int).SetString("115792089237316195423570985008687907853269984665640564039457584007908834671663", 10)
return ecNegate(virtual_machine, exec_scopes, ids_data, *secp_p)
}

/*
Implements hint:
%{
from starkware.cairo.common.cairo_secp.secp_utils import pack
SECP_P = 2**255-19
y = pack(ids.point.y, PRIME) % SECP_P
# The modulo operation in python always returns a nonnegative number.
value = (-y) % SECP_P
%}
*/

func ecNegateEmbeddedSecpP(virtual_machine vm.VirtualMachine, exec_scopes types.ExecutionScopes, ids_data hint_utils.IdsManager) error {
secp_p := big.NewInt(1)
secp_p.Lsh(secp_p, 255)
secp_p.Sub(secp_p, big.NewInt(19))
return ecNegate(virtual_machine, exec_scopes, ids_data, *secp_p)
}
134 changes: 134 additions & 0 deletions pkg/hints/ec_hint_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package hints_test

import (
"fmt"
"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 TestBigInt3Pack86(t *testing.T) {
limbs1 := []Felt{FeltFromUint64(10), FeltFromUint64(10), FeltFromUint64(10)}
bigint := BigInt3{Limbs: limbs1}
pack1 := bigint.Pack86()

expected, _ := new(big.Int).SetString("59863107065073783529622931521771477038469668772249610", 10)

if pack1.Cmp(expected) != 0 {
t.Errorf("Different pack from expected")
}

limbs2 := []Felt{FeltFromDecString("773712524553362"), FeltFromDecString("57408430697461422066401280"), FeltFromDecString("1292469707114105")}
bigint2 := BigInt3{Limbs: limbs2}
pack2 := bigint2.Pack86()

expected2, _ := new(big.Int).SetString("7737125245533626718119526477371252455336267181195264773712524553362", 10)

if pack2.Cmp(expected2) != 0 {
t.Errorf("Different pack from expected2")
}
}

func TestRunEcNegateOk(t *testing.T) {
vm := NewVirtualMachine()
vm.Segments.AddSegment()
vm.Segments.AddSegment()
vm.Segments.Memory.Insert(NewRelocatable(1, 3), NewMaybeRelocatableFelt(FeltFromUint64(2645)))
vm.Segments.Memory.Insert(NewRelocatable(1, 4), NewMaybeRelocatableFelt(FeltFromUint64(454)))
vm.Segments.Memory.Insert(NewRelocatable(1, 5), NewMaybeRelocatableFelt(FeltFromUint64(206)))

idsManager := SetupIdsForTest(
map[string][]*MaybeRelocatable{
"point": {NewMaybeRelocatableRelocatable(NewRelocatable(1, 0))},
"ec_negative": {nil},
},
vm,
)

point, _ := idsManager.Get("point", vm)
fmt.Println("Ids manager: ", point)
hintProcessor := CairoVmHintProcessor{}
hintData := any(HintData{
Ids: idsManager,
Code: EC_NEGATE,
})
exec_scopes := types.NewExecutionScopes()
err := hintProcessor.ExecuteHint(vm, &hintData, nil, exec_scopes)
if err != nil {
t.Errorf("Ec Negative hint test failed with error %s", err)
} else {
// Check ids.is_positive
value, err := exec_scopes.Get("value")
val := value.(*big.Int)
expected, _ := new(big.Int).SetString("115792089237316195423569751828682367333329274433232027476421668138471189901786", 10)

if err != nil || expected.Cmp(val) != 0 {
t.Errorf("Ec Negative hint test incorrect value for exec_scopes.value")
}
}
}

func TestRunEcEmbeddedSecpOk(t *testing.T) {
vm := NewVirtualMachine()
vm.Segments.AddSegment()
vm.Segments.AddSegment()
vm.Segments.Memory.Insert(NewRelocatable(1, 3), NewMaybeRelocatableFelt(FeltFromUint64(2645)))
vm.Segments.Memory.Insert(NewRelocatable(1, 4), NewMaybeRelocatableFelt(FeltFromUint64(454)))
vm.Segments.Memory.Insert(NewRelocatable(1, 5), NewMaybeRelocatableFelt(FeltFromUint64(206)))

y2 := big.NewInt(206)
y2.Lsh(y2, 86*2)

y1 := big.NewInt(454)
y1.Lsh(y1, 86)

y0 := big.NewInt(2645)

y := new(big.Int)
y.Add(y, y2)
y.Add(y, y1)
y.Add(y, y0)

vm.RunContext.Fp = NewRelocatable(1, 1)

idsManager := SetupIdsForTest(
map[string][]*MaybeRelocatable{
"point": {NewMaybeRelocatableRelocatable(NewRelocatable(1, 0))},
"ec_negative": {nil},
},
vm,
)

hintProcessor := CairoVmHintProcessor{}
hintData := any(HintData{
Ids: idsManager,
Code: EC_NEGATE_EMBEDDED_SECP,
})
exec_scopes := types.NewExecutionScopes()
err := hintProcessor.ExecuteHint(vm, &hintData, nil, exec_scopes)
if err != nil {
t.Errorf("Ec Negative Embedded Sec hint test failed with error %s", err)
} else {
// Check ids.is_positive
value, err := exec_scopes.Get("value")
val := value.(*big.Int)

// expected value
minus_y := big.NewInt(1)
minus_y.Lsh(minus_y, 255)
minus_y.Sub(minus_y, big.NewInt(19))
minus_y.Sub(minus_y, y)

if err != nil || minus_y.Cmp(val) != 0 {
t.Errorf("Ec Negative hint test incorrect value for exec_scopes.value")
}
}

}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package hints
package hint_codes

const DEFAULT_DICT_NEW = "if '__dict_manager' not in globals():\n from starkware.cairo.common.dict import DictManager\n __dict_manager = DictManager()\n\nmemory[ap] = __dict_manager.new_default_dict(segments, ids.default_value)"

Expand Down
4 changes: 4 additions & 0 deletions pkg/hints/hint_codes/ec_op_hints.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package hint_codes

const EC_NEGATE = "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack\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_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"
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package hints
package hint_codes

const ASSERT_NN = "from starkware.cairo.common.math_utils import assert_integer\nassert_integer(ids.a)\nassert 0 <= ids.a % PRIME < range_check_builtin.bound, f'a = {ids.a} is out of range.'"

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package hints
package hint_codes

const ADD_SEGMENT = "memory[ap] = segments.add()"
const VM_EXIT_SCOPE = "vm_exit_scope()"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
package hints
package hint_codes

const POW = "ids.locs.bit = (ids.prev_locs.exp % PRIME) & 1"
5 changes: 5 additions & 0 deletions pkg/hints/hint_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package hints
import (
"strings"

. "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_codes"
. "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils"
. "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks"
"github.com/lambdaclass/cairo-vm.go/pkg/parser"
Expand Down Expand Up @@ -61,6 +62,10 @@ func (p *CairoVmHintProcessor) ExecuteHint(vm *vm.VirtualMachine, hintData *any,
return vm_exit_scope(execScopes)
case ASSERT_NOT_EQUAL:
return assert_not_equal(data.Ids, vm)
case EC_NEGATE:
return ecNegateImportSecpP(*vm, *execScopes, data.Ids)
case EC_NEGATE_EMBEDDED_SECP:
return ecNegateEmbeddedSecpP(*vm, *execScopes, data.Ids)
case POW:
return pow(data.Ids, vm)
case SQRT:
Expand Down
1 change: 1 addition & 0 deletions pkg/hints/math_hints_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"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/vm"
Expand Down
1 change: 1 addition & 0 deletions pkg/hints/memcpy_hints_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"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"
Expand Down
1 change: 1 addition & 0 deletions pkg/hints/pow_hints_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package hints_test

import (
. "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/vm"
Expand Down

0 comments on commit 462f462

Please sign in to comment.