From 5023b3da9768eab21f9c57a71e975f72cab75feb Mon Sep 17 00:00:00 2001
From: jmjac <jakub@jackowiak.dev>
Date: Fri, 3 Nov 2023 07:41:31 -0400
Subject: [PATCH 01/16] Initial idea for ecdsa

---
 pkg/vm/builtins/ecdsa.go | 110 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 110 insertions(+)
 create mode 100644 pkg/vm/builtins/ecdsa.go

diff --git a/pkg/vm/builtins/ecdsa.go b/pkg/vm/builtins/ecdsa.go
new file mode 100644
index 000000000..3c21e2d31
--- /dev/null
+++ b/pkg/vm/builtins/ecdsa.go
@@ -0,0 +1,110 @@
+package builtins
+
+import (
+	"fmt"
+
+	"github.com/NethermindEth/cairo-vm-go/pkg/vm/memory"
+	starkcurve "github.com/consensys/gnark-crypto/ecc/stark-curve"
+	ecdsa "github.com/consensys/gnark-crypto/ecc/stark-curve/ecdsa"
+	"github.com/consensys/gnark-crypto/ecc/stark-curve/fp"
+)
+
+const ECDSAName = "ecdsa"
+const cellsPerECDSA = 2
+const inputCellsPerECDSA = 2 //Public key and msg
+
+type ECDSA struct {
+	signatures map[uint64]ecdsa.Signature
+}
+
+func (e *ECDSA) InferValue(segment *memory.Segment, offset uint64) error {
+	ecdsaIndex := offset % cellsPerECDSA
+	// input cell
+	pubOffset := offset - ecdsaIndex
+	msg_offset := pubOffset + 1
+
+	pub := segment.Peek(offset)
+	if !pub.Known() {
+		return fmt.Errorf("cannot infer value: input value at offset %d is unknown", pubOffset)
+	}
+
+	pubX, err := pub.FieldElement() //X element of the sig
+	if err != nil {
+		return err
+	}
+
+	msg := segment.Peek(offset)
+	if !msg.Known() {
+		return fmt.Errorf("cannot infer value: input value at offset %d is unknown", msg_offset)
+	}
+	msgField, err := msg.FieldElement()
+	if err != nil {
+		return err
+	}
+
+	//Sig verification
+	pubY, err := recoverY(pubX)
+	if err != nil {
+		return err
+	}
+
+	key := starkcurve.G1Affine{X: *pubX, Y: *pubY}
+	if !key.IsOnCurve() {
+		return fmt.Errorf("Key is not on curve")
+	}
+
+	pubKey := &ecdsa.PublicKey{A: key}
+	sig, ok := e.signatures[pubOffset]
+	if !ok {
+		return fmt.Errorf("Signature is missing form ECDA builtin")
+	}
+	msgBytes := msgField.Bytes()
+	pubKey.Verify(sig.Bytes(), msgBytes[:], nil)
+	//TODO: Get r, s, pub and hash
+
+	return nil
+}
+
+// "code": "ecdsa_builtin.add_signature(ids.ecdsa_ptr.address_, (ids.signature_r, ids.signature_s))",
+func (e *ECDSA) addSignature(pubOffset uint64, r, s fp.Element) error {
+	bytes := make([]byte, 0, 64)
+	rBytes := r.Bytes()
+	bytes = append(bytes, rBytes[:]...)
+	sBytes := s.Bytes()
+	bytes = append(bytes, sBytes[:]...)
+
+	sig := ecdsa.Signature{}
+	_, err := sig.SetBytes(bytes)
+	if err != nil {
+		return err
+	}
+
+	e.signatures[pubOffset] = sig
+	return nil
+}
+
+func (e *ECDSA) CheckWrite(segment *memory.Segment, offset uint64, value *memory.MemoryValue) error {
+	return nil
+}
+
+func (e *ECDSA) String() string {
+	return ECDSAName
+}
+
+// recoverY recovers the y coordinate of x. True y can be either y or -y
+func recoverY(x *fp.Element) (*fp.Element, error) {
+	ALPHA := fp.NewElement(1)
+	BETA := fp.Element{}
+	BETA.SetString("3141592653589793238462643383279502884197169399375105820974944592307816406665")
+	//y_squared = (x * x * x + ALPHA * x + BETA) % FIELD_PRIME
+	x2 := new(fp.Element).Mul(x, x)
+	x3 := x2.Mul(x2, x)
+	a := new(fp.Element).Mul(&ALPHA, x)
+	x3.Add(x3, a)
+	x3.Add(x3, &BETA)
+	y := x3.Sqrt(x3)
+	if y == nil {
+		return nil, fmt.Errorf("Invalid Public key")
+	}
+	return y, nil
+}

From d7419614d40918342a636d598c9fc7bf3d5312d1 Mon Sep 17 00:00:00 2001
From: jmjac <jakub@jackowiak.dev>
Date: Fri, 3 Nov 2023 08:01:55 -0400
Subject: [PATCH 02/16] Check the sig

---
 pkg/vm/builtins/ecdsa.go | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/pkg/vm/builtins/ecdsa.go b/pkg/vm/builtins/ecdsa.go
index 3c21e2d31..ada188cf1 100644
--- a/pkg/vm/builtins/ecdsa.go
+++ b/pkg/vm/builtins/ecdsa.go
@@ -59,7 +59,15 @@ func (e *ECDSA) InferValue(segment *memory.Segment, offset uint64) error {
 		return fmt.Errorf("Signature is missing form ECDA builtin")
 	}
 	msgBytes := msgField.Bytes()
-	pubKey.Verify(sig.Bytes(), msgBytes[:], nil)
+	valid, err := pubKey.Verify(sig.Bytes(), msgBytes[:], nil)
+	if err != nil {
+		return err
+	}
+
+	if !valid {
+		return fmt.Errorf("Signature is not valid")
+	}
+
 	//TODO: Get r, s, pub and hash
 
 	return nil

From 925bad083eee89cfe02e784585a5271b586754c8 Mon Sep 17 00:00:00 2001
From: jmjac <jakub@jackowiak.dev>
Date: Mon, 6 Nov 2023 00:47:31 -0500
Subject: [PATCH 03/16] Fix linter

---
 pkg/vm/builtins/ecdsa.go | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/pkg/vm/builtins/ecdsa.go b/pkg/vm/builtins/ecdsa.go
index ada188cf1..81df37e47 100644
--- a/pkg/vm/builtins/ecdsa.go
+++ b/pkg/vm/builtins/ecdsa.go
@@ -103,8 +103,8 @@ func (e *ECDSA) String() string {
 func recoverY(x *fp.Element) (*fp.Element, error) {
 	ALPHA := fp.NewElement(1)
 	BETA := fp.Element{}
-	BETA.SetString("3141592653589793238462643383279502884197169399375105820974944592307816406665")
-	//y_squared = (x * x * x + ALPHA * x + BETA) % FIELD_PRIME
+	_, _ = BETA.SetString("3141592653589793238462643383279502884197169399375105820974944592307816406665")
+	// y_squared = (x * x * x + ALPHA * x + BETA) % FIELD_PRIME
 	x2 := new(fp.Element).Mul(x, x)
 	x3 := x2.Mul(x2, x)
 	a := new(fp.Element).Mul(&ALPHA, x)

From 098cf1c55f3e24b6e5c41fe5232440541aaea58a Mon Sep 17 00:00:00 2001
From: jmjac <jakub@jackowiak.dev>
Date: Mon, 6 Nov 2023 06:27:12 -0500
Subject: [PATCH 04/16] Fix reading offsets

---
 pkg/vm/builtins/ecdsa.go      | 17 ++++++++++++-----
 pkg/vm/builtins/ecdsa_test.go | 30 ++++++++++++++++++++++++++++++
 2 files changed, 42 insertions(+), 5 deletions(-)
 create mode 100644 pkg/vm/builtins/ecdsa_test.go

diff --git a/pkg/vm/builtins/ecdsa.go b/pkg/vm/builtins/ecdsa.go
index 81df37e47..9e0d04801 100644
--- a/pkg/vm/builtins/ecdsa.go
+++ b/pkg/vm/builtins/ecdsa.go
@@ -10,7 +10,7 @@ import (
 )
 
 const ECDSAName = "ecdsa"
-const cellsPerECDSA = 2
+const cellsPerECDSA = 3
 const inputCellsPerECDSA = 2 //Public key and msg
 
 type ECDSA struct {
@@ -18,12 +18,13 @@ type ECDSA struct {
 }
 
 func (e *ECDSA) InferValue(segment *memory.Segment, offset uint64) error {
+	fmt.Println("INGERING")
 	ecdsaIndex := offset % cellsPerECDSA
-	// input cell
 	pubOffset := offset - ecdsaIndex
 	msg_offset := pubOffset + 1
+	fmt.Println(offset, cellsPerECDSA, offset&cellsPerECDSA, pubOffset, msg_offset)
 
-	pub := segment.Peek(offset)
+	pub := segment.Peek(pubOffset)
 	if !pub.Known() {
 		return fmt.Errorf("cannot infer value: input value at offset %d is unknown", pubOffset)
 	}
@@ -33,7 +34,7 @@ func (e *ECDSA) InferValue(segment *memory.Segment, offset uint64) error {
 		return err
 	}
 
-	msg := segment.Peek(offset)
+	msg := segment.Peek(msg_offset)
 	if !msg.Known() {
 		return fmt.Errorf("cannot infer value: input value at offset %d is unknown", msg_offset)
 	}
@@ -63,10 +64,13 @@ func (e *ECDSA) InferValue(segment *memory.Segment, offset uint64) error {
 	if err != nil {
 		return err
 	}
+	fmt.Println(valid, err)
 
 	if !valid {
 		return fmt.Errorf("Signature is not valid")
 	}
+	v := memory.MemoryValueFromInt(0)
+	segment.Write(offset, &v)
 
 	//TODO: Get r, s, pub and hash
 
@@ -74,7 +78,10 @@ func (e *ECDSA) InferValue(segment *memory.Segment, offset uint64) error {
 }
 
 // "code": "ecdsa_builtin.add_signature(ids.ecdsa_ptr.address_, (ids.signature_r, ids.signature_s))",
-func (e *ECDSA) addSignature(pubOffset uint64, r, s fp.Element) error {
+func (e *ECDSA) AddSignature(pubOffset uint64, r, s fp.Element) error {
+	if e.signatures == nil {
+		e.signatures = make(map[uint64]ecdsa.Signature)
+	}
 	bytes := make([]byte, 0, 64)
 	rBytes := r.Bytes()
 	bytes = append(bytes, rBytes[:]...)
diff --git a/pkg/vm/builtins/ecdsa_test.go b/pkg/vm/builtins/ecdsa_test.go
new file mode 100644
index 000000000..41ac7d490
--- /dev/null
+++ b/pkg/vm/builtins/ecdsa_test.go
@@ -0,0 +1,30 @@
+package builtins
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/NethermindEth/cairo-vm-go/pkg/vm/memory"
+	"github.com/consensys/gnark-crypto/ecc/stark-curve/fp"
+	"github.com/stretchr/testify/require"
+)
+
+func TestECDSA(t *testing.T) {
+	ecdsa := &ECDSA{}
+	segment := memory.EmptySegmentWithLength(5)
+	segment.WithBuiltinRunner(ecdsa)
+
+	pubkey, _ := new(fp.Element).SetString("1839793652349538280924927302501143912227271479439798783640887258675143576352")
+	msg, _ := new(fp.Element).SetString("1839793652349538280924927302501143912227271479439798783640887258675143576352")
+	r, _ := new(fp.Element).SetString("1839793652349538280924927302501143912227271479439798783640887258675143576352")
+	s, _ := new(fp.Element).SetString("1819432147005223164874083361865404672584671743718628757598322238853218813979")
+
+	pubkeyValue := memory.MemoryValueFromFieldElement(pubkey)
+	msgValue := memory.MemoryValueFromFieldElement(msg)
+
+	require.NoError(t, segment.Write(0, &pubkeyValue))
+	require.NoError(t, segment.Write(1, &msgValue))
+	ecdsa.AddSignature(0, *r, *s)
+
+	fmt.Println(segment.Read(2))
+}

From 05cccde739cbbcb012aead7f7ac88ae896f703eb Mon Sep 17 00:00:00 2001
From: jmjac <jakub@jackowiak.dev>
Date: Mon, 6 Nov 2023 07:22:34 -0500
Subject: [PATCH 05/16] Fix ecdsa signature test values

---
 pkg/vm/builtins/ecdsa_test.go | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/pkg/vm/builtins/ecdsa_test.go b/pkg/vm/builtins/ecdsa_test.go
index 41ac7d490..fbbe7d5b6 100644
--- a/pkg/vm/builtins/ecdsa_test.go
+++ b/pkg/vm/builtins/ecdsa_test.go
@@ -14,10 +14,10 @@ func TestECDSA(t *testing.T) {
 	segment := memory.EmptySegmentWithLength(5)
 	segment.WithBuiltinRunner(ecdsa)
 
-	pubkey, _ := new(fp.Element).SetString("1839793652349538280924927302501143912227271479439798783640887258675143576352")
-	msg, _ := new(fp.Element).SetString("1839793652349538280924927302501143912227271479439798783640887258675143576352")
-	r, _ := new(fp.Element).SetString("1839793652349538280924927302501143912227271479439798783640887258675143576352")
-	s, _ := new(fp.Element).SetString("1819432147005223164874083361865404672584671743718628757598322238853218813979")
+	pubkey, _ := new(fp.Element).SetString("1735102664668487605176656616876767369909409133946409161569774794110049207117")
+	msg, _ := new(fp.Element).SetString("2718")
+	r, _ := new(fp.Element).SetString("3086480810278599376317923499561306189851900463386393948998357832163236918254")
+	s, _ := new(fp.Element).SetString("598673427589502599949712887611119751108407514580626464031881322743364689811")
 
 	pubkeyValue := memory.MemoryValueFromFieldElement(pubkey)
 	msgValue := memory.MemoryValueFromFieldElement(msg)

From 12780576be93e408a61b9a5e0778894387c71819 Mon Sep 17 00:00:00 2001
From: jmjac <jakub@jackowiak.dev>
Date: Mon, 6 Nov 2023 07:33:12 -0500
Subject: [PATCH 06/16] Fix failing test case

---
 pkg/vm/builtins/ecdsa.go | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/pkg/vm/builtins/ecdsa.go b/pkg/vm/builtins/ecdsa.go
index 9e0d04801..ab722eb2e 100644
--- a/pkg/vm/builtins/ecdsa.go
+++ b/pkg/vm/builtins/ecdsa.go
@@ -121,5 +121,6 @@ func recoverY(x *fp.Element) (*fp.Element, error) {
 	if y == nil {
 		return nil, fmt.Errorf("Invalid Public key")
 	}
-	return y, nil
+	//TODO: Figure out if we need to check both
+	return y.Neg(y), nil
 }

From acdcc3ece01aef211f577e6c12f2de88f88d8d18 Mon Sep 17 00:00:00 2001
From: jmjac <jakub@jackowiak.dev>
Date: Mon, 6 Nov 2023 10:09:45 -0500
Subject: [PATCH 07/16] Check pubkey with y and -y

---
 pkg/vm/builtins/ecdsa.go | 27 ++++++++++++++++++---------
 1 file changed, 18 insertions(+), 9 deletions(-)

diff --git a/pkg/vm/builtins/ecdsa.go b/pkg/vm/builtins/ecdsa.go
index ab722eb2e..3c98d1b47 100644
--- a/pkg/vm/builtins/ecdsa.go
+++ b/pkg/vm/builtins/ecdsa.go
@@ -18,7 +18,6 @@ type ECDSA struct {
 }
 
 func (e *ECDSA) InferValue(segment *memory.Segment, offset uint64) error {
-	fmt.Println("INGERING")
 	ecdsaIndex := offset % cellsPerECDSA
 	pubOffset := offset - ecdsaIndex
 	msg_offset := pubOffset + 1
@@ -44,12 +43,13 @@ func (e *ECDSA) InferValue(segment *memory.Segment, offset uint64) error {
 	}
 
 	//Sig verification
-	pubY, err := recoverY(pubX)
+	posY, negY, err := recoverY(pubX)
 	if err != nil {
 		return err
 	}
 
-	key := starkcurve.G1Affine{X: *pubX, Y: *pubY}
+	//Try first with positive y
+	key := starkcurve.G1Affine{X: *pubX, Y: *posY}
 	if !key.IsOnCurve() {
 		return fmt.Errorf("Key is not on curve")
 	}
@@ -59,15 +59,24 @@ func (e *ECDSA) InferValue(segment *memory.Segment, offset uint64) error {
 	if !ok {
 		return fmt.Errorf("Signature is missing form ECDA builtin")
 	}
+
 	msgBytes := msgField.Bytes()
 	valid, err := pubKey.Verify(sig.Bytes(), msgBytes[:], nil)
 	if err != nil {
 		return err
 	}
-	fmt.Println(valid, err)
 
 	if !valid {
-		return fmt.Errorf("Signature is not valid")
+		// Now try with Neg Y. Already know the point is on the curve so no need to check again
+		key = starkcurve.G1Affine{X: *pubX, Y: *negY}
+		pubKey = &ecdsa.PublicKey{A: key}
+		valid, err := pubKey.Verify(sig.Bytes(), msgBytes[:], nil)
+		if err != nil {
+			return err
+		}
+		if !valid {
+			return fmt.Errorf("Signature is not valid")
+		}
 	}
 	v := memory.MemoryValueFromInt(0)
 	segment.Write(offset, &v)
@@ -106,8 +115,8 @@ func (e *ECDSA) String() string {
 	return ECDSAName
 }
 
-// recoverY recovers the y coordinate of x. True y can be either y or -y
-func recoverY(x *fp.Element) (*fp.Element, error) {
+// recoverY recovers the y and -y coordinate of x. True y can be either y or -y
+func recoverY(x *fp.Element) (*fp.Element, *fp.Element, error) {
 	ALPHA := fp.NewElement(1)
 	BETA := fp.Element{}
 	_, _ = BETA.SetString("3141592653589793238462643383279502884197169399375105820974944592307816406665")
@@ -119,8 +128,8 @@ func recoverY(x *fp.Element) (*fp.Element, error) {
 	x3.Add(x3, &BETA)
 	y := x3.Sqrt(x3)
 	if y == nil {
-		return nil, fmt.Errorf("Invalid Public key")
+		return nil, nil, fmt.Errorf("Invalid Public key")
 	}
 	//TODO: Figure out if we need to check both
-	return y.Neg(y), nil
+	return y, new(fp.Element).Neg(y), nil
 }

From 0f1545514e93656a57378ae2c91220fa60fc9856 Mon Sep 17 00:00:00 2001
From: jmjac <jakub@jackowiak.dev>
Date: Mon, 6 Nov 2023 21:07:30 -0500
Subject: [PATCH 08/16] Check for errors during testing

---
 pkg/vm/builtins/ecdsa.go      | 3 ---
 pkg/vm/builtins/ecdsa_test.go | 7 ++++---
 2 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/pkg/vm/builtins/ecdsa.go b/pkg/vm/builtins/ecdsa.go
index 3c98d1b47..97ed77a3d 100644
--- a/pkg/vm/builtins/ecdsa.go
+++ b/pkg/vm/builtins/ecdsa.go
@@ -78,9 +78,6 @@ func (e *ECDSA) InferValue(segment *memory.Segment, offset uint64) error {
 			return fmt.Errorf("Signature is not valid")
 		}
 	}
-	v := memory.MemoryValueFromInt(0)
-	segment.Write(offset, &v)
-
 	//TODO: Get r, s, pub and hash
 
 	return nil
diff --git a/pkg/vm/builtins/ecdsa_test.go b/pkg/vm/builtins/ecdsa_test.go
index fbbe7d5b6..af9fa1b75 100644
--- a/pkg/vm/builtins/ecdsa_test.go
+++ b/pkg/vm/builtins/ecdsa_test.go
@@ -1,7 +1,6 @@
 package builtins
 
 import (
-	"fmt"
 	"testing"
 
 	"github.com/NethermindEth/cairo-vm-go/pkg/vm/memory"
@@ -24,7 +23,9 @@ func TestECDSA(t *testing.T) {
 
 	require.NoError(t, segment.Write(0, &pubkeyValue))
 	require.NoError(t, segment.Write(1, &msgValue))
-	ecdsa.AddSignature(0, *r, *s)
+	err := ecdsa.AddSignature(0, *r, *s)
+	require.NoError(t, err)
 
-	fmt.Println(segment.Read(2))
+	_, err = segment.Read(2)
+	require.NoError(t, err)
 }

From 398be0e1e50a93439782ad2a380f33f2f9990068 Mon Sep 17 00:00:00 2001
From: jmjac <jakub@jackowiak.dev>
Date: Wed, 8 Nov 2023 20:45:28 -0500
Subject: [PATCH 09/16] WIP integration tests

---
 integration_tests/cairozero_test.go | 12 ++++++++++++
 pkg/vm/builtins/builtin_runner.go   |  2 +-
 pkg/vm/builtins/ecdsa.go            | 14 +++++++++-----
 3 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/integration_tests/cairozero_test.go b/integration_tests/cairozero_test.go
index 2ec2952c2..3bc5004c7 100644
--- a/integration_tests/cairozero_test.go
+++ b/integration_tests/cairozero_test.go
@@ -268,3 +268,15 @@ func TestPedersen(t *testing.T) {
 
 	clean("./builtin_tests/")
 }
+
+func TestECDSA(t *testing.T) {
+	compiledOutput, err := compileZeroCode("./builtin_tests/ecdsa_test.cairo")
+	require.NoError(t, err)
+
+	_, _, output, err := runVm(compiledOutput)
+	fmt.Println(output)
+	require.NoError(t, err)
+	//require.Contains(t, output, "Program output:\n\t2089986280348253421170679821480865132823066470938446095505822317253594081284")
+
+	clean("./builtin_tests/")
+}
diff --git a/pkg/vm/builtins/builtin_runner.go b/pkg/vm/builtins/builtin_runner.go
index bdc37d240..7bdec5dbd 100644
--- a/pkg/vm/builtins/builtin_runner.go
+++ b/pkg/vm/builtins/builtin_runner.go
@@ -14,7 +14,7 @@ func Runner(name starknetParser.Builtin) memory.BuiltinRunner {
 	case starknetParser.Pedersen:
 		return &Pedersen{}
 	case starknetParser.ECDSA:
-		panic("Not implemented")
+		return &ECDSA{}
 	case starknetParser.Keccak:
 		panic("Not implemented")
 	case starknetParser.Bitwise:
diff --git a/pkg/vm/builtins/ecdsa.go b/pkg/vm/builtins/ecdsa.go
index 97ed77a3d..987c087c9 100644
--- a/pkg/vm/builtins/ecdsa.go
+++ b/pkg/vm/builtins/ecdsa.go
@@ -10,13 +10,21 @@ import (
 )
 
 const ECDSAName = "ecdsa"
-const cellsPerECDSA = 3
+const cellsPerECDSA = 2
 const inputCellsPerECDSA = 2 //Public key and msg
 
 type ECDSA struct {
 	signatures map[uint64]ecdsa.Signature
 }
 
+//	verify_ecdsa_signature(message_hash, public_key, sig_r, sig_s)
+//
+// Test with casm ?
+func (e *ECDSA) CheckWrite(segment *memory.Segment, offset uint64, value *memory.MemoryValue) error {
+	fmt.Printf("Checking write for %v:%v value :%s\n", segment, offset, value)
+	return nil
+}
+
 func (e *ECDSA) InferValue(segment *memory.Segment, offset uint64) error {
 	ecdsaIndex := offset % cellsPerECDSA
 	pubOffset := offset - ecdsaIndex
@@ -104,10 +112,6 @@ func (e *ECDSA) AddSignature(pubOffset uint64, r, s fp.Element) error {
 	return nil
 }
 
-func (e *ECDSA) CheckWrite(segment *memory.Segment, offset uint64, value *memory.MemoryValue) error {
-	return nil
-}
-
 func (e *ECDSA) String() string {
 	return ECDSAName
 }

From 11c548552c3f9e89fbd43fba7fdb77a0cdcb502b Mon Sep 17 00:00:00 2001
From: jmjac <jakub@jackowiak.dev>
Date: Thu, 9 Nov 2023 08:36:09 -0500
Subject: [PATCH 10/16] Add integration test

---
 .../builtin_tests/ecdsa_test.cairo            | 13 ++++++++++
 integration_tests/cairozero_test.go           |  2 +-
 pkg/vm/builtins/ecdsa.go                      | 18 +++++++------
 pkg/vm/builtins/ecdsa_test.go                 | 25 ++++++++++++++++---
 4 files changed, 45 insertions(+), 13 deletions(-)
 create mode 100644 integration_tests/builtin_tests/ecdsa_test.cairo

diff --git a/integration_tests/builtin_tests/ecdsa_test.cairo b/integration_tests/builtin_tests/ecdsa_test.cairo
new file mode 100644
index 000000000..25f4ba39e
--- /dev/null
+++ b/integration_tests/builtin_tests/ecdsa_test.cairo
@@ -0,0 +1,13 @@
+%builtins ecdsa 
+from starkware.cairo.common.cairo_builtins import SignatureBuiltin
+from starkware.cairo.common.signature import verify_ecdsa_signature
+
+func main{ ecdsa_ptr: SignatureBuiltin*}() {
+     verify_ecdsa_signature(
+        2718,
+        1735102664668487605176656616876767369909409133946409161569774794110049207117,
+        3086480810278599376317923499561306189851900463386393948998357832163236918254,
+        598673427589502599949712887611119751108407514580626464031881322743364689811,
+    );
+    return ();
+}
diff --git a/integration_tests/cairozero_test.go b/integration_tests/cairozero_test.go
index 3bc5004c7..2ef30bbc7 100644
--- a/integration_tests/cairozero_test.go
+++ b/integration_tests/cairozero_test.go
@@ -274,9 +274,9 @@ func TestECDSA(t *testing.T) {
 	require.NoError(t, err)
 
 	_, _, output, err := runVm(compiledOutput)
+	//Note: This fails because no addSiganture hint
 	fmt.Println(output)
 	require.NoError(t, err)
-	//require.Contains(t, output, "Program output:\n\t2089986280348253421170679821480865132823066470938446095505822317253594081284")
 
 	clean("./builtin_tests/")
 }
diff --git a/pkg/vm/builtins/ecdsa.go b/pkg/vm/builtins/ecdsa.go
index 987c087c9..196ac33e6 100644
--- a/pkg/vm/builtins/ecdsa.go
+++ b/pkg/vm/builtins/ecdsa.go
@@ -21,19 +21,15 @@ type ECDSA struct {
 //
 // Test with casm ?
 func (e *ECDSA) CheckWrite(segment *memory.Segment, offset uint64, value *memory.MemoryValue) error {
-	fmt.Printf("Checking write for %v:%v value :%s\n", segment, offset, value)
-	return nil
-}
-
-func (e *ECDSA) InferValue(segment *memory.Segment, offset uint64) error {
 	ecdsaIndex := offset % cellsPerECDSA
 	pubOffset := offset - ecdsaIndex
 	msg_offset := pubOffset + 1
-	fmt.Println(offset, cellsPerECDSA, offset&cellsPerECDSA, pubOffset, msg_offset)
 
 	pub := segment.Peek(pubOffset)
 	if !pub.Known() {
-		return fmt.Errorf("cannot infer value: input value at offset %d is unknown", pubOffset)
+		//Not sure if this is the right approach. It seems the msg and pub key  can be passed in either order
+		return nil
+		//return fmt.Errorf("cannot infer value: input value at offset %d is unknown", pubOffset)
 	}
 
 	pubX, err := pub.FieldElement() //X element of the sig
@@ -43,7 +39,8 @@ func (e *ECDSA) InferValue(segment *memory.Segment, offset uint64) error {
 
 	msg := segment.Peek(msg_offset)
 	if !msg.Known() {
-		return fmt.Errorf("cannot infer value: input value at offset %d is unknown", msg_offset)
+		return nil
+		//return fmt.Errorf("cannot infer value: input value at offset %d is unknown", msg_offset)
 	}
 	msgField, err := msg.FieldElement()
 	if err != nil {
@@ -87,10 +84,15 @@ func (e *ECDSA) InferValue(segment *memory.Segment, offset uint64) error {
 		}
 	}
 	//TODO: Get r, s, pub and hash
+	fmt.Println("VALID")
 
 	return nil
 }
 
+func (e *ECDSA) InferValue(segment *memory.Segment, offset uint64) error {
+	return fmt.Errorf("Can't infer value")
+}
+
 // "code": "ecdsa_builtin.add_signature(ids.ecdsa_ptr.address_, (ids.signature_r, ids.signature_s))",
 func (e *ECDSA) AddSignature(pubOffset uint64, r, s fp.Element) error {
 	if e.signatures == nil {
diff --git a/pkg/vm/builtins/ecdsa_test.go b/pkg/vm/builtins/ecdsa_test.go
index af9fa1b75..f86adc206 100644
--- a/pkg/vm/builtins/ecdsa_test.go
+++ b/pkg/vm/builtins/ecdsa_test.go
@@ -21,11 +21,28 @@ func TestECDSA(t *testing.T) {
 	pubkeyValue := memory.MemoryValueFromFieldElement(pubkey)
 	msgValue := memory.MemoryValueFromFieldElement(msg)
 
-	require.NoError(t, segment.Write(0, &pubkeyValue))
-	require.NoError(t, segment.Write(1, &msgValue))
 	err := ecdsa.AddSignature(0, *r, *s)
+	require.NoError(t, segment.Write(1, &msgValue))
+	require.NoError(t, segment.Write(0, &pubkeyValue))
 	require.NoError(t, err)
 
-	_, err = segment.Read(2)
-	require.NoError(t, err)
+}
+func TestECDSAInvalidSig(t *testing.T) {
+	ecdsa := &ECDSA{}
+	segment := memory.EmptySegmentWithLength(5)
+	segment.WithBuiltinRunner(ecdsa)
+
+	pubkey, _ := new(fp.Element).SetString("1735102664668487605176656616876767369909409133946409161569774794110049207117")
+	msg, _ := new(fp.Element).SetString("999999999999999")
+	r, _ := new(fp.Element).SetString("4123123123213")
+	s, _ := new(fp.Element).SetString("31231231313")
+
+	pubkeyValue := memory.MemoryValueFromFieldElement(pubkey)
+	msgValue := memory.MemoryValueFromFieldElement(msg)
+
+	err := ecdsa.AddSignature(0, *r, *s)
+	require.NoError(t, segment.Write(0, &pubkeyValue))
+	err = segment.Write(1, &msgValue)
+	require.ErrorContains(t, err, "Signature is not valid")
+
 }

From 09e8843b231a5049efebff5880f8001ff0daa93a Mon Sep 17 00:00:00 2001
From: jmjac <jakub@jackowiak.dev>
Date: Thu, 9 Nov 2023 08:40:07 -0500
Subject: [PATCH 11/16] Fix linter

---
 pkg/vm/builtins/ecdsa.go      | 1 -
 pkg/vm/builtins/ecdsa_test.go | 7 +++----
 2 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/pkg/vm/builtins/ecdsa.go b/pkg/vm/builtins/ecdsa.go
index 196ac33e6..dc3d852d5 100644
--- a/pkg/vm/builtins/ecdsa.go
+++ b/pkg/vm/builtins/ecdsa.go
@@ -11,7 +11,6 @@ import (
 
 const ECDSAName = "ecdsa"
 const cellsPerECDSA = 2
-const inputCellsPerECDSA = 2 //Public key and msg
 
 type ECDSA struct {
 	signatures map[uint64]ecdsa.Signature
diff --git a/pkg/vm/builtins/ecdsa_test.go b/pkg/vm/builtins/ecdsa_test.go
index f86adc206..5549c63d7 100644
--- a/pkg/vm/builtins/ecdsa_test.go
+++ b/pkg/vm/builtins/ecdsa_test.go
@@ -21,10 +21,9 @@ func TestECDSA(t *testing.T) {
 	pubkeyValue := memory.MemoryValueFromFieldElement(pubkey)
 	msgValue := memory.MemoryValueFromFieldElement(msg)
 
-	err := ecdsa.AddSignature(0, *r, *s)
+	require.NoError(t, ecdsa.AddSignature(0, *r, *s))
 	require.NoError(t, segment.Write(1, &msgValue))
 	require.NoError(t, segment.Write(0, &pubkeyValue))
-	require.NoError(t, err)
 
 }
 func TestECDSAInvalidSig(t *testing.T) {
@@ -40,9 +39,9 @@ func TestECDSAInvalidSig(t *testing.T) {
 	pubkeyValue := memory.MemoryValueFromFieldElement(pubkey)
 	msgValue := memory.MemoryValueFromFieldElement(msg)
 
-	err := ecdsa.AddSignature(0, *r, *s)
+	require.NoError(t, ecdsa.AddSignature(0, *r, *s))
 	require.NoError(t, segment.Write(0, &pubkeyValue))
-	err = segment.Write(1, &msgValue)
+	err := segment.Write(1, &msgValue)
 	require.ErrorContains(t, err, "Signature is not valid")
 
 }

From 3eea289017226de949040500558da1428297ff01 Mon Sep 17 00:00:00 2001
From: jmjac <jakub@jackowiak.dev>
Date: Thu, 9 Nov 2023 09:54:52 -0500
Subject: [PATCH 12/16] Add comments

---
 pkg/vm/builtins/ecdsa.go | 33 +++++++++++++++++++++++++++++----
 1 file changed, 29 insertions(+), 4 deletions(-)

diff --git a/pkg/vm/builtins/ecdsa.go b/pkg/vm/builtins/ecdsa.go
index dc3d852d5..a0843d047 100644
--- a/pkg/vm/builtins/ecdsa.go
+++ b/pkg/vm/builtins/ecdsa.go
@@ -26,7 +26,7 @@ func (e *ECDSA) CheckWrite(segment *memory.Segment, offset uint64, value *memory
 
 	pub := segment.Peek(pubOffset)
 	if !pub.Known() {
-		//Not sure if this is the right approach. It seems the msg and pub key  can be passed in either order
+		//Not sure if this is the right approach. It seems the msg and pub key  can be passed in either order.
 		return nil
 		//return fmt.Errorf("cannot infer value: input value at offset %d is unknown", pubOffset)
 	}
@@ -82,9 +82,7 @@ func (e *ECDSA) CheckWrite(segment *memory.Segment, offset uint64, value *memory
 			return fmt.Errorf("Signature is not valid")
 		}
 	}
-	//TODO: Get r, s, pub and hash
 	fmt.Println("VALID")
-
 	return nil
 }
 
@@ -92,7 +90,34 @@ func (e *ECDSA) InferValue(segment *memory.Segment, offset uint64) error {
 	return fmt.Errorf("Can't infer value")
 }
 
-// "code": "ecdsa_builtin.add_signature(ids.ecdsa_ptr.address_, (ids.signature_r, ids.signature_s))",
+/*
+Hint that will call this function looks like this:
+
+	"hints": {
+	    "6": [
+	        {
+	            "accessible_scopes": [
+	                "starkware.cairo.common.signature",
+	                "starkware.cairo.common.signature.verify_ecdsa_signature"
+	            ],
+	            "code": "ecdsa_builtin.add_signature(ids.ecdsa_ptr.address_, (ids.signature_r, ids.signature_s))",
+	            "flow_tracking_data": {
+	                "ap_tracking": {
+	                    "group": 2,
+	                    "offset": 0
+	                },
+	                "reference_ids": {
+	                    "starkware.cairo.common.signature.verify_ecdsa_signature.ecdsa_ptr": 4,
+	                    "starkware.cairo.common.signature.verify_ecdsa_signature.message": 0,
+	                    "starkware.cairo.common.signature.verify_ecdsa_signature.public_key": 1,
+	                    "starkware.cairo.common.signature.verify_ecdsa_signature.signature_r": 2,
+	                    "starkware.cairo.common.signature.verify_ecdsa_signature.signature_s": 3
+	                }
+	            }
+	        }
+	    ]
+	},
+*/
 func (e *ECDSA) AddSignature(pubOffset uint64, r, s fp.Element) error {
 	if e.signatures == nil {
 		e.signatures = make(map[uint64]ecdsa.Signature)

From 1ab631d996c3d6fd263c67436137902eaae3db83 Mon Sep 17 00:00:00 2001
From: jmjac <jakub@jackowiak.dev>
Date: Thu, 9 Nov 2023 10:18:58 -0500
Subject: [PATCH 13/16] Fix comments

---
 pkg/vm/builtins/ecdsa.go | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/pkg/vm/builtins/ecdsa.go b/pkg/vm/builtins/ecdsa.go
index a0843d047..9b879e017 100644
--- a/pkg/vm/builtins/ecdsa.go
+++ b/pkg/vm/builtins/ecdsa.go
@@ -16,9 +16,7 @@ type ECDSA struct {
 	signatures map[uint64]ecdsa.Signature
 }
 
-//	verify_ecdsa_signature(message_hash, public_key, sig_r, sig_s)
-//
-// Test with casm ?
+// verify_ecdsa_signature(message_hash, public_key, sig_r, sig_s)
 func (e *ECDSA) CheckWrite(segment *memory.Segment, offset uint64, value *memory.MemoryValue) error {
 	ecdsaIndex := offset % cellsPerECDSA
 	pubOffset := offset - ecdsaIndex
@@ -46,7 +44,7 @@ func (e *ECDSA) CheckWrite(segment *memory.Segment, offset uint64, value *memory
 		return err
 	}
 
-	//Sig verification
+	//Recover Y part of the public key
 	posY, negY, err := recoverY(pubX)
 	if err != nil {
 		return err

From 50225d1f18ffcbc02069fc355a07404ba98cb18b Mon Sep 17 00:00:00 2001
From: jmjac <jakub@jackowiak.dev>
Date: Mon, 13 Nov 2023 00:11:53 -0500
Subject: [PATCH 14/16] Address review

---
 pkg/vm/builtins/ecdsa.go      | 44 +++++++++++++++++------------------
 pkg/vm/builtins/ecdsa_test.go |  6 ++---
 2 files changed, 25 insertions(+), 25 deletions(-)

diff --git a/pkg/vm/builtins/ecdsa.go b/pkg/vm/builtins/ecdsa.go
index 9b879e017..bf66a0179 100644
--- a/pkg/vm/builtins/ecdsa.go
+++ b/pkg/vm/builtins/ecdsa.go
@@ -3,6 +3,7 @@ package builtins
 import (
 	"fmt"
 
+	"github.com/NethermindEth/cairo-vm-go/pkg/utils"
 	"github.com/NethermindEth/cairo-vm-go/pkg/vm/memory"
 	starkcurve "github.com/consensys/gnark-crypto/ecc/stark-curve"
 	ecdsa "github.com/consensys/gnark-crypto/ecc/stark-curve/ecdsa"
@@ -20,7 +21,7 @@ type ECDSA struct {
 func (e *ECDSA) CheckWrite(segment *memory.Segment, offset uint64, value *memory.MemoryValue) error {
 	ecdsaIndex := offset % cellsPerECDSA
 	pubOffset := offset - ecdsaIndex
-	msg_offset := pubOffset + 1
+	msgOffset := pubOffset + 1
 
 	pub := segment.Peek(pubOffset)
 	if !pub.Known() {
@@ -34,7 +35,7 @@ func (e *ECDSA) CheckWrite(segment *memory.Segment, offset uint64, value *memory
 		return err
 	}
 
-	msg := segment.Peek(msg_offset)
+	msg := segment.Peek(msgOffset)
 	if !msg.Known() {
 		return nil
 		//return fmt.Errorf("cannot infer value: input value at offset %d is unknown", msg_offset)
@@ -51,15 +52,15 @@ func (e *ECDSA) CheckWrite(segment *memory.Segment, offset uint64, value *memory
 	}
 
 	//Try first with positive y
-	key := starkcurve.G1Affine{X: *pubX, Y: *posY}
+	key := starkcurve.G1Affine{X: *pubX, Y: posY}
 	if !key.IsOnCurve() {
-		return fmt.Errorf("Key is not on curve")
+		return fmt.Errorf("key is not on curve")
 	}
 
 	pubKey := &ecdsa.PublicKey{A: key}
 	sig, ok := e.signatures[pubOffset]
 	if !ok {
-		return fmt.Errorf("Signature is missing form ECDA builtin")
+		return fmt.Errorf("signature is missing form ECDA builtin")
 	}
 
 	msgBytes := msgField.Bytes()
@@ -70,17 +71,16 @@ func (e *ECDSA) CheckWrite(segment *memory.Segment, offset uint64, value *memory
 
 	if !valid {
 		// Now try with Neg Y. Already know the point is on the curve so no need to check again
-		key = starkcurve.G1Affine{X: *pubX, Y: *negY}
+		key = starkcurve.G1Affine{X: *pubX, Y: negY}
 		pubKey = &ecdsa.PublicKey{A: key}
 		valid, err := pubKey.Verify(sig.Bytes(), msgBytes[:], nil)
 		if err != nil {
 			return err
 		}
 		if !valid {
-			return fmt.Errorf("Signature is not valid")
+			return fmt.Errorf("signature is not valid")
 		}
 	}
-	fmt.Println("VALID")
 	return nil
 }
 
@@ -116,7 +116,7 @@ Hint that will call this function looks like this:
 	    ]
 	},
 */
-func (e *ECDSA) AddSignature(pubOffset uint64, r, s fp.Element) error {
+func (e *ECDSA) AddSignature(pubOffset uint64, r, s *fp.Element) error {
 	if e.signatures == nil {
 		e.signatures = make(map[uint64]ecdsa.Signature)
 	}
@@ -141,20 +141,20 @@ func (e *ECDSA) String() string {
 }
 
 // recoverY recovers the y and -y coordinate of x. True y can be either y or -y
-func recoverY(x *fp.Element) (*fp.Element, *fp.Element, error) {
-	ALPHA := fp.NewElement(1)
-	BETA := fp.Element{}
-	_, _ = BETA.SetString("3141592653589793238462643383279502884197169399375105820974944592307816406665")
+func recoverY(x *fp.Element) (fp.Element, fp.Element, error) {
 	// y_squared = (x * x * x + ALPHA * x + BETA) % FIELD_PRIME
-	x2 := new(fp.Element).Mul(x, x)
-	x3 := x2.Mul(x2, x)
-	a := new(fp.Element).Mul(&ALPHA, x)
-	x3.Add(x3, a)
-	x3.Add(x3, &BETA)
-	y := x3.Sqrt(x3)
+	ax := &fp.Element{}
+	ax.Mul(&utils.Alpha, x)
+	x2 := &fp.Element{}
+	x2.Mul(x, x)
+	x2.Mul(x2, x)
+	x2.Add(x2, ax)
+	x2.Add(x2, &utils.Beta)
+	y := x2.Sqrt(x2)
 	if y == nil {
-		return nil, nil, fmt.Errorf("Invalid Public key")
+		return fp.Element{}, fp.Element{}, fmt.Errorf("Invalid Public key")
 	}
-	//TODO: Figure out if we need to check both
-	return y, new(fp.Element).Neg(y), nil
+	negY := fp.Element{}
+	negY.Neg(y)
+	return *y, negY, nil
 }
diff --git a/pkg/vm/builtins/ecdsa_test.go b/pkg/vm/builtins/ecdsa_test.go
index 5549c63d7..21eff949f 100644
--- a/pkg/vm/builtins/ecdsa_test.go
+++ b/pkg/vm/builtins/ecdsa_test.go
@@ -21,7 +21,7 @@ func TestECDSA(t *testing.T) {
 	pubkeyValue := memory.MemoryValueFromFieldElement(pubkey)
 	msgValue := memory.MemoryValueFromFieldElement(msg)
 
-	require.NoError(t, ecdsa.AddSignature(0, *r, *s))
+	require.NoError(t, ecdsa.AddSignature(0, r, s))
 	require.NoError(t, segment.Write(1, &msgValue))
 	require.NoError(t, segment.Write(0, &pubkeyValue))
 
@@ -39,9 +39,9 @@ func TestECDSAInvalidSig(t *testing.T) {
 	pubkeyValue := memory.MemoryValueFromFieldElement(pubkey)
 	msgValue := memory.MemoryValueFromFieldElement(msg)
 
-	require.NoError(t, ecdsa.AddSignature(0, *r, *s))
+	require.NoError(t, ecdsa.AddSignature(0, r, s))
 	require.NoError(t, segment.Write(0, &pubkeyValue))
 	err := segment.Write(1, &msgValue)
-	require.ErrorContains(t, err, "Signature is not valid")
+	require.ErrorContains(t, err, "signature is not valid")
 
 }

From 117e670577b450222ad846d1e28e307c471894c0 Mon Sep 17 00:00:00 2001
From: jmjac <jakub@jackowiak.dev>
Date: Mon, 13 Nov 2023 00:18:10 -0500
Subject: [PATCH 15/16] Check if pub and msg are known together

---
 pkg/vm/builtins/ecdsa.go | 12 ++++--------
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/pkg/vm/builtins/ecdsa.go b/pkg/vm/builtins/ecdsa.go
index bf66a0179..ed9ffd0fb 100644
--- a/pkg/vm/builtins/ecdsa.go
+++ b/pkg/vm/builtins/ecdsa.go
@@ -24,10 +24,11 @@ func (e *ECDSA) CheckWrite(segment *memory.Segment, offset uint64, value *memory
 	msgOffset := pubOffset + 1
 
 	pub := segment.Peek(pubOffset)
-	if !pub.Known() {
-		//Not sure if this is the right approach. It seems the msg and pub key  can be passed in either order.
+	msg := segment.Peek(msgOffset)
+
+	//Both must be known to check the signature
+	if !msg.Known() || !pub.Known() {
 		return nil
-		//return fmt.Errorf("cannot infer value: input value at offset %d is unknown", pubOffset)
 	}
 
 	pubX, err := pub.FieldElement() //X element of the sig
@@ -35,11 +36,6 @@ func (e *ECDSA) CheckWrite(segment *memory.Segment, offset uint64, value *memory
 		return err
 	}
 
-	msg := segment.Peek(msgOffset)
-	if !msg.Known() {
-		return nil
-		//return fmt.Errorf("cannot infer value: input value at offset %d is unknown", msg_offset)
-	}
 	msgField, err := msg.FieldElement()
 	if err != nil {
 		return err

From a46cd582205ae2a833bab1e2af1ab5d2fe97cfb0 Mon Sep 17 00:00:00 2001
From: jmjac <jakub@jackowiak.dev>
Date: Mon, 13 Nov 2023 08:33:44 -0500
Subject: [PATCH 16/16] Fix case

---
 pkg/vm/builtins/ecdsa.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pkg/vm/builtins/ecdsa.go b/pkg/vm/builtins/ecdsa.go
index ed9ffd0fb..c9dfd100e 100644
--- a/pkg/vm/builtins/ecdsa.go
+++ b/pkg/vm/builtins/ecdsa.go
@@ -81,7 +81,7 @@ func (e *ECDSA) CheckWrite(segment *memory.Segment, offset uint64, value *memory
 }
 
 func (e *ECDSA) InferValue(segment *memory.Segment, offset uint64) error {
-	return fmt.Errorf("Can't infer value")
+	return fmt.Errorf("can't infer value")
 }
 
 /*