From 98dbe0e77c2d5ee7630d56aa9c5fc70d816bd220 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Wed, 26 Jan 2022 14:25:53 +0000 Subject: [PATCH] crypto/ed25519: Switch to curve25519-voi While tendermint v0.35.x has upstreamed the use of curve25519-voi, we may be stuck on v0.34.x for a while longer, and the improvements are worth folding in. --- crypto/batchsig/batchsig.go | 8 +++----- crypto/ed25519/ed25519.go | 22 ++++++++++++++++++++-- crypto/ed25519/oasis_core.go | 26 ++++++++++++++++++++------ go.mod | 2 +- go.sum | 6 +++--- 5 files changed, 47 insertions(+), 17 deletions(-) diff --git a/crypto/batchsig/batchsig.go b/crypto/batchsig/batchsig.go index 33354d94227..18644c75dbd 100644 --- a/crypto/batchsig/batchsig.go +++ b/crypto/batchsig/batchsig.go @@ -5,20 +5,18 @@ package batchsig import ( "fmt" - "github.com/oasisprotocol/ed25519" + "github.com/oasisprotocol/curve25519-voi/primitives/ed25519" "github.com/tendermint/tendermint/crypto" tmEd25519 "github.com/tendermint/tendermint/crypto/ed25519" ) -var defaultOptions ed25519.Options - // VerifyBatch verifies signatures in bulk. Note that this call is only // faster than calling VerifyBytes for each signature iff every signature // is valid. func VerifyBatch(pubKeys []crypto.PubKey, msgs, sigs [][]byte) ([]bool, error) { if len(pubKeys) != len(msgs) || len(msgs) != len(sigs) { - return nil, fmt.Errorf("tendermint/crypto/ed25519: parameter size mismatch") + return nil, fmt.Errorf("tendermint/crypto/batchsig: parameter size mismatch") } // Currently only Ed25519 supports batch verification. @@ -39,7 +37,7 @@ func VerifyBatch(pubKeys []crypto.PubKey, msgs, sigs [][]byte) ([]bool, error) { if tmEd25519.OasisDomainSeparationEnabled() { validSigs, err = tmEd25519.OasisVerifyBatchContext(nativePubKeys, msgs, sigs) } else { - _, validSigs, err = ed25519.VerifyBatch(nil, nativePubKeys, msgs, sigs, &defaultOptions) + validSigs, err = tmEd25519.VerifyBatch(nativePubKeys, msgs, sigs) } return validSigs, err } diff --git a/crypto/ed25519/ed25519.go b/crypto/ed25519/ed25519.go index 11c2989f9e1..d9c2d7ced1d 100644 --- a/crypto/ed25519/ed25519.go +++ b/crypto/ed25519/ed25519.go @@ -5,7 +5,7 @@ import ( "crypto/subtle" "io" - "github.com/oasisprotocol/ed25519" + "github.com/oasisprotocol/curve25519-voi/primitives/ed25519" "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/tmhash" @@ -155,7 +155,7 @@ func (pubKey PubKey) VerifySignature(msg []byte, sig []byte) bool { if oasisDomainSeparatorEnabled { return oasisVerifyBytesContext(pubKey, msg, sig) } - return ed25519.Verify(ed25519.PublicKey(pubKey), msg, sig) + return CachingVerifier.VerifyWithOptions(ed25519.PublicKey(pubKey), msg, sig, verifyOptionsOasis) } func (pubKey PubKey) Type() string { @@ -169,3 +169,21 @@ func (pubKey PubKey) Equals(other crypto.PubKey) bool { return false } + +func VerifyBatch(pubKeys []ed25519.PublicKey, msgs, sigs [][]byte) ([]bool, error) { + batchVerifier := ed25519.NewBatchVerifierWithCapacity(len(msgs)) + + for i := range pubKeys { + CachingVerifier.AddWithOptions( + batchVerifier, + pubKeys[i], + msgs[i], + sigs[i], + verifyOptionsOasis, + ) + } + + _, validSigs := batchVerifier.Verify(nil) + + return validSigs, nil +} diff --git a/crypto/ed25519/oasis_core.go b/crypto/ed25519/oasis_core.go index 84c4fcabcff..85f8458792b 100644 --- a/crypto/ed25519/oasis_core.go +++ b/crypto/ed25519/oasis_core.go @@ -3,7 +3,8 @@ package ed25519 import ( "crypto/sha512" - "github.com/oasisprotocol/ed25519" + "github.com/oasisprotocol/curve25519-voi/primitives/ed25519" + "github.com/oasisprotocol/curve25519-voi/primitives/ed25519/extra/cache" ) // This file adds the helpers for forcing Tendermint to use oasis-core's @@ -23,7 +24,22 @@ var ( oasisDomainSeparator string oasisDomainSeparatorEnabled bool - defaultOptions ed25519.Options + // Oasis Protocol uses a very specific definition of Ed25519pure that + // is slightly different from everyone else. + verifyOptionsOasis = &ed25519.Options{ + Verify: &ed25519.VerifyOptions{ + AllowSmallOrderA: false, + AllowSmallOrderR: false, + AllowNonCanonicalA: true, + AllowNonCanonicalR: true, + }, + } + + // CachingVerifier stores the decompressed public keys to accelerate + // repeated signature verification with the same public keys. + CachingVerifier = cache.NewVerifier( + cache.NewLRUCache(4096), // Should be big enough? + ) ) // EnableOasisDomainSeparation enables oasis-core's ad-hoc domain-separated @@ -49,7 +65,7 @@ func oasisSignContext(privKey PrivKey, msg []byte) ([]byte, error) { func oasisVerifyBytesContext(pubKey PubKey, msg, sig []byte) bool { prehash := oasisDomainSeparationPrehash(msg) - return ed25519.Verify(ed25519.PublicKey(pubKey), prehash, sig) + return CachingVerifier.VerifyWithOptions(ed25519.PublicKey(pubKey), prehash, sig, verifyOptionsOasis) } func OasisVerifyBatchContext(nativePubKeys []ed25519.PublicKey, msgs, sigs [][]byte) ([]bool, error) { @@ -57,9 +73,7 @@ func OasisVerifyBatchContext(nativePubKeys []ed25519.PublicKey, msgs, sigs [][]b for _, v := range msgs { prehashes = append(prehashes, oasisDomainSeparationPrehash(v)) } - - _, validSigs, err := ed25519.VerifyBatch(nil, nativePubKeys, prehashes, sigs, &defaultOptions) - return validSigs, err + return VerifyBatch(nativePubKeys, prehashes, sigs) } func oasisDomainSeparationPrehash(message []byte) []byte { diff --git a/go.mod b/go.mod index 4bdcb08877a..cf74c0b98df 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( github.com/lib/pq v1.10.4 github.com/libp2p/go-buffer-pool v0.0.2 github.com/minio/highwayhash v1.0.2 - github.com/oasisprotocol/ed25519 v0.0.0-20210127160119-f7017427c1ea + github.com/oasisprotocol/curve25519-voi v0.0.0-20211219162838-e9a669f65da9 github.com/oasisprotocol/safeopen v0.0.0-20200528085122-e01cfdfc7661 github.com/ory/dockertest v3.3.5+incompatible github.com/pkg/errors v0.9.1 diff --git a/go.sum b/go.sum index 960581c3351..313b1095026 100644 --- a/go.sum +++ b/go.sum @@ -480,8 +480,8 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLA github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/oasisprotocol/ed25519 v0.0.0-20210127160119-f7017427c1ea h1:r4MhxgqQ1bed0fQhRINBM50Rbwsgma6oEjG4zQ444Lw= -github.com/oasisprotocol/ed25519 v0.0.0-20210127160119-f7017427c1ea/go.mod h1:IZbb50w3AB72BVobEF6qG93NNSrTw/V2QlboxqSu3Xw= +github.com/oasisprotocol/curve25519-voi v0.0.0-20211219162838-e9a669f65da9 h1:7PEzI9zayQvzHKpF2HRGlLnhs6RFNnbMAnolyyVevug= +github.com/oasisprotocol/curve25519-voi v0.0.0-20211219162838-e9a669f65da9/go.mod h1:WUcXjUd98qaCVFb6j8Xc87MsKeMCXDu9Nk8JRJ9SeC8= github.com/oasisprotocol/safeopen v0.0.0-20200528085122-e01cfdfc7661 h1:MB73kGMtuMGS+6VDoU/mitzff7Cu+aZo9ta5wabuxVA= github.com/oasisprotocol/safeopen v0.0.0-20200528085122-e01cfdfc7661/go.mod h1:SwBxaVibf6Sr2IZ6M3WnUue0yp8dPLAo1riQRNQ60+g= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= @@ -690,7 +690,6 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191119213627-4f8c1d86b1ba/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -698,6 +697,7 @@ golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210813211128-0a44fdfbc16e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210915214749-c084706c2272 h1:3erb+vDS8lU1sxfDHF4/hhWyaXnhIaO+7RgL4fDZORA= golang.org/x/crypto v0.0.0-20210915214749-c084706c2272/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=