diff --git a/crypto/ed25519/key_test.go b/crypto/ed25519/key_test.go index fe8e3a9..2b962a8 100644 --- a/crypto/ed25519/key_test.go +++ b/crypto/ed25519/key_test.go @@ -3,6 +3,7 @@ package ed25519 import ( "testing" + "github.com/INFURA/go-did/crypto" "github.com/INFURA/go-did/crypto/_testsuite" ) @@ -17,6 +18,8 @@ var harness = testsuite.TestHarness[PublicKey, PrivateKey]{ PrivateKeyFromPKCS8DER: PrivateKeyFromPKCS8DER, PrivateKeyFromPKCS8PEM: PrivateKeyFromPKCS8PEM, MultibaseCode: MultibaseCode, + DefaultHash: crypto.SHA512, + OtherHashes: nil, PublicKeyBytesSize: PublicKeyBytesSize, PrivateKeyBytesSize: PrivateKeyBytesSize, SignatureBytesSize: SignatureBytesSize, diff --git a/crypto/ed25519/private.go b/crypto/ed25519/private.go index 5e3d445..d88154b 100644 --- a/crypto/ed25519/private.go +++ b/crypto/ed25519/private.go @@ -68,13 +68,21 @@ func (p PrivateKey) Public() crypto.PublicKey { return PublicKey{k: p.k.Public().(ed25519.PublicKey)} } -func (p PrivateKey) SignToBytes(message []byte) ([]byte, error) { +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 { + return nil, fmt.Errorf("ed25519 does not support custom hash functions") + } return ed25519.Sign(p.k, message), nil } // SignToASN1 creates a signature with ASN.1 encoding. // This ASN.1 encoding uses a BIT STRING, which would be correct for an X.509 certificate. -func (p PrivateKey) SignToASN1(message []byte) ([]byte, error) { +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 { + 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 53065ee..da89745 100644 --- a/crypto/ed25519/public.go +++ b/crypto/ed25519/public.go @@ -98,13 +98,23 @@ func (p PublicKey) Equal(other crypto.PublicKey) bool { return false } -func (p PublicKey) VerifyBytes(message, signature []byte) 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 { + // ed25519 does not support custom hash functions + return false + } return ed25519.Verify(p.k, message, signature) } // VerifyASN1 verifies a signature with ASN.1 encoding. // This ASN.1 encoding uses a BIT STRING, which would be correct for an X.509 certificate. -func (p PublicKey) VerifyASN1(message, signature []byte) bool { +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 { + // 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 new file mode 100644 index 0000000..f92c769 --- /dev/null +++ b/crypto/hash.go @@ -0,0 +1,102 @@ +package crypto + +import ( + stdcrypto "crypto" + "hash" + "strconv" + + "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 + MD5 // import crypto/md5 + SHA1 // import crypto/sha1 + SHA224 // import crypto/sha256 + SHA256 // import crypto/sha256 + SHA384 // import crypto/sha512 + SHA512 // import crypto/sha512 + MD5SHA1 // no implementation; MD5+SHA1 used for TLS RSA + RIPEMD160 // import golang.org/x/crypto/ripemd160 + SHA3_224 // import golang.org/x/crypto/sha3 + SHA3_256 // import golang.org/x/crypto/sha3 + SHA3_384 // import golang.org/x/crypto/sha3 + SHA3_512 // import golang.org/x/crypto/sha3 + SHA512_224 // import crypto/sha512 + SHA512_256 // import crypto/sha512 + BLAKE2s_256 // import golang.org/x/crypto/blake2s + BLAKE2b_256 // import golang.org/x/crypto/blake2b + BLAKE2b_384 // import golang.org/x/crypto/blake2b + BLAKE2b_512 // import golang.org/x/crypto/blake2b + + maxStdHash + + // Extensions + KECCAK_256 + KECCAK_512 + + maxHash +) + +var hashes = make([]func() hash.Hash, maxHash-maxStdHash-1) + +// New returns a new hash.Hash calculating the given hash function. New panics +// if the hash function is not linked into the binary. +func (h Hash) New() hash.Hash { + if h > 0 && h < maxStdHash { + return stdcrypto.Hash(h).New() + } + if h > maxStdHash && h < maxHash { + f := hashes[h-maxStdHash-1] + if f != nil { + return f() + } + } + panic("crypto: 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") + } + if h <= maxStdHash { + panic("crypto: RegisterHash of standard hash function") + } + hashes[h-maxStdHash-1] = f +} diff --git a/crypto/interface.go b/crypto/interface.go index 1bd00f4..5c30272 100644 --- a/crypto/interface.go +++ b/crypto/interface.go @@ -32,10 +32,10 @@ type PublicKeySigning interface { // 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) bool + VerifyBytes(message, signature []byte, opts ...SigningOption) bool // VerifyASN1 checks a signature in the ASN.1 format. - VerifyASN1(message, signature []byte) bool + VerifyASN1(message, signature []byte, opts ...SigningOption) bool } // Private Key @@ -69,10 +69,10 @@ type PrivateKeySigning interface { // 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. - SignToBytes(message []byte) ([]byte, error) + SignToBytes(message []byte, opts ...SigningOption) ([]byte, error) // SignToASN1 creates a signature in the ASN.1 format. - SignToASN1(message []byte) ([]byte, error) + SignToASN1(message []byte, opts ...SigningOption) ([]byte, error) } type PrivateKeyKeyExchange interface { diff --git a/crypto/options.go b/crypto/options.go new file mode 100644 index 0000000..c24ab67 --- /dev/null +++ b/crypto/options.go @@ -0,0 +1,29 @@ +package crypto + +type SigningOpts struct { + Hash Hash +} + +func CollectSigningOptions(opts []SigningOption) SigningOpts { + res := SigningOpts{} + for _, opt := range opts { + opt(&res) + } + return res +} + +func (opts SigningOpts) HashOrDefault(_default Hash) Hash { + if opts.Hash == 0 { + return _default + } + return opts.Hash +} + +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 + } +} diff --git a/crypto/p256/key_test.go b/crypto/p256/key_test.go index 59029a0..dd26997 100644 --- a/crypto/p256/key_test.go +++ b/crypto/p256/key_test.go @@ -3,6 +3,7 @@ package p256 import ( "testing" + "github.com/INFURA/go-did/crypto" "github.com/INFURA/go-did/crypto/_testsuite" ) @@ -17,6 +18,8 @@ var harness = testsuite.TestHarness[*PublicKey, *PrivateKey]{ PrivateKeyFromPKCS8DER: PrivateKeyFromPKCS8DER, PrivateKeyFromPKCS8PEM: PrivateKeyFromPKCS8PEM, MultibaseCode: MultibaseCode, + DefaultHash: crypto.SHA256, + OtherHashes: []crypto.Hash{crypto.SHA224, crypto.SHA384, crypto.SHA512}, PublicKeyBytesSize: PublicKeyBytesSize, PrivateKeyBytesSize: PrivateKeyBytesSize, SignatureBytesSize: SignatureBytesSize, diff --git a/crypto/p256/private.go b/crypto/p256/private.go index 6ca8f0f..0fe9481 100644 --- a/crypto/p256/private.go +++ b/crypto/p256/private.go @@ -4,7 +4,6 @@ import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rand" - "crypto/sha256" "crypto/x509" "encoding/pem" "fmt" @@ -96,15 +95,13 @@ func (p *PrivateKey) ToPKCS8PEM() string { })) } -/* - Note: signatures for the crypto.PrivateKeySigning interface assumes SHA256, - which should be correct almost always. If there is a need to use a different - hash function, we can add separate functions that have that flexibility. -*/ +// The default signing hash is SHA-256. +func (p *PrivateKey) SignToBytes(message []byte, opts ...crypto.SigningOption) ([]byte, error) { + params := crypto.CollectSigningOptions(opts) -func (p *PrivateKey) SignToBytes(message []byte) ([]byte, error) { - // Hash the message with SHA-256 - hash := sha256.Sum256(message) + hasher := params.HashOrDefault(crypto.SHA256).New() + hasher.Write(message) + hash := hasher.Sum(nil) r, s, err := ecdsa.Sign(rand.Reader, p.k, hash[:]) if err != nil { @@ -118,9 +115,13 @@ func (p *PrivateKey) SignToBytes(message []byte) ([]byte, error) { return sig, nil } -func (p *PrivateKey) SignToASN1(message []byte) ([]byte, error) { - // Hash the message with SHA-256 - hash := sha256.Sum256(message) +// The default signing hash is SHA-256. +func (p *PrivateKey) SignToASN1(message []byte, opts ...crypto.SigningOption) ([]byte, error) { + params := crypto.CollectSigningOptions(opts) + + hasher := params.HashOrDefault(crypto.SHA256).New() + hasher.Write(message) + hash := hasher.Sum(nil) return ecdsa.SignASN1(rand.Reader, p.k, hash[:]) } diff --git a/crypto/p256/public.go b/crypto/p256/public.go index 5c75ba9..c262f7e 100644 --- a/crypto/p256/public.go +++ b/crypto/p256/public.go @@ -3,7 +3,6 @@ package p256 import ( "crypto/ecdsa" "crypto/elliptic" - "crypto/sha256" "crypto/x509" "encoding/pem" "fmt" @@ -124,13 +123,8 @@ func (p *PublicKey) ToX509PEM() string { })) } -/* - Note: signatures for the crypto.PrivateKeySigning interface assumes SHA256, - which should be correct almost always. If there is a need to use a different - hash function, we can add separate functions that have that flexibility. -*/ - -func (p *PublicKey) VerifyBytes(message, signature []byte) bool { +// The default signing hash is SHA-256. +func (p *PublicKey) VerifyBytes(message, signature []byte, opts ...crypto.SigningOption) bool { if len(signature) != SignatureBytesSize { return false } @@ -142,12 +136,16 @@ func (p *PublicKey) VerifyBytes(message, signature []byte) bool { return false } - return p.VerifyASN1(message, sigAsn1) + return p.VerifyASN1(message, sigAsn1, opts...) } -func (p *PublicKey) VerifyASN1(message, signature []byte) bool { - // Hash the message with SHA-256 - hash := sha256.Sum256(message) +// The default signing hash is SHA-256. +func (p *PublicKey) VerifyASN1(message, signature []byte, opts ...crypto.SigningOption) bool { + params := crypto.CollectSigningOptions(opts) + + hasher := params.HashOrDefault(crypto.SHA256).New() + hasher.Write(message) + hash := hasher.Sum(nil) return ecdsa.VerifyASN1(p.k, hash[:], signature) } diff --git a/crypto/p384/key_test.go b/crypto/p384/key_test.go index cb56ecb..50613b5 100644 --- a/crypto/p384/key_test.go +++ b/crypto/p384/key_test.go @@ -3,6 +3,7 @@ package p384 import ( "testing" + "github.com/INFURA/go-did/crypto" "github.com/INFURA/go-did/crypto/_testsuite" ) @@ -17,6 +18,8 @@ var harness = testsuite.TestHarness[*PublicKey, *PrivateKey]{ PrivateKeyFromPKCS8DER: PrivateKeyFromPKCS8DER, PrivateKeyFromPKCS8PEM: PrivateKeyFromPKCS8PEM, MultibaseCode: MultibaseCode, + DefaultHash: crypto.SHA384, + OtherHashes: []crypto.Hash{crypto.SHA256, crypto.SHA512}, PublicKeyBytesSize: PublicKeyBytesSize, PrivateKeyBytesSize: PrivateKeyBytesSize, SignatureBytesSize: SignatureBytesSize, diff --git a/crypto/p384/private.go b/crypto/p384/private.go index ef4fabe..7012ec2 100644 --- a/crypto/p384/private.go +++ b/crypto/p384/private.go @@ -4,7 +4,6 @@ import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rand" - "crypto/sha512" "crypto/x509" "encoding/pem" "fmt" @@ -96,15 +95,13 @@ func (p *PrivateKey) ToPKCS8PEM() string { })) } -/* - Note: signatures for the crypto.PrivateKeySigning interface assumes SHA384, - which should be correct almost always. If there is a need to use a different - hash function, we can add separate functions that have that flexibility. -*/ +// The default signing hash is SHA-384. +func (p *PrivateKey) SignToBytes(message []byte, opts ...crypto.SigningOption) ([]byte, error) { + params := crypto.CollectSigningOptions(opts) -func (p *PrivateKey) SignToBytes(message []byte) ([]byte, error) { - // Hash the message with SHA-384 - hash := sha512.Sum384(message) + hasher := params.HashOrDefault(crypto.SHA384).New() + hasher.Write(message) + hash := hasher.Sum(nil) r, s, err := ecdsa.Sign(rand.Reader, p.k, hash[:]) if err != nil { @@ -118,9 +115,13 @@ func (p *PrivateKey) SignToBytes(message []byte) ([]byte, error) { return sig, nil } -func (p *PrivateKey) SignToASN1(message []byte) ([]byte, error) { - // Hash the message with SHA-384 - hash := sha512.Sum384(message) +// The default signing hash is SHA-384. +func (p *PrivateKey) SignToASN1(message []byte, opts ...crypto.SigningOption) ([]byte, error) { + params := crypto.CollectSigningOptions(opts) + + hasher := params.HashOrDefault(crypto.SHA384).New() + hasher.Write(message) + hash := hasher.Sum(nil) return ecdsa.SignASN1(rand.Reader, p.k, hash[:]) } diff --git a/crypto/p384/public.go b/crypto/p384/public.go index c3f405d..06a1d96 100644 --- a/crypto/p384/public.go +++ b/crypto/p384/public.go @@ -3,7 +3,6 @@ package p384 import ( "crypto/ecdsa" "crypto/elliptic" - "crypto/sha512" "crypto/x509" "encoding/pem" "fmt" @@ -124,13 +123,8 @@ func (p *PublicKey) ToX509PEM() string { })) } -/* - Note: signatures for the crypto.PrivateKeySigning interface assumes SHA384, - which should be correct almost always. If there is a need to use a different - hash function, we can add separate functions that have that flexibility. -*/ - -func (p *PublicKey) VerifyBytes(message, signature []byte) bool { +// The default signing hash is SHA-384. +func (p *PublicKey) VerifyBytes(message, signature []byte, opts ...crypto.SigningOption) bool { if len(signature) != SignatureBytesSize { return false } @@ -142,12 +136,16 @@ func (p *PublicKey) VerifyBytes(message, signature []byte) bool { return false } - return p.VerifyASN1(message, sigAsn1) + return p.VerifyASN1(message, sigAsn1, opts...) } -func (p *PublicKey) VerifyASN1(message, signature []byte) bool { - // Hash the message with SHA-384 - hash := sha512.Sum384(message) +// The default signing hash is SHA-384. +func (p *PublicKey) VerifyASN1(message, signature []byte, opts ...crypto.SigningOption) bool { + params := crypto.CollectSigningOptions(opts) + + hasher := params.HashOrDefault(crypto.SHA384).New() + hasher.Write(message) + hash := hasher.Sum(nil) return ecdsa.VerifyASN1(p.k, hash[:], signature) } diff --git a/crypto/p521/key_test.go b/crypto/p521/key_test.go index 79a82fc..5e65c6e 100644 --- a/crypto/p521/key_test.go +++ b/crypto/p521/key_test.go @@ -3,6 +3,7 @@ package p521 import ( "testing" + "github.com/INFURA/go-did/crypto" "github.com/INFURA/go-did/crypto/_testsuite" ) @@ -17,6 +18,8 @@ var harness = testsuite.TestHarness[*PublicKey, *PrivateKey]{ PrivateKeyFromPKCS8DER: PrivateKeyFromPKCS8DER, PrivateKeyFromPKCS8PEM: PrivateKeyFromPKCS8PEM, MultibaseCode: MultibaseCode, + DefaultHash: crypto.SHA512, + OtherHashes: []crypto.Hash{crypto.SHA384}, PublicKeyBytesSize: PublicKeyBytesSize, PrivateKeyBytesSize: PrivateKeyBytesSize, SignatureBytesSize: SignatureBytesSize, diff --git a/crypto/p521/private.go b/crypto/p521/private.go index a33353e..15da5b5 100644 --- a/crypto/p521/private.go +++ b/crypto/p521/private.go @@ -4,7 +4,6 @@ import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rand" - "crypto/sha512" "crypto/x509" "encoding/pem" "fmt" @@ -96,15 +95,13 @@ func (p *PrivateKey) ToPKCS8PEM() string { })) } -/* - Note: signatures for the crypto.PrivateKeySigning interface assumes SHA512, - which should be correct almost always. If there is a need to use a different - hash function, we can add separate functions that have that flexibility. -*/ +// The default signing hash is SHA-512. +func (p *PrivateKey) SignToBytes(message []byte, opts ...crypto.SigningOption) ([]byte, error) { + params := crypto.CollectSigningOptions(opts) -func (p *PrivateKey) SignToBytes(message []byte) ([]byte, error) { - // Hash the message with SHA-512 - hash := sha512.Sum512(message) + hasher := params.HashOrDefault(crypto.SHA512).New() + hasher.Write(message) + hash := hasher.Sum(nil) r, s, err := ecdsa.Sign(rand.Reader, p.k, hash[:]) if err != nil { @@ -118,9 +115,13 @@ func (p *PrivateKey) SignToBytes(message []byte) ([]byte, error) { return sig, nil } -func (p *PrivateKey) SignToASN1(message []byte) ([]byte, error) { - // Hash the message with SHA-512 - hash := sha512.Sum512(message) +// The default signing hash is SHA-512. +func (p *PrivateKey) SignToASN1(message []byte, opts ...crypto.SigningOption) ([]byte, error) { + params := crypto.CollectSigningOptions(opts) + + hasher := params.HashOrDefault(crypto.SHA512).New() + hasher.Write(message) + hash := hasher.Sum(nil) return ecdsa.SignASN1(rand.Reader, p.k, hash[:]) } diff --git a/crypto/p521/public.go b/crypto/p521/public.go index 33d09e1..01b4b35 100644 --- a/crypto/p521/public.go +++ b/crypto/p521/public.go @@ -3,7 +3,6 @@ package p521 import ( "crypto/ecdsa" "crypto/elliptic" - "crypto/sha512" "crypto/x509" "encoding/pem" "fmt" @@ -124,13 +123,8 @@ func (p *PublicKey) ToX509PEM() string { })) } -/* - Note: signatures for the crypto.PrivateKeySigning interface assumes SHA512, - which should be correct almost always. If there is a need to use a different - hash function, we can add separate functions that have that flexibility. -*/ - -func (p *PublicKey) VerifyBytes(message, signature []byte) bool { +// The default signing hash is SHA-512. +func (p *PublicKey) VerifyBytes(message, signature []byte, opts ...crypto.SigningOption) bool { if len(signature) != SignatureBytesSize { return false } @@ -142,12 +136,16 @@ func (p *PublicKey) VerifyBytes(message, signature []byte) bool { return false } - return p.VerifyASN1(message, sigAsn1) + return p.VerifyASN1(message, sigAsn1, opts...) } -func (p *PublicKey) VerifyASN1(message, signature []byte) bool { - // Hash the message with SHA-512 - hash := sha512.Sum512(message) +// The default signing hash is SHA-512. +func (p *PublicKey) VerifyASN1(message, signature []byte, opts ...crypto.SigningOption) bool { + params := crypto.CollectSigningOptions(opts) + + hasher := params.HashOrDefault(crypto.SHA512).New() + hasher.Write(message) + hash := hasher.Sum(nil) return ecdsa.VerifyASN1(p.k, hash[:], signature) } diff --git a/go.mod b/go.mod index 5011e7d..28283bd 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,8 @@ go 1.23.0 toolchain go1.23.1 require ( + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 + github.com/mr-tron/base58 v1.1.0 github.com/multiformats/go-multibase v0.2.0 github.com/multiformats/go-varint v0.0.7 github.com/stretchr/testify v1.10.0 @@ -13,9 +15,9 @@ require ( require ( github.com/davecgh/go-spew v1.1.1 // indirect - github.com/mr-tron/base58 v1.1.0 // indirect 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 gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index efbce26..cbbeb8a 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,9 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8= +github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40= github.com/mr-tron/base58 v1.1.0 h1:Y51FGVJ91WBqCEabAi5OPUz38eAx8DakuAm5svLcsfQ= github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= @@ -16,6 +20,8 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf 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= 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=