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") } /*