diff --git a/docs/reference/go-gno-compatibility.md b/docs/reference/go-gno-compatibility.md index fbc7d10668e..87f4f1105c8 100644 --- a/docs/reference/go-gno-compatibility.md +++ b/docs/reference/go-gno-compatibility.md @@ -124,7 +124,7 @@ Legend: | crypto/dsa | `tbd` | | crypto/ecdh | `tbd` | | crypto/ecdsa | `tbd` | -| crypto/ed25519 | `tbd` | +| crypto/ed25519 | `part`[^8] | | crypto/elliptic | `tbd` | | crypto/hmac | `todo` | | crypto/md5 | `test`[^2] | @@ -289,6 +289,8 @@ Legend: bit of boilerplate, but you can use `sort.Interface` + `sort.Sort`! [^7]: `time.Now` returns the block time rather than the system time, for determinism. Concurrent functionality (such as `time.Ticker`) is not implemented. +[^8]: `crypto/ed25519` is currently only implemented for `Verify`, which should + still cover a majority of use cases. A full implementation is welcome. ## Tooling (`gno` binary) diff --git a/gnovm/stdlibs/crypto/ed25519/ed25519.gno b/gnovm/stdlibs/crypto/ed25519/ed25519.gno new file mode 100644 index 00000000000..80c9d24085b --- /dev/null +++ b/gnovm/stdlibs/crypto/ed25519/ed25519.gno @@ -0,0 +1,8 @@ +package ed25519 + +// Verify returns true if the signature is valid for the message and public key. +func Verify(publicKey []byte, message []byte, signature []byte) bool { + return verify(publicKey, message, signature) +} + +func verify(publicKey []byte, message []byte, signature []byte) bool // injected diff --git a/gnovm/stdlibs/crypto/ed25519/ed25519.go b/gnovm/stdlibs/crypto/ed25519/ed25519.go new file mode 100644 index 00000000000..b19e6870312 --- /dev/null +++ b/gnovm/stdlibs/crypto/ed25519/ed25519.go @@ -0,0 +1,9 @@ +package ed25519 + +import ( + "crypto/ed25519" +) + +func X_verify(publicKey []byte, message []byte, signature []byte) bool { + return ed25519.Verify(publicKey, message, signature) +} diff --git a/gnovm/stdlibs/crypto/ed25519/ed25519_test.gno b/gnovm/stdlibs/crypto/ed25519/ed25519_test.gno new file mode 100644 index 00000000000..419c3bc61a7 --- /dev/null +++ b/gnovm/stdlibs/crypto/ed25519/ed25519_test.gno @@ -0,0 +1,16 @@ +package ed25519 + +import ( + "crypto/ed25519" + "encoding/hex" + "std" + "testing" +) + +func TestVerify(t *testing.T) { + publicKey, _ := hex.DecodeString("0D853FA898A07EB91F618BB3E8B738B0E45BE9B3053799A2C42F8204F5FA3505") + signature, _ := hex.DecodeString("2B39638983858715AD2FA059665ADFE267936B8F20C4DA01E9650958E0CA65C0255C75164360F468087FE8385140E48EE3471E332472A50AEE599F9D0EADD106") + if !ed25519.Verify(publicKey, []byte("hello gno.land"), signature) { + t.Error("verify failed") + } +} diff --git a/gnovm/stdlibs/native.go b/gnovm/stdlibs/native.go index 0cb7d9a7859..0b56eeb7399 100644 --- a/gnovm/stdlibs/native.go +++ b/gnovm/stdlibs/native.go @@ -7,6 +7,7 @@ import ( "reflect" gno "github.com/gnolang/gno/gnovm/pkg/gnolang" + libs_crypto_ed25519 "github.com/gnolang/gno/gnovm/stdlibs/crypto/ed25519" libs_crypto_sha256 "github.com/gnolang/gno/gnovm/stdlibs/crypto/sha256" libs_math "github.com/gnolang/gno/gnovm/stdlibs/math" libs_std "github.com/gnolang/gno/gnovm/stdlibs/std" @@ -24,6 +25,41 @@ type nativeFunc struct { } var nativeFuncs = [...]nativeFunc{ + { + "crypto/ed25519", + "verify", + []gno.FieldTypeExpr{ + {Name: gno.N("p0"), Type: gno.X("[]byte")}, + {Name: gno.N("p1"), Type: gno.X("[]byte")}, + {Name: gno.N("p2"), Type: gno.X("[]byte")}, + }, + []gno.FieldTypeExpr{ + {Name: gno.N("r0"), Type: gno.X("bool")}, + }, + func(m *gno.Machine) { + b := m.LastBlock() + var ( + p0 []byte + rp0 = reflect.ValueOf(&p0).Elem() + p1 []byte + rp1 = reflect.ValueOf(&p1).Elem() + p2 []byte + rp2 = reflect.ValueOf(&p2).Elem() + ) + + gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 0, "")).TV, rp0) + gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 1, "")).TV, rp1) + gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 2, "")).TV, rp2) + + r0 := libs_crypto_ed25519.X_verify(p0, p1, p2) + + m.PushValue(gno.Go2GnoValue( + m.Alloc, + m.Store, + reflect.ValueOf(&r0).Elem(), + )) + }, + }, { "crypto/sha256", "sum256",