From 2f76eaa8fe443c30d3eb9e2a9ad1fbe8763ab8da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Mur=C3=A9?= Date: Wed, 30 Jul 2025 18:32:14 +0200 Subject: [PATCH] crypto: integrate varsig --- .github/workflows/gotest.yml | 2 +- crypto/_testsuite/testsuite.go | 45 ++++++ crypto/ed25519/private.go | 18 ++- crypto/ed25519/public.go | 17 ++- crypto/hash.go | 143 +++++++++++++----- crypto/options.go | 70 ++++++++- crypto/p256/private.go | 8 + crypto/p256/public.go | 6 + crypto/p384/private.go | 8 + crypto/p384/public.go | 6 + crypto/p521/private.go | 8 + crypto/p521/public.go | 6 + crypto/{interface.go => private.go} | 50 +----- crypto/public.go | 41 +++++ crypto/rsa/private.go | 16 +- crypto/rsa/public.go | 10 +- crypto/secp256k1/private.go | 7 + crypto/secp256k1/public.go | 9 ++ did_test.go | 2 +- go.mod | 9 +- go.sum | 10 +- interfaces.go | 7 +- utilities.go | 18 ++- .../_methods/ed25519/VerificationKey2018.go | 9 +- .../_methods/ed25519/VerificationKey2020.go | 9 +- .../_methods/jsonwebkey/JsonWebKey2020.go | 11 +- verifiers/_methods/multikey/multikey.go | 11 +- verifiers/_methods/p256/key2021.go | 8 +- .../_methods/secp256k1/VerificationKey2019.go | 8 +- verifiers/did-key/key_test.go | 2 +- 30 files changed, 451 insertions(+), 123 deletions(-) rename crypto/{interface.go => private.go} (53%) create mode 100644 crypto/public.go diff --git a/.github/workflows/gotest.yml b/.github/workflows/gotest.yml index bbfee95..3288dce 100644 --- a/.github/workflows/gotest.yml +++ b/.github/workflows/gotest.yml @@ -24,4 +24,4 @@ jobs: - name: Run tests run: go test -v ./... - name: Check formatted - run: gofmt -l . \ No newline at end of file + run: gofmt -l . diff --git a/crypto/_testsuite/testsuite.go b/crypto/_testsuite/testsuite.go index 9f6e350..7988842 100644 --- a/crypto/_testsuite/testsuite.go +++ b/crypto/_testsuite/testsuite.go @@ -9,6 +9,7 @@ import ( mbase "github.com/multiformats/go-multibase" "github.com/multiformats/go-varint" "github.com/stretchr/testify/require" + "github.com/ucan-wg/go-varsig" "github.com/MetaMask/go-did-it/crypto" ) @@ -194,6 +195,7 @@ func TestSuite[PubT crypto.PublicKey, PrivT crypto.PrivateKey](t *testing.T, har name string signer func(msg []byte, opts ...crypto.SigningOption) ([]byte, error) verifier func(msg []byte, sig []byte, opts ...crypto.SigningOption) bool + varsig func(opts ...crypto.SigningOption) varsig.Varsig expectedSize int stats *int defaultHash crypto.Hash @@ -210,6 +212,7 @@ func TestSuite[PubT crypto.PublicKey, PrivT crypto.PrivateKey](t *testing.T, har name: "Bytes signature", signer: spriv.SignToBytes, verifier: spub.VerifyBytes, + varsig: spriv.Varsig, expectedSize: harness.SignatureBytesSize, stats: &stats.sigRawSize, defaultHash: harness.DefaultHash, @@ -227,6 +230,7 @@ func TestSuite[PubT crypto.PublicKey, PrivT crypto.PrivateKey](t *testing.T, har name: "ASN.1 signature", signer: spriv.SignToASN1, verifier: spub.VerifyASN1, + varsig: spriv.Varsig, stats: &stats.sigAsn1Size, defaultHash: harness.DefaultHash, otherHashes: harness.OtherHashes, @@ -245,6 +249,9 @@ func TestSuite[PubT crypto.PublicKey, PrivT crypto.PrivateKey](t *testing.T, har sigDefault, err := tc.signer(msg, crypto.WithSigningHash(tc.defaultHash)) require.NoError(t, err) + vsig := tc.varsig() + require.Equal(t, harness.DefaultHash.ToVarsigHash(), vsig.Hash()) + if tc.expectedSize > 0 { require.Equal(t, tc.expectedSize, len(sigNoParams)) } @@ -253,13 +260,21 @@ func TestSuite[PubT crypto.PublicKey, PrivT crypto.PrivateKey](t *testing.T, har // signatures might be different (i.e. non-deterministic), but they should verify the same way valid := tc.verifier(msg, sigNoParams) require.True(t, valid) + valid = tc.verifier(msg, sigNoParams, crypto.WithVarsig(vsig)) + require.True(t, valid) valid = tc.verifier(msg, sigDefault) require.True(t, valid) + valid = tc.verifier(msg, sigDefault, crypto.WithVarsig(vsig)) + require.True(t, valid) valid = tc.verifier([]byte("wrong message"), sigNoParams) require.False(t, valid) + valid = tc.verifier([]byte("wrong message"), sigNoParams, crypto.WithVarsig(vsig)) + require.False(t, valid) valid = tc.verifier([]byte("wrong message"), sigDefault) require.False(t, valid) + valid = tc.verifier([]byte("wrong message"), sigDefault, crypto.WithVarsig(vsig)) + require.False(t, valid) }) for _, hash := range tc.otherHashes { t.Run(fmt.Sprintf("%s-%s", tc.name, hash.String()), func(t *testing.T) { @@ -269,11 +284,18 @@ func TestSuite[PubT crypto.PublicKey, PrivT crypto.PrivateKey](t *testing.T, har require.NoError(t, err) require.NotEmpty(t, sig) + vsig := tc.varsig(crypto.WithSigningHash(hash)) + require.Equal(t, hash.ToVarsigHash(), vsig.Hash()) + valid := tc.verifier(msg, sig, crypto.WithSigningHash(hash)) require.True(t, valid) + valid = tc.verifier(msg, sig, crypto.WithVarsig(vsig)) + require.True(t, valid) valid = tc.verifier([]byte("wrong message"), sig) require.False(t, valid) + valid = tc.verifier([]byte("wrong message"), sig, crypto.WithVarsig(vsig)) + require.False(t, valid) }) } } @@ -503,6 +525,29 @@ func BenchSuite[PubT crypto.PublicKey, PrivT crypto.PrivateKey](b *testing.B, ha } }) + b.Run("Verify from varsig signature", func(b *testing.B) { + if !pubImplements[PubT, crypto.PublicKeySigningBytes]() { + b.Skip("Signature to bytes is not implemented") + } + + pub, priv, err := harness.GenerateKeyPair() + require.NoError(b, err) + + spub := (crypto.PublicKey(pub)).(crypto.PublicKeySigningBytes) + spriv := (crypto.PrivateKey(priv)).(crypto.PrivateKeySigningBytes) + + sig, err := spriv.SignToBytes([]byte("message")) + require.NoError(b, err) + vsig := spriv.Varsig() + + b.ResetTimer() + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + spub.VerifyBytes([]byte("message"), sig, crypto.WithVarsig(vsig)) + } + }) + b.Run("Sign to ASN.1 signature", func(b *testing.B) { if !pubImplements[PubT, crypto.PublicKeySigningASN1]() { b.Skip("Signature to ASN.1 is not implemented") diff --git a/crypto/ed25519/private.go b/crypto/ed25519/private.go index efc1aba..4d909e4 100644 --- a/crypto/ed25519/private.go +++ b/crypto/ed25519/private.go @@ -6,6 +6,7 @@ import ( "encoding/pem" "fmt" + "github.com/ucan-wg/go-varsig" "golang.org/x/crypto/cryptobyte" "github.com/MetaMask/go-did-it/crypto" @@ -21,7 +22,7 @@ type PrivateKey struct { // PrivateKeyFromBytes converts a serialized private key to a PrivateKey. // This compact serialization format is the raw key material, without metadata or structure. -// It errors if the slice is not the right size. +// It returns an error if the slice is not the right size. func PrivateKeyFromBytes(b []byte) (PrivateKey, error) { if len(b) != PrivateKeyBytesSize { return PrivateKey{}, fmt.Errorf("invalid ed25519 private key size") @@ -73,11 +74,19 @@ func (p PrivateKey) Public() crypto.PublicKey { return PublicKey{k: p.k.Public().(ed25519.PublicKey)} } +func (p PrivateKey) Varsig(opts ...crypto.SigningOption) varsig.Varsig { + params := crypto.CollectSigningOptions(opts) + return varsig.NewEdDSAVarsig(varsig.CurveEd25519, params.HashOrDefault(crypto.SHA512).ToVarsigHash(), params.PayloadEncoding()) +} + func (p PrivateKey) SignToBytes(message []byte, opts ...crypto.SigningOption) ([]byte, error) { params := crypto.CollectSigningOptions(opts) - if params.Hash != crypto.Hash(0) && params.Hash != crypto.SHA512 { + + hash := params.HashOrDefault(crypto.SHA512) + if hash != crypto.SHA512 { return nil, fmt.Errorf("ed25519 does not support custom hash functions") } + return ed25519.Sign(p.k, message), nil } @@ -85,9 +94,12 @@ func (p PrivateKey) SignToBytes(message []byte, opts ...crypto.SigningOption) ([ // This ASN.1 encoding uses a BIT STRING, which would be correct for an X.509 certificate. func (p PrivateKey) SignToASN1(message []byte, opts ...crypto.SigningOption) ([]byte, error) { params := crypto.CollectSigningOptions(opts) - if params.Hash != crypto.Hash(0) && params.Hash != crypto.SHA512 { + + hash := params.HashOrDefault(crypto.SHA512) + if hash != crypto.SHA512 { return nil, fmt.Errorf("ed25519 does not support custom hash functions") } + sig := ed25519.Sign(p.k, message) var b cryptobyte.Builder b.AddASN1BitString(sig) diff --git a/crypto/ed25519/public.go b/crypto/ed25519/public.go index 949066d..06226e2 100644 --- a/crypto/ed25519/public.go +++ b/crypto/ed25519/public.go @@ -7,6 +7,7 @@ import ( "encoding/pem" "fmt" + "github.com/ucan-wg/go-varsig" "golang.org/x/crypto/cryptobyte" "github.com/MetaMask/go-did-it/crypto" @@ -101,10 +102,16 @@ func (p PublicKey) Equal(other crypto.PublicKey) bool { func (p PublicKey) VerifyBytes(message, signature []byte, opts ...crypto.SigningOption) bool { params := crypto.CollectSigningOptions(opts) - if params.Hash != crypto.Hash(0) && params.Hash != crypto.SHA512 { + + if !params.VarsigMatch(varsig.AlgorithmEdDSA, uint64(varsig.CurveEd25519), 0) { + return false + } + + if params.HashOrDefault(crypto.SHA512) != crypto.SHA512 { // ed25519 does not support custom hash functions return false } + return ed25519.Verify(p.k, message, signature) } @@ -112,10 +119,16 @@ func (p PublicKey) VerifyBytes(message, signature []byte, opts ...crypto.Signing // This ASN.1 encoding uses a BIT STRING, which would be correct for an X.509 certificate. func (p PublicKey) VerifyASN1(message, signature []byte, opts ...crypto.SigningOption) bool { params := crypto.CollectSigningOptions(opts) - if params.Hash != crypto.Hash(0) && params.Hash != crypto.SHA512 { + + if !params.VarsigMatch(varsig.AlgorithmEdDSA, uint64(varsig.CurveEd25519), 0) { + return false + } + + if params.HashOrDefault(crypto.SHA512) != crypto.SHA512 { // ed25519 does not support custom hash functions return false } + var s cryptobyte.String = signature var bitString asn1.BitString diff --git a/crypto/hash.go b/crypto/hash.go index f92c769..fbfc274 100644 --- a/crypto/hash.go +++ b/crypto/hash.go @@ -5,41 +5,15 @@ import ( "hash" "strconv" + "github.com/ucan-wg/go-varsig" "golang.org/x/crypto/sha3" ) // As the standard crypto library prohibits from registering additional hash algorithm (like keccak), // below is essentially an extension of that mechanism to allow it. -func init() { - RegisterHash(KECCAK_256, sha3.NewLegacyKeccak256) - RegisterHash(KECCAK_512, sha3.NewLegacyKeccak512) -} - type Hash uint -// HashFunc simply returns the value of h so that [Hash] implements [SignerOpts]. -func (h Hash) HashFunc() Hash { - return h -} - -func (h Hash) String() string { - if h < maxStdHash { - return stdcrypto.Hash(h).String() - } - - // Extensions - switch h { - case KECCAK_256: - return "Keccak-256" - case KECCAK_512: - return "Keccak-512" - - default: - return "unknown hash value " + strconv.Itoa(int(h)) - } -} - const ( // From "crypto" MD4 Hash = 1 + iota // import golang.org/x/crypto/md4 @@ -71,7 +45,20 @@ const ( maxHash ) -var hashes = make([]func() hash.Hash, maxHash-maxStdHash-1) +// HashFunc simply returns the value of h so that [Hash] implements [SignerOpts]. +func (h Hash) HashFunc() Hash { + return h +} + +func (h Hash) String() string { + if h < maxStdHash { + return stdcrypto.Hash(h).String() + } + if h > maxStdHash && h < maxHash { + return hashNames[h-maxStdHash-1] + } + panic("requested hash #" + strconv.Itoa(int(h)) + " is unavailable") +} // New returns a new hash.Hash calculating the given hash function. New panics // if the hash function is not linked into the binary. @@ -80,23 +67,101 @@ func (h Hash) New() hash.Hash { return stdcrypto.Hash(h).New() } if h > maxStdHash && h < maxHash { - f := hashes[h-maxStdHash-1] + f := hashFns[h-maxStdHash-1] if f != nil { return f() } } - panic("crypto: requested hash function #" + strconv.Itoa(int(h)) + " is unavailable") + panic("requested hash function #" + strconv.Itoa(int(h)) + " is unavailable") } -// RegisterHash registers a function that returns a new instance of the given -// hash function. This is intended to be called from the init function in -// packages that implement hash functions. -func RegisterHash(h Hash, f func() hash.Hash) { - if h >= maxHash { - panic("crypto: RegisterHash of unknown hash function") +func (h Hash) ToVarsigHash() varsig.Hash { + if h == MD5SHA1 { + panic("no multihash/multicodec value exists for MD5+SHA1") } - if h <= maxStdHash { - panic("crypto: RegisterHash of standard hash function") + if h < maxHash { + return hashVarsigs[h] } - hashes[h-maxStdHash-1] = f + panic("requested hash #" + strconv.Itoa(int(h)) + " is unavailable") +} + +func FromVarsigHash(h varsig.Hash) Hash { + switch h { + case varsig.HashMd4: + return MD4 + case varsig.HashMd5: + return MD5 + case varsig.HashSha1: + return SHA1 + case varsig.HashSha2_224: + return SHA224 + case varsig.HashSha2_256: + return SHA256 + case varsig.HashSha2_384: + return SHA384 + case varsig.HashSha2_512: + return SHA512 + case varsig.HashRipemd_160: + return RIPEMD160 + case varsig.HashSha3_224: + return SHA3_224 + case varsig.HashSha3_256: + return SHA3_256 + case varsig.HashSha3_384: + return SHA3_384 + case varsig.HashSha3_512: + return SHA3_512 + case varsig.HashSha512_224: + return SHA512_224 + case varsig.HashSha512_256: + return SHA512_256 + case varsig.HashBlake2s_256: + return BLAKE2s_256 + case varsig.HashBlake2b_256: + return BLAKE2b_256 + case varsig.HashBlake2b_384: + return BLAKE2b_384 + case varsig.HashBlake2b_512: + return BLAKE2b_512 + case varsig.HashKeccak_256: + return KECCAK_256 + case varsig.HashKeccak_512: + return KECCAK_512 + default: + panic("varsig " + strconv.Itoa(int(h)) + " is not supported") + } +} + +var hashNames = []string{ + "Keccak-256", + "Keccak-512", +} +var hashFns = []func() hash.Hash{ + sha3.NewLegacyKeccak256, + sha3.NewLegacyKeccak512, +} +var hashVarsigs = []varsig.Hash{ + 0, // undef + varsig.HashMd4, + varsig.HashMd5, + varsig.HashSha1, + varsig.HashSha2_224, + varsig.HashSha2_256, + varsig.HashSha2_384, + varsig.HashSha2_512, + 0, // missing MD5SHA1 + varsig.HashRipemd_160, + varsig.HashSha3_224, + varsig.HashSha3_256, + varsig.HashSha3_384, + varsig.HashSha3_512, + varsig.HashSha512_224, + varsig.HashSha512_256, + varsig.HashBlake2s_256, + varsig.HashBlake2b_256, + varsig.HashBlake2b_384, + varsig.HashBlake2b_512, + 0, // maxStdHash + varsig.HashKeccak_256, + varsig.HashKeccak_512, } diff --git a/crypto/options.go b/crypto/options.go index c24ab67..b7cda87 100644 --- a/crypto/options.go +++ b/crypto/options.go @@ -1,7 +1,17 @@ package crypto +import ( + "github.com/ucan-wg/go-varsig" +) + type SigningOpts struct { - Hash Hash + hash Hash + payloadEncoding varsig.PayloadEncoding + + // if WithVarsig is used + algo varsig.Algorithm + curve uint64 + keyLen uint64 } func CollectSigningOptions(opts []SigningOption) SigningOpts { @@ -13,10 +23,34 @@ func CollectSigningOptions(opts []SigningOption) SigningOpts { } func (opts SigningOpts) HashOrDefault(_default Hash) Hash { - if opts.Hash == 0 { + if opts.hash == 0 { return _default } - return opts.Hash + return opts.hash +} + +func (opts SigningOpts) PayloadEncoding() varsig.PayloadEncoding { + if opts.payloadEncoding == 0 { + return varsig.PayloadEncodingVerbatim + } + return opts.payloadEncoding +} + +func (opts SigningOpts) VarsigMatch(algo varsig.Algorithm, curve uint64, keyLength uint64) bool { + // This is relatively ugly, but we get cyclic import otherwise + switch opts.algo { + case 0: + // not varsig to compare + return true + case varsig.AlgorithmECDSA: + return algo == varsig.AlgorithmECDSA && opts.curve == curve + case varsig.AlgorithmEdDSA: + return algo == varsig.AlgorithmEdDSA && opts.curve == curve + case varsig.AlgorithmRSA: + return algo == varsig.AlgorithmRSA && opts.keyLen == keyLength + default: + panic("unreachable") + } } type SigningOption func(opts *SigningOpts) @@ -24,6 +58,34 @@ type SigningOption func(opts *SigningOpts) // WithSigningHash specify the hash algorithm to be used for signatures func WithSigningHash(hash Hash) SigningOption { return func(opts *SigningOpts) { - opts.Hash = hash + opts.hash = hash + } +} + +// WithPayloadEncoding specify the encoding that was used on the message before signing it. +// This will be included in the resulting varsig. +func WithPayloadEncoding(encoding varsig.PayloadEncoding) SigningOption { + return func(opts *SigningOpts) { + opts.payloadEncoding = encoding + } +} + +// WithVarsig configure the signing or verification parameters from a varsig. +// If you use WithVarsig, you should NOT use other options. +func WithVarsig(vsig varsig.Varsig) SigningOption { + return func(opts *SigningOpts) { + opts.payloadEncoding = vsig.PayloadEncoding() + opts.hash = FromVarsigHash(vsig.Hash()) + opts.algo = vsig.Algorithm() + switch vsig := vsig.(type) { + case varsig.EdDSAVarsig: + opts.curve = uint64(vsig.Curve()) + case varsig.ECDSAVarsig: + opts.curve = uint64(vsig.Curve()) + case varsig.RSAVarsig: + opts.keyLen = vsig.KeyLength() + default: + panic("unreachable") + } } } diff --git a/crypto/p256/private.go b/crypto/p256/private.go index 245b69b..21b7268 100644 --- a/crypto/p256/private.go +++ b/crypto/p256/private.go @@ -9,6 +9,8 @@ import ( "fmt" "math/big" + "github.com/ucan-wg/go-varsig" + "github.com/MetaMask/go-did-it/crypto" ) @@ -99,6 +101,12 @@ func (p *PrivateKey) ToPKCS8PEM() string { })) } +// The default signing hash is SHA-256. +func (p *PrivateKey) Varsig(opts ...crypto.SigningOption) varsig.Varsig { + params := crypto.CollectSigningOptions(opts) + return varsig.NewECDSAVarsig(varsig.CurveP256, params.HashOrDefault(crypto.SHA256).ToVarsigHash(), params.PayloadEncoding()) +} + // The default signing hash is SHA-256. func (p *PrivateKey) SignToBytes(message []byte, opts ...crypto.SigningOption) ([]byte, error) { params := crypto.CollectSigningOptions(opts) diff --git a/crypto/p256/public.go b/crypto/p256/public.go index 902dd93..5cbfe91 100644 --- a/crypto/p256/public.go +++ b/crypto/p256/public.go @@ -8,6 +8,8 @@ import ( "fmt" "math/big" + "github.com/ucan-wg/go-varsig" + "github.com/MetaMask/go-did-it/crypto" helpers "github.com/MetaMask/go-did-it/crypto/internal" ) @@ -148,6 +150,10 @@ func (p *PublicKey) VerifyBytes(message, signature []byte, opts ...crypto.Signin func (p *PublicKey) VerifyASN1(message, signature []byte, opts ...crypto.SigningOption) bool { params := crypto.CollectSigningOptions(opts) + if !params.VarsigMatch(varsig.AlgorithmECDSA, uint64(varsig.CurveP256), 0) { + return false + } + hasher := params.HashOrDefault(crypto.SHA256).New() hasher.Write(message) hash := hasher.Sum(nil) diff --git a/crypto/p384/private.go b/crypto/p384/private.go index 73346cb..b2c5ba6 100644 --- a/crypto/p384/private.go +++ b/crypto/p384/private.go @@ -9,6 +9,8 @@ import ( "fmt" "math/big" + "github.com/ucan-wg/go-varsig" + "github.com/MetaMask/go-did-it/crypto" ) @@ -99,6 +101,12 @@ func (p *PrivateKey) ToPKCS8PEM() string { })) } +// The default signing hash is SHA-384. +func (p *PrivateKey) Varsig(opts ...crypto.SigningOption) varsig.Varsig { + params := crypto.CollectSigningOptions(opts) + return varsig.NewECDSAVarsig(varsig.CurveP384, params.HashOrDefault(crypto.SHA384).ToVarsigHash(), params.PayloadEncoding()) +} + // The default signing hash is SHA-384. func (p *PrivateKey) SignToBytes(message []byte, opts ...crypto.SigningOption) ([]byte, error) { params := crypto.CollectSigningOptions(opts) diff --git a/crypto/p384/public.go b/crypto/p384/public.go index c318659..168dbce 100644 --- a/crypto/p384/public.go +++ b/crypto/p384/public.go @@ -8,6 +8,8 @@ import ( "fmt" "math/big" + "github.com/ucan-wg/go-varsig" + "github.com/MetaMask/go-did-it/crypto" helpers "github.com/MetaMask/go-did-it/crypto/internal" ) @@ -148,6 +150,10 @@ func (p *PublicKey) VerifyBytes(message, signature []byte, opts ...crypto.Signin func (p *PublicKey) VerifyASN1(message, signature []byte, opts ...crypto.SigningOption) bool { params := crypto.CollectSigningOptions(opts) + if !params.VarsigMatch(varsig.AlgorithmECDSA, uint64(varsig.CurveP384), 0) { + return false + } + hasher := params.HashOrDefault(crypto.SHA384).New() hasher.Write(message) hash := hasher.Sum(nil) diff --git a/crypto/p521/private.go b/crypto/p521/private.go index bcc1e29..2a8dc19 100644 --- a/crypto/p521/private.go +++ b/crypto/p521/private.go @@ -9,6 +9,8 @@ import ( "fmt" "math/big" + "github.com/ucan-wg/go-varsig" + "github.com/MetaMask/go-did-it/crypto" ) @@ -99,6 +101,12 @@ func (p *PrivateKey) ToPKCS8PEM() string { })) } +// The default signing hash is SHA-512. +func (p *PrivateKey) Varsig(opts ...crypto.SigningOption) varsig.Varsig { + params := crypto.CollectSigningOptions(opts) + return varsig.NewECDSAVarsig(varsig.CurveP521, params.HashOrDefault(crypto.SHA512).ToVarsigHash(), params.PayloadEncoding()) +} + // The default signing hash is SHA-512. func (p *PrivateKey) SignToBytes(message []byte, opts ...crypto.SigningOption) ([]byte, error) { params := crypto.CollectSigningOptions(opts) diff --git a/crypto/p521/public.go b/crypto/p521/public.go index 3ebb6a9..dc94d91 100644 --- a/crypto/p521/public.go +++ b/crypto/p521/public.go @@ -8,6 +8,8 @@ import ( "fmt" "math/big" + "github.com/ucan-wg/go-varsig" + "github.com/MetaMask/go-did-it/crypto" helpers "github.com/MetaMask/go-did-it/crypto/internal" ) @@ -148,6 +150,10 @@ func (p *PublicKey) VerifyBytes(message, signature []byte, opts ...crypto.Signin func (p *PublicKey) VerifyASN1(message, signature []byte, opts ...crypto.SigningOption) bool { params := crypto.CollectSigningOptions(opts) + if !params.VarsigMatch(varsig.AlgorithmECDSA, uint64(varsig.CurveP521), 0) { + return false + } + hasher := params.HashOrDefault(crypto.SHA512).New() hasher.Write(message) hash := hasher.Sum(nil) diff --git a/crypto/interface.go b/crypto/private.go similarity index 53% rename from crypto/interface.go rename to crypto/private.go index 43b0809..22a48ef 100644 --- a/crypto/interface.go +++ b/crypto/private.go @@ -1,48 +1,6 @@ package crypto -// Public Key - -type PublicKey interface { - // Equal returns true if other is the same PublicKey - Equal(other PublicKey) bool - - // ToPublicKeyMultibase format the PublicKey into a string compatible with a PublicKeyMultibase field - // in a DID Document. - ToPublicKeyMultibase() string - - // ToX509DER serializes the PublicKey into the X.509 DER (binary) format. - ToX509DER() []byte - - // ToX509PEM serializes the PublicKey into the X.509 PEM (string) format. - ToX509PEM() string -} - -type PublicKeyToBytes interface { - PublicKey - - // ToBytes serializes the PublicKey into "raw bytes", without metadata or structure. - // This format can make some assumptions and may not be what you expect. - // Ideally, this format is defined by the same specification as the underlying crypto scheme. - ToBytes() []byte -} - -type PublicKeySigningBytes interface { - PublicKey - - // VerifyBytes checks a signature in the "raw bytes" format. - // This format can make some assumptions and may not be what you expect. - // Ideally, this format is defined by the same specification as the underlying crypto scheme. - VerifyBytes(message, signature []byte, opts ...SigningOption) bool -} - -type PublicKeySigningASN1 interface { - PublicKey - - // VerifyASN1 checks a signature in the ASN.1 format. - VerifyASN1(message, signature []byte, opts ...SigningOption) bool -} - -// Private Key +import "github.com/ucan-wg/go-varsig" type PrivateKey interface { // Equal returns true if other is the same PrivateKey @@ -70,6 +28,9 @@ type PrivateKeyToBytes interface { type PrivateKeySigningBytes interface { PrivateKey + // Varsig returns the varsig.Varsig corresponding to the given parameters and private key. + Varsig(opts ...SigningOption) varsig.Varsig + // SignToBytes creates a signature in the "raw bytes" format. // This format can make some assumptions and may not be what you expect. // Ideally, this format is defined by the same specification as the underlying crypto scheme. @@ -79,6 +40,9 @@ type PrivateKeySigningBytes interface { type PrivateKeySigningASN1 interface { PrivateKey + // Varsig returns the varsig.Varsig corresponding to the given parameters and private key. + Varsig(opts ...SigningOption) varsig.Varsig + // SignToASN1 creates a signature in the ASN.1 format. SignToASN1(message []byte, opts ...SigningOption) ([]byte, error) } diff --git a/crypto/public.go b/crypto/public.go new file mode 100644 index 0000000..a120481 --- /dev/null +++ b/crypto/public.go @@ -0,0 +1,41 @@ +package crypto + +type PublicKey interface { + // Equal returns true if other is the same PublicKey + Equal(other PublicKey) bool + + // ToPublicKeyMultibase format the PublicKey into a string compatible with a PublicKeyMultibase field + // in a DID Document. + ToPublicKeyMultibase() string + + // ToX509DER serializes the PublicKey into the X.509 DER (binary) format. + ToX509DER() []byte + + // ToX509PEM serializes the PublicKey into the X.509 PEM (string) format. + ToX509PEM() string +} + +type PublicKeyToBytes interface { + PublicKey + + // ToBytes serializes the PublicKey into "raw bytes", without metadata or structure. + // This format can make some assumptions and may not be what you expect. + // Ideally, this format is defined by the same specification as the underlying crypto scheme. + ToBytes() []byte +} + +type PublicKeySigningBytes interface { + PublicKey + + // VerifyBytes checks a signature in the "raw bytes" format. + // This format can make some assumptions and may not be what you expect. + // Ideally, this format is defined by the same specification as the underlying crypto scheme. + VerifyBytes(message, signature []byte, opts ...SigningOption) bool +} + +type PublicKeySigningASN1 interface { + PublicKey + + // VerifyASN1 checks a signature in the ASN.1 format. + VerifyASN1(message, signature []byte, opts ...SigningOption) bool +} diff --git a/crypto/rsa/private.go b/crypto/rsa/private.go index a0440e9..014ea41 100644 --- a/crypto/rsa/private.go +++ b/crypto/rsa/private.go @@ -9,6 +9,8 @@ import ( "fmt" "math/big" + "github.com/ucan-wg/go-varsig" + "github.com/MetaMask/go-did-it/crypto" ) @@ -67,8 +69,8 @@ func PrivateKeyFromPKCS8PEM(str string) (*PrivateKey, error) { return PrivateKeyFromPKCS8DER(block.Bytes) } -func (p *PrivateKey) BitLen() int { - return p.k.N.BitLen() +func (p *PrivateKey) KeyLength() uint64 { + return uint64((p.k.N.BitLen() + 7) / 8) // Round up to the nearest byte } func (p *PrivateKey) DBytes() []byte { @@ -147,6 +149,16 @@ func (p *PrivateKey) ToPKCS8PEM() string { })) } +// The default signing hash is: +// - SHA-256 for keys of length 2048 bits and under +// - SHA-384 for keys of length 3072 bits and under +// - SHA-512 for higher key length +func (p *PrivateKey) Varsig(opts ...crypto.SigningOption) varsig.Varsig { + params := crypto.CollectSigningOptions(opts) + hashCode := params.HashOrDefault(defaultSigHash(p.k.N.BitLen())) + return varsig.NewRSAVarsig(hashCode.ToVarsigHash(), uint64(p.KeyLength()), params.PayloadEncoding()) +} + // SignToASN1 produce a PKCS#1 v1.5 signature. // The default signing hash is: // - SHA-256 for keys of length 2048 bits and under diff --git a/crypto/rsa/public.go b/crypto/rsa/public.go index 3d7832d..04ac9b9 100644 --- a/crypto/rsa/public.go +++ b/crypto/rsa/public.go @@ -8,6 +8,8 @@ import ( "fmt" "math/big" + "github.com/ucan-wg/go-varsig" + "github.com/MetaMask/go-did-it/crypto" helpers "github.com/MetaMask/go-did-it/crypto/internal" ) @@ -93,8 +95,8 @@ func PublicKeyFromX509PEM(str string) (*PublicKey, error) { return PublicKeyFromX509DER(block.Bytes) } -func (p *PublicKey) BitLen() int { - return p.k.N.BitLen() +func (p *PublicKey) KeyLength() uint64 { + return uint64((p.k.N.BitLen() + 7) / 8) // Round up to the nearest byte } func (p *PublicKey) NBytes() []byte { @@ -138,6 +140,10 @@ func (p *PublicKey) ToX509PEM() string { func (p *PublicKey) VerifyASN1(message, signature []byte, opts ...crypto.SigningOption) bool { params := crypto.CollectSigningOptions(opts) + if !params.VarsigMatch(varsig.AlgorithmRSA, 0, p.KeyLength()) { + return false + } + hashCode := params.HashOrDefault(defaultSigHash(p.k.N.BitLen())) hasher := hashCode.New() hasher.Write(message) diff --git a/crypto/secp256k1/private.go b/crypto/secp256k1/private.go index 0c172d0..6ce6e8f 100644 --- a/crypto/secp256k1/private.go +++ b/crypto/secp256k1/private.go @@ -8,6 +8,7 @@ import ( "github.com/decred/dcrd/dcrec/secp256k1/v4" "github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa" + "github.com/ucan-wg/go-varsig" "github.com/MetaMask/go-did-it/crypto" ) @@ -172,6 +173,12 @@ func (p *PrivateKey) ToPKCS8PEM() string { })) } +// The default signing hash is SHA-256. +func (p *PrivateKey) Varsig(opts ...crypto.SigningOption) varsig.Varsig { + params := crypto.CollectSigningOptions(opts) + return varsig.NewECDSAVarsig(varsig.CurveSecp256k1, params.HashOrDefault(crypto.SHA256).ToVarsigHash(), params.PayloadEncoding()) +} + // The default signing hash is SHA-256. func (p *PrivateKey) SignToBytes(message []byte, opts ...crypto.SigningOption) ([]byte, error) { params := crypto.CollectSigningOptions(opts) diff --git a/crypto/secp256k1/public.go b/crypto/secp256k1/public.go index f96c2b0..3cfe257 100644 --- a/crypto/secp256k1/public.go +++ b/crypto/secp256k1/public.go @@ -8,6 +8,7 @@ import ( "github.com/decred/dcrd/dcrec/secp256k1/v4" "github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa" + "github.com/ucan-wg/go-varsig" "github.com/MetaMask/go-did-it/crypto" helpers "github.com/MetaMask/go-did-it/crypto/internal" @@ -176,6 +177,10 @@ func (p *PublicKey) VerifyBytes(message, signature []byte, opts ...crypto.Signin params := crypto.CollectSigningOptions(opts) + if !params.VarsigMatch(varsig.AlgorithmECDSA, uint64(varsig.CurveSecp256k1), 0) { + return false + } + hasher := params.HashOrDefault(crypto.SHA256).New() hasher.Write(message) hash := hasher.Sum(nil) @@ -191,6 +196,10 @@ func (p *PublicKey) VerifyBytes(message, signature []byte, opts ...crypto.Signin func (p *PublicKey) VerifyASN1(message, signature []byte, opts ...crypto.SigningOption) bool { params := crypto.CollectSigningOptions(opts) + if !params.VarsigMatch(varsig.AlgorithmECDSA, uint64(varsig.CurveSecp256k1), 0) { + return false + } + hasher := params.HashOrDefault(crypto.SHA256).New() hasher.Write(message) hash := hasher.Sum(nil) diff --git a/did_test.go b/did_test.go index cc23365..e4fa1c1 100644 --- a/did_test.go +++ b/did_test.go @@ -23,7 +23,7 @@ func Example_signature() { // 3) Use the appropriate set of verification methods (ex: verify a signature for authentication purpose) sig, _ := base64.StdEncoding.DecodeString("nhpkr5a7juUM2eDpDRSJVdEE++0SYqaZXHtuvyafVFUx8zsOdDSrij+vHmd/ARwUOmi/ysmSD+b3K9WTBtmmBQ==") - if ok, method := did.TryAllVerify(doc.Authentication(), []byte("message"), sig); ok { + if ok, method := did.TryAllVerifyBytes(doc.Authentication(), []byte("message"), sig); ok { fmt.Println("Signature is valid, verified with method:", method.Type(), method.ID()) } else { fmt.Println("Signature is invalid") diff --git a/go.mod b/go.mod index 7568f65..838c737 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,8 @@ module github.com/MetaMask/go-did-it -go 1.23.0 +go 1.24.4 -toolchain go1.23.1 +toolchain go1.24.5 require ( github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 @@ -10,7 +10,8 @@ require ( github.com/multiformats/go-multibase v0.2.0 github.com/multiformats/go-varint v0.0.7 github.com/stretchr/testify v1.10.0 - golang.org/x/crypto v0.39.0 + github.com/ucan-wg/go-varsig v1.0.0 + golang.org/x/crypto v0.40.0 ) require ( @@ -18,6 +19,6 @@ require ( github.com/multiformats/go-base32 v0.0.3 // indirect github.com/multiformats/go-base36 v0.1.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - golang.org/x/sys v0.33.0 // indirect + golang.org/x/sys v0.34.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index cbbeb8a..1a7b852 100644 --- a/go.sum +++ b/go.sum @@ -18,10 +18,12 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= -golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +github.com/ucan-wg/go-varsig v1.0.0 h1:Hrc437Zg+B5Eoajg+qZQZI3Q3ocPyjlnp3/Bz9ZnlWw= +github.com/ucan-wg/go-varsig v1.0.0/go.mod h1:Sakln6IPooDPH+ClQ0VvR09TuwUhHcfLqcPiPkMZGh0= +golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= +golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/interfaces.go b/interfaces.go index 58ddbb0..6c5d6c5 100644 --- a/interfaces.go +++ b/interfaces.go @@ -104,8 +104,11 @@ type VerificationMethod interface { type VerificationMethodSignature interface { VerificationMethod - // Verify checks that 'sig' is a valid signature of 'data'. - Verify(data []byte, sig []byte) (bool, error) + // VerifyBytes checks that 'sig' is a valid "raw bytes" signature of 'data'. + VerifyBytes(data []byte, sig []byte, opts ...crypto.SigningOption) (bool, error) + + // VerifyASN1 checks that 'sig' is a valid ASN.1 signature of 'data'. + VerifyASN1(data []byte, sig []byte, opts ...crypto.SigningOption) (bool, error) } // VerificationMethodKeyAgreement is a VerificationMethod implementing a shared key agreement. diff --git a/utilities.go b/utilities.go index 152a99e..d3a2474 100644 --- a/utilities.go +++ b/utilities.go @@ -6,12 +6,24 @@ import ( "github.com/MetaMask/go-did-it/crypto" ) -// TryAllVerify tries to verify the signature with all the methods in the slice. +// TryAllVerifyBytes tries to verify the signature as bytes with all the methods in the slice. // It returns true if the signature is verified, and the method that verified it. // If no method verifies the signature, it returns false and nil. -func TryAllVerify(methods []VerificationMethodSignature, data []byte, sig []byte) (bool, VerificationMethodSignature) { +func TryAllVerifyBytes(methods []VerificationMethodSignature, data []byte, sig []byte, opts ...crypto.SigningOption) (bool, VerificationMethodSignature) { for _, method := range methods { - if valid, err := method.Verify(data, sig); err == nil && valid { + if valid, err := method.VerifyBytes(data, sig, opts...); err == nil && valid { + return true, method + } + } + return false, nil +} + +// TryAllVerifyASN1 tries to verify the signature as ASN.1 with all the methods in the slice. +// It returns true if the signature is verified, and the method that verified it. +// If no method verifies the signature, it returns false and nil. +func TryAllVerifyASN1(methods []VerificationMethodSignature, data []byte, sig []byte, opts ...crypto.SigningOption) (bool, VerificationMethodSignature) { + for _, method := range methods { + if valid, err := method.VerifyASN1(data, sig, opts...); err == nil && valid { return true, method } } diff --git a/verifiers/_methods/ed25519/VerificationKey2018.go b/verifiers/_methods/ed25519/VerificationKey2018.go index 3bbfc64..9b06ee1 100644 --- a/verifiers/_methods/ed25519/VerificationKey2018.go +++ b/verifiers/_methods/ed25519/VerificationKey2018.go @@ -8,6 +8,7 @@ import ( "github.com/mr-tron/base58" "github.com/MetaMask/go-did-it" + "github.com/MetaMask/go-did-it/crypto" "github.com/MetaMask/go-did-it/crypto/ed25519" ) @@ -97,6 +98,10 @@ func (v VerificationKey2018) JsonLdContext() string { return JsonLdContext2018 } -func (v VerificationKey2018) Verify(data []byte, sig []byte) (bool, error) { - return v.pubkey.VerifyBytes(data, sig), nil +func (v VerificationKey2018) VerifyBytes(data []byte, sig []byte, opts ...crypto.SigningOption) (bool, error) { + return v.pubkey.VerifyBytes(data, sig, opts...), nil +} + +func (v VerificationKey2018) VerifyASN1(data []byte, sig []byte, opts ...crypto.SigningOption) (bool, error) { + return v.pubkey.VerifyASN1(data, sig, opts...), nil } diff --git a/verifiers/_methods/ed25519/VerificationKey2020.go b/verifiers/_methods/ed25519/VerificationKey2020.go index 4cdc174..cedb424 100644 --- a/verifiers/_methods/ed25519/VerificationKey2020.go +++ b/verifiers/_methods/ed25519/VerificationKey2020.go @@ -6,6 +6,7 @@ import ( "fmt" "github.com/MetaMask/go-did-it" + "github.com/MetaMask/go-did-it/crypto" "github.com/MetaMask/go-did-it/crypto/ed25519" ) @@ -91,6 +92,10 @@ func (v VerificationKey2020) JsonLdContext() string { return JsonLdContext2020 } -func (v VerificationKey2020) Verify(data []byte, sig []byte) (bool, error) { - return v.pubkey.VerifyBytes(data, sig), nil +func (v VerificationKey2020) VerifyBytes(data []byte, sig []byte, opts ...crypto.SigningOption) (bool, error) { + return v.pubkey.VerifyBytes(data, sig, opts...), nil +} + +func (v VerificationKey2020) VerifyASN1(data []byte, sig []byte, opts ...crypto.SigningOption) (bool, error) { + return v.pubkey.VerifyASN1(data, sig, opts...), nil } diff --git a/verifiers/_methods/jsonwebkey/JsonWebKey2020.go b/verifiers/_methods/jsonwebkey/JsonWebKey2020.go index 6a93392..ac8bc2c 100644 --- a/verifiers/_methods/jsonwebkey/JsonWebKey2020.go +++ b/verifiers/_methods/jsonwebkey/JsonWebKey2020.go @@ -93,9 +93,16 @@ func (j JsonWebKey2020) JsonLdContext() string { return JsonLdContext } -func (j JsonWebKey2020) Verify(data []byte, sig []byte) (bool, error) { +func (j JsonWebKey2020) VerifyBytes(data []byte, sig []byte, opts ...crypto.SigningOption) (bool, error) { if pub, ok := j.pubkey.(crypto.PublicKeySigningBytes); ok { - return pub.VerifyBytes(data, sig), nil + return pub.VerifyBytes(data, sig, opts...), nil + } + return false, errors.New("not a signing public key") +} + +func (j JsonWebKey2020) VerifyASN1(data []byte, sig []byte, opts ...crypto.SigningOption) (bool, error) { + if pub, ok := j.pubkey.(crypto.PublicKeySigningASN1); ok { + return pub.VerifyASN1(data, sig, opts...), nil } return false, errors.New("not a signing public key") } diff --git a/verifiers/_methods/multikey/multikey.go b/verifiers/_methods/multikey/multikey.go index dbcd761..0234131 100644 --- a/verifiers/_methods/multikey/multikey.go +++ b/verifiers/_methods/multikey/multikey.go @@ -96,9 +96,16 @@ func (m MultiKey) JsonLdContext() string { return JsonLdContext } -func (m MultiKey) Verify(data []byte, sig []byte) (bool, error) { +func (m MultiKey) VerifyBytes(data []byte, sig []byte, opts ...crypto.SigningOption) (bool, error) { if pub, ok := m.pubkey.(crypto.PublicKeySigningBytes); ok { - return pub.VerifyBytes(data, sig), nil + return pub.VerifyBytes(data, sig, opts...), nil + } + return false, errors.New("not a signing public key") +} + +func (m MultiKey) VerifyASN1(data []byte, sig []byte, opts ...crypto.SigningOption) (bool, error) { + if pub, ok := m.pubkey.(crypto.PublicKeySigningASN1); ok { + return pub.VerifyASN1(data, sig, opts...), nil } return false, errors.New("not a signing public key") } diff --git a/verifiers/_methods/p256/key2021.go b/verifiers/_methods/p256/key2021.go index 072cdb3..8a1e3d8 100644 --- a/verifiers/_methods/p256/key2021.go +++ b/verifiers/_methods/p256/key2021.go @@ -101,8 +101,12 @@ func (m Key2021) JsonLdContext() string { return JsonLdContext2021 } -func (m Key2021) Verify(data []byte, sig []byte) (bool, error) { - return m.pubkey.VerifyBytes(data, sig), nil +func (m Key2021) VerifyBytes(data []byte, sig []byte, opts ...crypto.SigningOption) (bool, error) { + return m.pubkey.VerifyBytes(data, sig, opts...), nil +} + +func (m Key2021) VerifyASN1(data []byte, sig []byte, opts ...crypto.SigningOption) (bool, error) { + return m.pubkey.VerifyASN1(data, sig, opts...), nil } func (m Key2021) PrivateKeyIsCompatible(local crypto.PrivateKeyKeyExchange) bool { diff --git a/verifiers/_methods/secp256k1/VerificationKey2019.go b/verifiers/_methods/secp256k1/VerificationKey2019.go index fd8b746..21a3cb9 100644 --- a/verifiers/_methods/secp256k1/VerificationKey2019.go +++ b/verifiers/_methods/secp256k1/VerificationKey2019.go @@ -101,8 +101,12 @@ func (vm VerificationKey2019) JsonLdContext() string { return JsonLdContext } -func (vm VerificationKey2019) Verify(data []byte, sig []byte) (bool, error) { - return vm.pubkey.VerifyBytes(data, sig), nil +func (vm VerificationKey2019) VerifyBytes(data []byte, sig []byte, opts ...crypto.SigningOption) (bool, error) { + return vm.pubkey.VerifyBytes(data, sig, opts...), nil +} + +func (vm VerificationKey2019) VerifyASN1(data []byte, sig []byte, opts ...crypto.SigningOption) (bool, error) { + return vm.pubkey.VerifyASN1(data, sig, opts...), nil } func (vm VerificationKey2019) PrivateKeyIsCompatible(local crypto.PrivateKeyKeyExchange) bool { diff --git a/verifiers/did-key/key_test.go b/verifiers/did-key/key_test.go index 5e966c6..bc9fab5 100644 --- a/verifiers/did-key/key_test.go +++ b/verifiers/did-key/key_test.go @@ -32,7 +32,7 @@ func ExampleGenerateKeyPair() { // Resolve the DID and verify a signature doc, err := dk.Document() handleErr(err) - ok, _ := did.TryAllVerify(doc.Authentication(), msg, sig) + ok, _ := did.TryAllVerifyBytes(doc.Authentication(), msg, sig) fmt.Println("Signature verified:", ok) }