Merge pull request #17 from MetaMask/varsig

crypto: integrate varsig
This commit is contained in:
Michael Muré
2025-08-05 16:25:39 +02:00
committed by GitHub
30 changed files with 451 additions and 123 deletions

View File

@@ -24,4 +24,4 @@ jobs:
- name: Run tests - name: Run tests
run: go test -v ./... run: go test -v ./...
- name: Check formatted - name: Check formatted
run: gofmt -l . run: gofmt -l .

View File

@@ -9,6 +9,7 @@ import (
mbase "github.com/multiformats/go-multibase" mbase "github.com/multiformats/go-multibase"
"github.com/multiformats/go-varint" "github.com/multiformats/go-varint"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/ucan-wg/go-varsig"
"github.com/MetaMask/go-did-it/crypto" "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 name string
signer func(msg []byte, opts ...crypto.SigningOption) ([]byte, error) signer func(msg []byte, opts ...crypto.SigningOption) ([]byte, error)
verifier func(msg []byte, sig []byte, opts ...crypto.SigningOption) bool verifier func(msg []byte, sig []byte, opts ...crypto.SigningOption) bool
varsig func(opts ...crypto.SigningOption) varsig.Varsig
expectedSize int expectedSize int
stats *int stats *int
defaultHash crypto.Hash defaultHash crypto.Hash
@@ -210,6 +212,7 @@ func TestSuite[PubT crypto.PublicKey, PrivT crypto.PrivateKey](t *testing.T, har
name: "Bytes signature", name: "Bytes signature",
signer: spriv.SignToBytes, signer: spriv.SignToBytes,
verifier: spub.VerifyBytes, verifier: spub.VerifyBytes,
varsig: spriv.Varsig,
expectedSize: harness.SignatureBytesSize, expectedSize: harness.SignatureBytesSize,
stats: &stats.sigRawSize, stats: &stats.sigRawSize,
defaultHash: harness.DefaultHash, defaultHash: harness.DefaultHash,
@@ -227,6 +230,7 @@ func TestSuite[PubT crypto.PublicKey, PrivT crypto.PrivateKey](t *testing.T, har
name: "ASN.1 signature", name: "ASN.1 signature",
signer: spriv.SignToASN1, signer: spriv.SignToASN1,
verifier: spub.VerifyASN1, verifier: spub.VerifyASN1,
varsig: spriv.Varsig,
stats: &stats.sigAsn1Size, stats: &stats.sigAsn1Size,
defaultHash: harness.DefaultHash, defaultHash: harness.DefaultHash,
otherHashes: harness.OtherHashes, 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)) sigDefault, err := tc.signer(msg, crypto.WithSigningHash(tc.defaultHash))
require.NoError(t, err) require.NoError(t, err)
vsig := tc.varsig()
require.Equal(t, harness.DefaultHash.ToVarsigHash(), vsig.Hash())
if tc.expectedSize > 0 { if tc.expectedSize > 0 {
require.Equal(t, tc.expectedSize, len(sigNoParams)) 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 // signatures might be different (i.e. non-deterministic), but they should verify the same way
valid := tc.verifier(msg, sigNoParams) valid := tc.verifier(msg, sigNoParams)
require.True(t, valid) require.True(t, valid)
valid = tc.verifier(msg, sigNoParams, crypto.WithVarsig(vsig))
require.True(t, valid)
valid = tc.verifier(msg, sigDefault) valid = tc.verifier(msg, sigDefault)
require.True(t, valid) require.True(t, valid)
valid = tc.verifier(msg, sigDefault, crypto.WithVarsig(vsig))
require.True(t, valid)
valid = tc.verifier([]byte("wrong message"), sigNoParams) valid = tc.verifier([]byte("wrong message"), sigNoParams)
require.False(t, valid) 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) valid = tc.verifier([]byte("wrong message"), sigDefault)
require.False(t, valid) require.False(t, valid)
valid = tc.verifier([]byte("wrong message"), sigDefault, crypto.WithVarsig(vsig))
require.False(t, valid)
}) })
for _, hash := range tc.otherHashes { for _, hash := range tc.otherHashes {
t.Run(fmt.Sprintf("%s-%s", tc.name, hash.String()), func(t *testing.T) { 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.NoError(t, err)
require.NotEmpty(t, sig) 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)) valid := tc.verifier(msg, sig, crypto.WithSigningHash(hash))
require.True(t, valid) require.True(t, valid)
valid = tc.verifier(msg, sig, crypto.WithVarsig(vsig))
require.True(t, valid)
valid = tc.verifier([]byte("wrong message"), sig) valid = tc.verifier([]byte("wrong message"), sig)
require.False(t, valid) 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) { b.Run("Sign to ASN.1 signature", func(b *testing.B) {
if !pubImplements[PubT, crypto.PublicKeySigningASN1]() { if !pubImplements[PubT, crypto.PublicKeySigningASN1]() {
b.Skip("Signature to ASN.1 is not implemented") b.Skip("Signature to ASN.1 is not implemented")

View File

@@ -6,6 +6,7 @@ import (
"encoding/pem" "encoding/pem"
"fmt" "fmt"
"github.com/ucan-wg/go-varsig"
"golang.org/x/crypto/cryptobyte" "golang.org/x/crypto/cryptobyte"
"github.com/MetaMask/go-did-it/crypto" "github.com/MetaMask/go-did-it/crypto"
@@ -21,7 +22,7 @@ type PrivateKey struct {
// PrivateKeyFromBytes converts a serialized private key to a PrivateKey. // PrivateKeyFromBytes converts a serialized private key to a PrivateKey.
// This compact serialization format is the raw key material, without metadata or structure. // 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) { func PrivateKeyFromBytes(b []byte) (PrivateKey, error) {
if len(b) != PrivateKeyBytesSize { if len(b) != PrivateKeyBytesSize {
return PrivateKey{}, fmt.Errorf("invalid ed25519 private key size") 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)} 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) { func (p PrivateKey) SignToBytes(message []byte, opts ...crypto.SigningOption) ([]byte, error) {
params := crypto.CollectSigningOptions(opts) 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 nil, fmt.Errorf("ed25519 does not support custom hash functions")
} }
return ed25519.Sign(p.k, message), nil 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. // 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) { func (p PrivateKey) SignToASN1(message []byte, opts ...crypto.SigningOption) ([]byte, error) {
params := crypto.CollectSigningOptions(opts) 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 nil, fmt.Errorf("ed25519 does not support custom hash functions")
} }
sig := ed25519.Sign(p.k, message) sig := ed25519.Sign(p.k, message)
var b cryptobyte.Builder var b cryptobyte.Builder
b.AddASN1BitString(sig) b.AddASN1BitString(sig)

View File

@@ -7,6 +7,7 @@ import (
"encoding/pem" "encoding/pem"
"fmt" "fmt"
"github.com/ucan-wg/go-varsig"
"golang.org/x/crypto/cryptobyte" "golang.org/x/crypto/cryptobyte"
"github.com/MetaMask/go-did-it/crypto" "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 { func (p PublicKey) VerifyBytes(message, signature []byte, opts ...crypto.SigningOption) bool {
params := crypto.CollectSigningOptions(opts) 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 // ed25519 does not support custom hash functions
return false return false
} }
return ed25519.Verify(p.k, message, signature) 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. // 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 { func (p PublicKey) VerifyASN1(message, signature []byte, opts ...crypto.SigningOption) bool {
params := crypto.CollectSigningOptions(opts) 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 // ed25519 does not support custom hash functions
return false return false
} }
var s cryptobyte.String = signature var s cryptobyte.String = signature
var bitString asn1.BitString var bitString asn1.BitString

View File

@@ -5,41 +5,15 @@ import (
"hash" "hash"
"strconv" "strconv"
"github.com/ucan-wg/go-varsig"
"golang.org/x/crypto/sha3" "golang.org/x/crypto/sha3"
) )
// As the standard crypto library prohibits from registering additional hash algorithm (like keccak), // As the standard crypto library prohibits from registering additional hash algorithm (like keccak),
// below is essentially an extension of that mechanism to allow it. // 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 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 ( const (
// From "crypto" // From "crypto"
MD4 Hash = 1 + iota // import golang.org/x/crypto/md4 MD4 Hash = 1 + iota // import golang.org/x/crypto/md4
@@ -71,7 +45,20 @@ const (
maxHash 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 // New returns a new hash.Hash calculating the given hash function. New panics
// if the hash function is not linked into the binary. // 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() return stdcrypto.Hash(h).New()
} }
if h > maxStdHash && h < maxHash { if h > maxStdHash && h < maxHash {
f := hashes[h-maxStdHash-1] f := hashFns[h-maxStdHash-1]
if f != nil { if f != nil {
return f() 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 func (h Hash) ToVarsigHash() varsig.Hash {
// hash function. This is intended to be called from the init function in if h == MD5SHA1 {
// packages that implement hash functions. panic("no multihash/multicodec value exists for MD5+SHA1")
func RegisterHash(h Hash, f func() hash.Hash) {
if h >= maxHash {
panic("crypto: RegisterHash of unknown hash function")
} }
if h <= maxStdHash { if h < maxHash {
panic("crypto: RegisterHash of standard hash function") 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,
} }

View File

@@ -1,7 +1,17 @@
package crypto package crypto
import (
"github.com/ucan-wg/go-varsig"
)
type SigningOpts struct { 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 { func CollectSigningOptions(opts []SigningOption) SigningOpts {
@@ -13,10 +23,34 @@ func CollectSigningOptions(opts []SigningOption) SigningOpts {
} }
func (opts SigningOpts) HashOrDefault(_default Hash) Hash { func (opts SigningOpts) HashOrDefault(_default Hash) Hash {
if opts.Hash == 0 { if opts.hash == 0 {
return _default 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) type SigningOption func(opts *SigningOpts)
@@ -24,6 +58,34 @@ type SigningOption func(opts *SigningOpts)
// WithSigningHash specify the hash algorithm to be used for signatures // WithSigningHash specify the hash algorithm to be used for signatures
func WithSigningHash(hash Hash) SigningOption { func WithSigningHash(hash Hash) SigningOption {
return func(opts *SigningOpts) { 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")
}
} }
} }

View File

@@ -9,6 +9,8 @@ import (
"fmt" "fmt"
"math/big" "math/big"
"github.com/ucan-wg/go-varsig"
"github.com/MetaMask/go-did-it/crypto" "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. // The default signing hash is SHA-256.
func (p *PrivateKey) SignToBytes(message []byte, opts ...crypto.SigningOption) ([]byte, error) { func (p *PrivateKey) SignToBytes(message []byte, opts ...crypto.SigningOption) ([]byte, error) {
params := crypto.CollectSigningOptions(opts) params := crypto.CollectSigningOptions(opts)

View File

@@ -8,6 +8,8 @@ import (
"fmt" "fmt"
"math/big" "math/big"
"github.com/ucan-wg/go-varsig"
"github.com/MetaMask/go-did-it/crypto" "github.com/MetaMask/go-did-it/crypto"
helpers "github.com/MetaMask/go-did-it/crypto/internal" 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 { func (p *PublicKey) VerifyASN1(message, signature []byte, opts ...crypto.SigningOption) bool {
params := crypto.CollectSigningOptions(opts) params := crypto.CollectSigningOptions(opts)
if !params.VarsigMatch(varsig.AlgorithmECDSA, uint64(varsig.CurveP256), 0) {
return false
}
hasher := params.HashOrDefault(crypto.SHA256).New() hasher := params.HashOrDefault(crypto.SHA256).New()
hasher.Write(message) hasher.Write(message)
hash := hasher.Sum(nil) hash := hasher.Sum(nil)

View File

@@ -9,6 +9,8 @@ import (
"fmt" "fmt"
"math/big" "math/big"
"github.com/ucan-wg/go-varsig"
"github.com/MetaMask/go-did-it/crypto" "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. // The default signing hash is SHA-384.
func (p *PrivateKey) SignToBytes(message []byte, opts ...crypto.SigningOption) ([]byte, error) { func (p *PrivateKey) SignToBytes(message []byte, opts ...crypto.SigningOption) ([]byte, error) {
params := crypto.CollectSigningOptions(opts) params := crypto.CollectSigningOptions(opts)

View File

@@ -8,6 +8,8 @@ import (
"fmt" "fmt"
"math/big" "math/big"
"github.com/ucan-wg/go-varsig"
"github.com/MetaMask/go-did-it/crypto" "github.com/MetaMask/go-did-it/crypto"
helpers "github.com/MetaMask/go-did-it/crypto/internal" 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 { func (p *PublicKey) VerifyASN1(message, signature []byte, opts ...crypto.SigningOption) bool {
params := crypto.CollectSigningOptions(opts) params := crypto.CollectSigningOptions(opts)
if !params.VarsigMatch(varsig.AlgorithmECDSA, uint64(varsig.CurveP384), 0) {
return false
}
hasher := params.HashOrDefault(crypto.SHA384).New() hasher := params.HashOrDefault(crypto.SHA384).New()
hasher.Write(message) hasher.Write(message)
hash := hasher.Sum(nil) hash := hasher.Sum(nil)

View File

@@ -9,6 +9,8 @@ import (
"fmt" "fmt"
"math/big" "math/big"
"github.com/ucan-wg/go-varsig"
"github.com/MetaMask/go-did-it/crypto" "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. // The default signing hash is SHA-512.
func (p *PrivateKey) SignToBytes(message []byte, opts ...crypto.SigningOption) ([]byte, error) { func (p *PrivateKey) SignToBytes(message []byte, opts ...crypto.SigningOption) ([]byte, error) {
params := crypto.CollectSigningOptions(opts) params := crypto.CollectSigningOptions(opts)

View File

@@ -8,6 +8,8 @@ import (
"fmt" "fmt"
"math/big" "math/big"
"github.com/ucan-wg/go-varsig"
"github.com/MetaMask/go-did-it/crypto" "github.com/MetaMask/go-did-it/crypto"
helpers "github.com/MetaMask/go-did-it/crypto/internal" 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 { func (p *PublicKey) VerifyASN1(message, signature []byte, opts ...crypto.SigningOption) bool {
params := crypto.CollectSigningOptions(opts) params := crypto.CollectSigningOptions(opts)
if !params.VarsigMatch(varsig.AlgorithmECDSA, uint64(varsig.CurveP521), 0) {
return false
}
hasher := params.HashOrDefault(crypto.SHA512).New() hasher := params.HashOrDefault(crypto.SHA512).New()
hasher.Write(message) hasher.Write(message)
hash := hasher.Sum(nil) hash := hasher.Sum(nil)

View File

@@ -1,48 +1,6 @@
package crypto package crypto
// Public Key import "github.com/ucan-wg/go-varsig"
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
type PrivateKey interface { type PrivateKey interface {
// Equal returns true if other is the same PrivateKey // Equal returns true if other is the same PrivateKey
@@ -70,6 +28,9 @@ type PrivateKeyToBytes interface {
type PrivateKeySigningBytes interface { type PrivateKeySigningBytes interface {
PrivateKey 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. // SignToBytes creates a signature in the "raw bytes" format.
// This format can make some assumptions and may not be what you expect. // 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. // Ideally, this format is defined by the same specification as the underlying crypto scheme.
@@ -79,6 +40,9 @@ type PrivateKeySigningBytes interface {
type PrivateKeySigningASN1 interface { type PrivateKeySigningASN1 interface {
PrivateKey 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 creates a signature in the ASN.1 format.
SignToASN1(message []byte, opts ...SigningOption) ([]byte, error) SignToASN1(message []byte, opts ...SigningOption) ([]byte, error)
} }

41
crypto/public.go Normal file
View File

@@ -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
}

View File

@@ -9,6 +9,8 @@ import (
"fmt" "fmt"
"math/big" "math/big"
"github.com/ucan-wg/go-varsig"
"github.com/MetaMask/go-did-it/crypto" "github.com/MetaMask/go-did-it/crypto"
) )
@@ -67,8 +69,8 @@ func PrivateKeyFromPKCS8PEM(str string) (*PrivateKey, error) {
return PrivateKeyFromPKCS8DER(block.Bytes) return PrivateKeyFromPKCS8DER(block.Bytes)
} }
func (p *PrivateKey) BitLen() int { func (p *PrivateKey) KeyLength() uint64 {
return p.k.N.BitLen() return uint64((p.k.N.BitLen() + 7) / 8) // Round up to the nearest byte
} }
func (p *PrivateKey) DBytes() []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. // SignToASN1 produce a PKCS#1 v1.5 signature.
// The default signing hash is: // The default signing hash is:
// - SHA-256 for keys of length 2048 bits and under // - SHA-256 for keys of length 2048 bits and under

View File

@@ -8,6 +8,8 @@ import (
"fmt" "fmt"
"math/big" "math/big"
"github.com/ucan-wg/go-varsig"
"github.com/MetaMask/go-did-it/crypto" "github.com/MetaMask/go-did-it/crypto"
helpers "github.com/MetaMask/go-did-it/crypto/internal" helpers "github.com/MetaMask/go-did-it/crypto/internal"
) )
@@ -93,8 +95,8 @@ func PublicKeyFromX509PEM(str string) (*PublicKey, error) {
return PublicKeyFromX509DER(block.Bytes) return PublicKeyFromX509DER(block.Bytes)
} }
func (p *PublicKey) BitLen() int { func (p *PublicKey) KeyLength() uint64 {
return p.k.N.BitLen() return uint64((p.k.N.BitLen() + 7) / 8) // Round up to the nearest byte
} }
func (p *PublicKey) NBytes() []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 { func (p *PublicKey) VerifyASN1(message, signature []byte, opts ...crypto.SigningOption) bool {
params := crypto.CollectSigningOptions(opts) params := crypto.CollectSigningOptions(opts)
if !params.VarsigMatch(varsig.AlgorithmRSA, 0, p.KeyLength()) {
return false
}
hashCode := params.HashOrDefault(defaultSigHash(p.k.N.BitLen())) hashCode := params.HashOrDefault(defaultSigHash(p.k.N.BitLen()))
hasher := hashCode.New() hasher := hashCode.New()
hasher.Write(message) hasher.Write(message)

View File

@@ -8,6 +8,7 @@ import (
"github.com/decred/dcrd/dcrec/secp256k1/v4" "github.com/decred/dcrd/dcrec/secp256k1/v4"
"github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa" "github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa"
"github.com/ucan-wg/go-varsig"
"github.com/MetaMask/go-did-it/crypto" "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. // The default signing hash is SHA-256.
func (p *PrivateKey) SignToBytes(message []byte, opts ...crypto.SigningOption) ([]byte, error) { func (p *PrivateKey) SignToBytes(message []byte, opts ...crypto.SigningOption) ([]byte, error) {
params := crypto.CollectSigningOptions(opts) params := crypto.CollectSigningOptions(opts)

View File

@@ -8,6 +8,7 @@ import (
"github.com/decred/dcrd/dcrec/secp256k1/v4" "github.com/decred/dcrd/dcrec/secp256k1/v4"
"github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa" "github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa"
"github.com/ucan-wg/go-varsig"
"github.com/MetaMask/go-did-it/crypto" "github.com/MetaMask/go-did-it/crypto"
helpers "github.com/MetaMask/go-did-it/crypto/internal" 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) params := crypto.CollectSigningOptions(opts)
if !params.VarsigMatch(varsig.AlgorithmECDSA, uint64(varsig.CurveSecp256k1), 0) {
return false
}
hasher := params.HashOrDefault(crypto.SHA256).New() hasher := params.HashOrDefault(crypto.SHA256).New()
hasher.Write(message) hasher.Write(message)
hash := hasher.Sum(nil) 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 { func (p *PublicKey) VerifyASN1(message, signature []byte, opts ...crypto.SigningOption) bool {
params := crypto.CollectSigningOptions(opts) params := crypto.CollectSigningOptions(opts)
if !params.VarsigMatch(varsig.AlgorithmECDSA, uint64(varsig.CurveSecp256k1), 0) {
return false
}
hasher := params.HashOrDefault(crypto.SHA256).New() hasher := params.HashOrDefault(crypto.SHA256).New()
hasher.Write(message) hasher.Write(message)
hash := hasher.Sum(nil) hash := hasher.Sum(nil)

View File

@@ -23,7 +23,7 @@ func Example_signature() {
// 3) Use the appropriate set of verification methods (ex: verify a signature for authentication purpose) // 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==") 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()) fmt.Println("Signature is valid, verified with method:", method.Type(), method.ID())
} else { } else {
fmt.Println("Signature is invalid") fmt.Println("Signature is invalid")

9
go.mod
View File

@@ -1,8 +1,8 @@
module github.com/MetaMask/go-did-it module github.com/MetaMask/go-did-it
go 1.23.0 go 1.24.4
toolchain go1.23.1 toolchain go1.24.5
require ( require (
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 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-multibase v0.2.0
github.com/multiformats/go-varint v0.0.7 github.com/multiformats/go-varint v0.0.7
github.com/stretchr/testify v1.10.0 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 ( require (
@@ -18,6 +19,6 @@ require (
github.com/multiformats/go-base32 v0.0.3 // indirect github.com/multiformats/go-base32 v0.0.3 // indirect
github.com/multiformats/go-base36 v0.1.0 // indirect github.com/multiformats/go-base36 v0.1.0 // indirect
github.com/pmezard/go-difflib v1.0.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 gopkg.in/yaml.v3 v3.0.1 // indirect
) )

10
go.sum
View File

@@ -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/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 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 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= github.com/ucan-wg/go-varsig v1.0.0 h1:Hrc437Zg+B5Eoajg+qZQZI3Q3ocPyjlnp3/Bz9ZnlWw=
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= github.com/ucan-wg/go-varsig v1.0.0/go.mod h1:Sakln6IPooDPH+ClQ0VvR09TuwUhHcfLqcPiPkMZGh0=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 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 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

View File

@@ -104,8 +104,11 @@ type VerificationMethod interface {
type VerificationMethodSignature interface { type VerificationMethodSignature interface {
VerificationMethod VerificationMethod
// Verify checks that 'sig' is a valid signature of 'data'. // VerifyBytes checks that 'sig' is a valid "raw bytes" signature of 'data'.
Verify(data []byte, sig []byte) (bool, error) 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. // VerificationMethodKeyAgreement is a VerificationMethod implementing a shared key agreement.

View File

@@ -6,12 +6,24 @@ import (
"github.com/MetaMask/go-did-it/crypto" "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. // 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. // 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 { 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 return true, method
} }
} }

View File

@@ -8,6 +8,7 @@ import (
"github.com/mr-tron/base58" "github.com/mr-tron/base58"
"github.com/MetaMask/go-did-it" "github.com/MetaMask/go-did-it"
"github.com/MetaMask/go-did-it/crypto"
"github.com/MetaMask/go-did-it/crypto/ed25519" "github.com/MetaMask/go-did-it/crypto/ed25519"
) )
@@ -97,6 +98,10 @@ func (v VerificationKey2018) JsonLdContext() string {
return JsonLdContext2018 return JsonLdContext2018
} }
func (v VerificationKey2018) Verify(data []byte, sig []byte) (bool, error) { func (v VerificationKey2018) VerifyBytes(data []byte, sig []byte, opts ...crypto.SigningOption) (bool, error) {
return v.pubkey.VerifyBytes(data, sig), nil 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
} }

View File

@@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"github.com/MetaMask/go-did-it" "github.com/MetaMask/go-did-it"
"github.com/MetaMask/go-did-it/crypto"
"github.com/MetaMask/go-did-it/crypto/ed25519" "github.com/MetaMask/go-did-it/crypto/ed25519"
) )
@@ -91,6 +92,10 @@ func (v VerificationKey2020) JsonLdContext() string {
return JsonLdContext2020 return JsonLdContext2020
} }
func (v VerificationKey2020) Verify(data []byte, sig []byte) (bool, error) { func (v VerificationKey2020) VerifyBytes(data []byte, sig []byte, opts ...crypto.SigningOption) (bool, error) {
return v.pubkey.VerifyBytes(data, sig), nil 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
} }

View File

@@ -93,9 +93,16 @@ func (j JsonWebKey2020) JsonLdContext() string {
return JsonLdContext 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 { 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") return false, errors.New("not a signing public key")
} }

View File

@@ -96,9 +96,16 @@ func (m MultiKey) JsonLdContext() string {
return JsonLdContext 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 { 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") return false, errors.New("not a signing public key")
} }

View File

@@ -101,8 +101,12 @@ func (m Key2021) JsonLdContext() string {
return JsonLdContext2021 return JsonLdContext2021
} }
func (m Key2021) Verify(data []byte, sig []byte) (bool, error) { func (m Key2021) VerifyBytes(data []byte, sig []byte, opts ...crypto.SigningOption) (bool, error) {
return m.pubkey.VerifyBytes(data, sig), nil 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 { func (m Key2021) PrivateKeyIsCompatible(local crypto.PrivateKeyKeyExchange) bool {

View File

@@ -101,8 +101,12 @@ func (vm VerificationKey2019) JsonLdContext() string {
return JsonLdContext return JsonLdContext
} }
func (vm VerificationKey2019) Verify(data []byte, sig []byte) (bool, error) { func (vm VerificationKey2019) VerifyBytes(data []byte, sig []byte, opts ...crypto.SigningOption) (bool, error) {
return vm.pubkey.VerifyBytes(data, sig), nil 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 { func (vm VerificationKey2019) PrivateKeyIsCompatible(local crypto.PrivateKeyKeyExchange) bool {

View File

@@ -32,7 +32,7 @@ func ExampleGenerateKeyPair() {
// Resolve the DID and verify a signature // Resolve the DID and verify a signature
doc, err := dk.Document() doc, err := dk.Document()
handleErr(err) handleErr(err)
ok, _ := did.TryAllVerify(doc.Authentication(), msg, sig) ok, _ := did.TryAllVerifyBytes(doc.Authentication(), msg, sig)
fmt.Println("Signature verified:", ok) fmt.Println("Signature verified:", ok)
} }