Skip to content

Commit

Permalink
Implement FieldSqrt hint (#179)
Browse files Browse the repository at this point in the history
* added UpdatePc tests and fixed a bug in UpdatePc

* Fixed accessing field value without Read()

* fixed failing tests

* small refactor for TestUpdatePcJump

* randomEcPoint done

* move comment

* move randomizers into utils.go

* address PR comments

* FieldSqrt hint done

* added test

* added testcase
  • Loading branch information
mmk-1 authored Dec 11, 2023
1 parent 635b495 commit e0ff2e6
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 2 deletions.
47 changes: 47 additions & 0 deletions pkg/hintrunner/hint.go
Original file line number Diff line number Diff line change
Expand Up @@ -1388,6 +1388,7 @@ func (hint *RandomEcPoint) Execute(vm *VM.VirtualMachine) error {
// Legendre == 1 -> Quadratic residue
// Legendre == -1 -> Quadratic non-residue
// Legendre == 0 -> Zero
// https://en.wikipedia.org/wiki/Legendre_symbol
if randomYSquared.Legendre() == 1 {
break
}
Expand Down Expand Up @@ -1418,3 +1419,49 @@ func (hint *RandomEcPoint) Execute(vm *VM.VirtualMachine) error {

return nil
}

type FieldSqrt struct {
val ResOperander
sqrt CellRefer
}

func (hint *FieldSqrt) String() string {
return "FieldSqrt"
}

func (hint *FieldSqrt) Execute(vm *VM.VirtualMachine) error {
val, err := hint.val.Resolve(vm)
if err != nil {
return fmt.Errorf("resolve val operand %s: %v", hint.val, err)
}

valFelt, err := val.FieldElement()
if err != nil {
return err
}

threeFelt := f.Element{}
threeFelt.SetUint64(3)

var res f.Element
// Legendre == 1 -> Quadratic residue
// Legendre == -1 -> Quadratic non-residue
// Legendre == 0 -> Zero
// https://en.wikipedia.org/wiki/Legendre_symbol
if valFelt.Legendre() == 1 {
res = *valFelt
} else {
res = *valFelt.Mul(valFelt, &threeFelt)
}

res.Sqrt(&res)

sqrtVal := mem.MemoryValueFromFieldElement(&res)

sqrtAddr, err := hint.sqrt.Get(vm)
if err != nil {
return fmt.Errorf("get sqrt address: %v", err)
}

return vm.Memory.WriteToAddress(&sqrtAddr, &sqrtVal)
}
24 changes: 22 additions & 2 deletions pkg/hintrunner/hint_bechmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,6 @@ func BenchmarkAssertLeIsFirstArcExcluded(b *testing.B) {

vm.Context.Ap += 1
}

}

func BenchmarkAssertLeIsSecondArcExcluded(b *testing.B) {
Expand Down Expand Up @@ -327,7 +326,6 @@ func BenchmarkAssertLeIsSecondArcExcluded(b *testing.B) {

vm.Context.Ap += 1
}

}

func BenchmarkAssertLeFindSmallArc(b *testing.B) {
Expand Down Expand Up @@ -388,5 +386,27 @@ func BenchmarkRandomEcPoint(b *testing.B) {

vm.Context.Ap += 2
}
}

func BenchmarkFieldSqrt(b *testing.B) {
vm := defaultVirtualMachine()

rand := defaultRandGenerator()

b.ResetTimer()
for i := 0; i < b.N; i++ {

hint := FieldSqrt{
val: Immediate(randomFeltElement(rand)),
sqrt: ApCellRef(0),
}

err := hint.Execute(vm)
if err != nil {
b.Error(err)
break
}

vm.Context.Ap += 1
}
}
43 changes: 43 additions & 0 deletions pkg/hintrunner/hint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -916,3 +916,46 @@ func TestRandomEcPoint(t *testing.T) {
require.Equal(t, expectedX, actualX)
require.Equal(t, expectedY, actualY)
}

func TestFieldSqrt(t *testing.T) {
testCases := []struct {
name string
value uint64
expected int
}{
{
name: "TestFieldSqrt",
value: 49,
expected: 7,
},
{
name: "TestFieldSqrtNonResidue",
value: 27,
expected: -9,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
vm := defaultVirtualMachine()
vm.Context.Ap = 0
vm.Context.Fp = 0

value := Immediate(f.NewElement(tc.value))
hint := FieldSqrt{
val: value,
sqrt: ApCellRef(0),
}

err := hint.Execute(vm)

require.NoError(t, err)
require.Equal(
t,
mem.MemoryValueFromInt(tc.expected),
readFrom(vm, VM.ExecutionSegment, 0),
)
})
}
}

0 comments on commit e0ff2e6

Please sign in to comment.