crypto: adjust interface names

This commit is contained in:
Michael Muré
2025-07-03 15:55:58 +02:00
parent e8ec13ae74
commit 9b871b5a20
15 changed files with 122 additions and 70 deletions

View File

@@ -78,8 +78,14 @@ func TestSuite[PubT crypto.PublicKey, PrivT crypto.PrivateKey](t *testing.T, har
})
t.Run("Equality", func(t *testing.T) {
if !pubImplements[PubT, crypto.PublicKeyToBytes]() {
t.Skip("Public key does not implement crypto.PublicKeyToBytes")
}
pub1, priv1, err := harness.GenerateKeyPair()
require.NoError(t, err)
pub1Tb := (crypto.PublicKey(pub1)).(crypto.PublicKeyToBytes)
priv1Tb := (crypto.PrivateKey(priv1)).(crypto.PrivateKeyToBytes)
pub2, priv2, err := harness.GenerateKeyPair()
require.NoError(t, err)
@@ -88,29 +94,35 @@ func TestSuite[PubT crypto.PublicKey, PrivT crypto.PrivateKey](t *testing.T, har
require.False(t, pub1.Equal(pub2))
require.False(t, priv1.Equal(priv2))
pub1copy, err := harness.PublicKeyFromBytes(pub1.ToBytes())
pub1copy, err := harness.PublicKeyFromBytes(pub1Tb.ToBytes())
require.NoError(t, err)
require.True(t, pub1.Equal(pub1copy))
require.True(t, pub1copy.Equal(pub1))
priv1copy, err := harness.PrivateKeyFromBytes(priv1.ToBytes())
priv1copy, err := harness.PrivateKeyFromBytes(priv1Tb.ToBytes())
require.NoError(t, err)
require.True(t, priv1.Equal(priv1copy))
require.True(t, priv1copy.Equal(priv1))
})
t.Run("BytesRoundTrip", func(t *testing.T) {
if !pubImplements[PubT, crypto.PublicKeyToBytes]() {
t.Skip("Public key does not implement crypto.PublicKeyToBytes")
}
pub, priv, err := harness.GenerateKeyPair()
require.NoError(t, err)
pubTb := (crypto.PublicKey(pub)).(crypto.PublicKeyToBytes)
privTb := (crypto.PrivateKey(priv)).(crypto.PrivateKeyToBytes)
bytes := pub.ToBytes()
bytes := pubTb.ToBytes()
stats.bytesPubSize = len(bytes)
rtPub, err := harness.PublicKeyFromBytes(bytes)
require.NoError(t, err)
require.True(t, pub.Equal(rtPub))
require.Equal(t, harness.PublicKeyBytesSize, len(bytes))
bytes = priv.ToBytes()
bytes = privTb.ToBytes()
stats.bytesPrivSize = len(bytes)
rtPriv, err := harness.PrivateKeyFromBytes(bytes)
require.NoError(t, err)
@@ -175,11 +187,11 @@ func TestSuite[PubT crypto.PublicKey, PrivT crypto.PrivateKey](t *testing.T, har
pub, priv, err := harness.GenerateKeyPair()
require.NoError(t, err)
spub, ok := (crypto.PublicKey(pub)).(crypto.SigningPublicKey)
spub, ok := (crypto.PublicKey(pub)).(crypto.PublicKeySigning)
if !ok {
t.Skip("Signature is not implemented")
}
spriv, ok := (crypto.PrivateKey(priv)).(crypto.SigningPrivateKey)
spriv, ok := (crypto.PrivateKey(priv)).(crypto.PrivateKeySigning)
if !ok {
t.Skip("Signature is not implemented")
}
@@ -234,11 +246,11 @@ func TestSuite[PubT crypto.PublicKey, PrivT crypto.PrivateKey](t *testing.T, har
pub3, _, err := harness.GenerateKeyPair()
require.NoError(t, err)
kePriv1, ok := crypto.PrivateKey(priv1).(crypto.KeyExchangePrivateKey)
kePriv1, ok := crypto.PrivateKey(priv1).(crypto.PrivateKeyKeyExchange)
if !ok {
t.Skip("Key exchange is not implemented")
}
kePriv2 := crypto.PrivateKey(priv2).(crypto.KeyExchangePrivateKey)
kePriv2 := crypto.PrivateKey(priv2).(crypto.PrivateKeyKeyExchange)
// TODO: test with incompatible public keys
require.True(t, kePriv1.PublicKeyIsCompatible(pub2))
@@ -271,20 +283,26 @@ func BenchSuite[PubT crypto.PublicKey, PrivT crypto.PrivateKey](b *testing.B, ha
})
b.Run("Bytes", func(b *testing.B) {
if !pubImplements[PubT, crypto.PublicKeyToBytes]() {
b.Skip("Public key does not implement crypto.PublicKeyToBytes")
}
b.Run("PubToBytes", func(b *testing.B) {
pub, _, err := harness.GenerateKeyPair()
require.NoError(b, err)
pubTb := (crypto.PublicKey(pub)).(crypto.PublicKeyToBytes)
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_ = pub.ToBytes()
_ = pubTb.ToBytes()
}
})
b.Run("PubFromBytes", func(b *testing.B) {
pub, _, err := harness.GenerateKeyPair()
require.NoError(b, err)
buf := pub.ToBytes()
pubTb := (crypto.PublicKey(pub)).(crypto.PublicKeyToBytes)
buf := pubTb.ToBytes()
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
@@ -295,17 +313,19 @@ func BenchSuite[PubT crypto.PublicKey, PrivT crypto.PrivateKey](b *testing.B, ha
b.Run("PrivToBytes", func(b *testing.B) {
_, priv, err := harness.GenerateKeyPair()
require.NoError(b, err)
privTb := (crypto.PrivateKey(priv)).(crypto.PrivateKeyToBytes)
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_ = priv.ToBytes()
_ = privTb.ToBytes()
}
})
b.Run("PrivFromBytes", func(b *testing.B) {
_, priv, err := harness.GenerateKeyPair()
require.NoError(b, err)
buf := priv.ToBytes()
privTb := (crypto.PrivateKey(priv)).(crypto.PrivateKeyToBytes)
buf := privTb.ToBytes()
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
@@ -403,7 +423,7 @@ func BenchSuite[PubT crypto.PublicKey, PrivT crypto.PrivateKey](b *testing.B, ha
})
b.Run("Signatures", func(b *testing.B) {
if _, ok := (crypto.PublicKey(*new(PubT))).(crypto.SigningPublicKey); !ok {
if !pubImplements[PubT, crypto.PublicKeySigning]() {
b.Skip("Signature is not implemented")
}
@@ -411,7 +431,7 @@ func BenchSuite[PubT crypto.PublicKey, PrivT crypto.PrivateKey](b *testing.B, ha
_, priv, err := harness.GenerateKeyPair()
require.NoError(b, err)
spriv := (crypto.PrivateKey(priv)).(crypto.SigningPrivateKey)
spriv := (crypto.PrivateKey(priv)).(crypto.PrivateKeySigning)
b.ResetTimer()
b.ReportAllocs()
@@ -425,8 +445,8 @@ func BenchSuite[PubT crypto.PublicKey, PrivT crypto.PrivateKey](b *testing.B, ha
pub, priv, err := harness.GenerateKeyPair()
require.NoError(b, err)
spub := (crypto.PublicKey(pub)).(crypto.SigningPublicKey)
spriv := (crypto.PrivateKey(priv)).(crypto.SigningPrivateKey)
spub := (crypto.PublicKey(pub)).(crypto.PublicKeySigning)
spriv := (crypto.PrivateKey(priv)).(crypto.PrivateKeySigning)
sig, err := spriv.SignToBytes([]byte("message"))
require.NoError(b, err)
@@ -442,7 +462,7 @@ func BenchSuite[PubT crypto.PublicKey, PrivT crypto.PrivateKey](b *testing.B, ha
_, priv, err := harness.GenerateKeyPair()
require.NoError(b, err)
spriv := (crypto.PrivateKey(priv)).(crypto.SigningPrivateKey)
spriv := (crypto.PrivateKey(priv)).(crypto.PrivateKeySigning)
b.ResetTimer()
b.ReportAllocs()
@@ -456,8 +476,8 @@ func BenchSuite[PubT crypto.PublicKey, PrivT crypto.PrivateKey](b *testing.B, ha
pub, priv, err := harness.GenerateKeyPair()
require.NoError(b, err)
spub := (crypto.PublicKey(pub)).(crypto.SigningPublicKey)
spriv := (crypto.PrivateKey(priv)).(crypto.SigningPrivateKey)
spub := (crypto.PublicKey(pub)).(crypto.PublicKeySigning)
spriv := (crypto.PrivateKey(priv)).(crypto.PrivateKeySigning)
sig, err := spriv.SignToASN1([]byte("message"))
require.NoError(b, err)
@@ -471,14 +491,14 @@ func BenchSuite[PubT crypto.PublicKey, PrivT crypto.PrivateKey](b *testing.B, ha
})
b.Run("Key exchange", func(b *testing.B) {
if _, ok := (crypto.PrivateKey(*new(PrivT))).(crypto.KeyExchangePrivateKey); !ok {
if !privImplements[PrivT, crypto.PrivateKeyKeyExchange]() {
b.Skip("Key echange is not implemented")
}
b.Run("KeyExchange", func(b *testing.B) {
_, priv1, err := harness.GenerateKeyPair()
require.NoError(b, err)
kePriv1 := (crypto.PrivateKey(priv1)).(crypto.KeyExchangePrivateKey)
kePriv1 := (crypto.PrivateKey(priv1)).(crypto.PrivateKeyKeyExchange)
pub2, _, err := harness.GenerateKeyPair()
require.NoError(b, err)
@@ -491,3 +511,13 @@ func BenchSuite[PubT crypto.PublicKey, PrivT crypto.PrivateKey](b *testing.B, ha
})
})
}
func privImplements[PrivT crypto.PrivateKey, wanted crypto.PrivateKey]() bool {
_, ok := crypto.PrivateKey(*new(PrivT)).(wanted)
return ok
}
func pubImplements[PubT crypto.PublicKey, wanted crypto.PublicKey]() bool {
_, ok := crypto.PublicKey(*new(PubT)).(wanted)
return ok
}

View File

@@ -11,7 +11,8 @@ import (
"github.com/INFURA/go-did/crypto"
)
var _ crypto.SigningPrivateKey = &PrivateKey{}
var _ crypto.PrivateKeySigning = &PrivateKey{}
var _ crypto.PrivateKeyToBytes = &PrivateKey{}
type PrivateKey struct {
k ed25519.PrivateKey

View File

@@ -13,7 +13,8 @@ import (
"github.com/INFURA/go-did/crypto/internal"
)
var _ crypto.SigningPublicKey = &PublicKey{}
var _ crypto.PublicKeySigning = PublicKey{}
var _ crypto.PublicKeyToBytes = PublicKey{}
type PublicKey struct {
k ed25519.PublicKey

View File

@@ -1,14 +1,11 @@
package crypto
// Public Key
type PublicKey interface {
// Equal returns true if other is the same PublicKey
Equal(other PublicKey) bool
// 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
// ToPublicKeyMultibase format the PublicKey into a string compatible with a PublicKeyMultibase field
// in a DID Document.
ToPublicKeyMultibase() string
@@ -20,26 +17,16 @@ type PublicKey interface {
ToX509PEM() string
}
type PrivateKey interface {
// Equal returns true if other is the same PrivateKey
Equal(other PrivateKey) bool
type PublicKeyToBytes interface {
PublicKey
// Public returns the matching PublicKey.
Public() PublicKey
// ToBytes serializes the PrivateKey into "raw bytes", without metadata or structure.
// 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
// ToPKCS8DER serializes the PrivateKey into the PKCS#8 DER (binary) format.
ToPKCS8DER() []byte
// ToPKCS8PEM serializes the PrivateKey into the PKCS#8 PEM (string) format.
ToPKCS8PEM() string
}
type SigningPublicKey interface {
type PublicKeySigning interface {
PublicKey
// VerifyBytes checks a signature in the "raw bytes" format.
@@ -51,7 +38,32 @@ type SigningPublicKey interface {
VerifyASN1(message, signature []byte) bool
}
type SigningPrivateKey interface {
// Private Key
type PrivateKey interface {
// Equal returns true if other is the same PrivateKey
Equal(other PrivateKey) bool
// Public returns the matching PublicKey.
Public() PublicKey
// ToPKCS8DER serializes the PrivateKey into the PKCS#8 DER (binary) format.
ToPKCS8DER() []byte
// ToPKCS8PEM serializes the PrivateKey into the PKCS#8 PEM (string) format.
ToPKCS8PEM() string
}
type PrivateKeyToBytes interface {
PrivateKey
// ToBytes serializes the PrivateKey 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 PrivateKeySigning interface {
PrivateKey
// SignToBytes creates a signature in the "raw bytes" format.
@@ -63,7 +75,7 @@ type SigningPrivateKey interface {
SignToASN1(message []byte) ([]byte, error)
}
type KeyExchangePrivateKey interface {
type PrivateKeyKeyExchange interface {
PrivateKey
// PublicKeyIsCompatible checks that the given PublicKey is compatible to perform key exchange.

View File

@@ -13,8 +13,9 @@ import (
"github.com/INFURA/go-did/crypto"
)
var _ crypto.SigningPrivateKey = (*PrivateKey)(nil)
var _ crypto.KeyExchangePrivateKey = (*PrivateKey)(nil)
var _ crypto.PrivateKeySigning = &PrivateKey{}
var _ crypto.PrivateKeyToBytes = &PrivateKey{}
var _ crypto.PrivateKeyKeyExchange = &PrivateKey{}
type PrivateKey struct {
k *ecdsa.PrivateKey
@@ -96,7 +97,7 @@ func (p *PrivateKey) ToPKCS8PEM() string {
}
/*
Note: signatures for the crypto.SigningPrivateKey interface assumes SHA256,
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.
*/

View File

@@ -13,7 +13,8 @@ import (
helpers "github.com/INFURA/go-did/crypto/internal"
)
var _ crypto.SigningPublicKey = &PublicKey{}
var _ crypto.PublicKeySigning = &PublicKey{}
var _ crypto.PublicKeyToBytes = &PublicKey{}
type PublicKey struct {
k *ecdsa.PublicKey
@@ -124,7 +125,7 @@ func (p *PublicKey) ToX509PEM() string {
}
/*
Note: signatures for the crypto.SigningPrivateKey interface assumes SHA256,
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.
*/

View File

@@ -13,8 +13,9 @@ import (
"github.com/INFURA/go-did/crypto"
)
var _ crypto.SigningPrivateKey = (*PrivateKey)(nil)
var _ crypto.KeyExchangePrivateKey = (*PrivateKey)(nil)
var _ crypto.PrivateKeySigning = &PrivateKey{}
var _ crypto.PrivateKeyToBytes = &PrivateKey{}
var _ crypto.PrivateKeyKeyExchange = &PrivateKey{}
type PrivateKey struct {
k *ecdsa.PrivateKey
@@ -96,7 +97,7 @@ func (p *PrivateKey) ToPKCS8PEM() string {
}
/*
Note: signatures for the crypto.SigningPrivateKey interface assumes SHA384,
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.
*/

View File

@@ -13,7 +13,8 @@ import (
helpers "github.com/INFURA/go-did/crypto/internal"
)
var _ crypto.SigningPublicKey = &PublicKey{}
var _ crypto.PublicKeySigning = &PublicKey{}
var _ crypto.PublicKeyToBytes = &PublicKey{}
type PublicKey struct {
k *ecdsa.PublicKey
@@ -124,7 +125,7 @@ func (p *PublicKey) ToX509PEM() string {
}
/*
Note: signatures for the crypto.SigningPrivateKey interface assumes SHA384,
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.
*/

View File

@@ -13,8 +13,9 @@ import (
"github.com/INFURA/go-did/crypto"
)
var _ crypto.SigningPrivateKey = (*PrivateKey)(nil)
var _ crypto.KeyExchangePrivateKey = (*PrivateKey)(nil)
var _ crypto.PrivateKeySigning = &PrivateKey{}
var _ crypto.PrivateKeyToBytes = &PrivateKey{}
var _ crypto.PrivateKeyKeyExchange = &PrivateKey{}
type PrivateKey struct {
k *ecdsa.PrivateKey
@@ -96,7 +97,7 @@ func (p *PrivateKey) ToPKCS8PEM() string {
}
/*
Note: signatures for the crypto.SigningPrivateKey interface assumes SHA512,
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.
*/

View File

@@ -13,7 +13,8 @@ import (
helpers "github.com/INFURA/go-did/crypto/internal"
)
var _ crypto.SigningPublicKey = &PublicKey{}
var _ crypto.PublicKeySigning = &PublicKey{}
var _ crypto.PublicKeyToBytes = &PublicKey{}
type PublicKey struct {
k *ecdsa.PublicKey
@@ -124,7 +125,7 @@ func (p *PublicKey) ToX509PEM() string {
}
/*
Note: signatures for the crypto.SigningPrivateKey interface assumes SHA512,
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.
*/

View File

@@ -11,7 +11,7 @@ import (
"github.com/INFURA/go-did/crypto/ed25519"
)
var _ crypto.KeyExchangePrivateKey = (*PrivateKey)(nil)
var _ crypto.PrivateKeyKeyExchange = (*PrivateKey)(nil)
type PrivateKey struct {
k *ecdh.PrivateKey

View File

@@ -111,8 +111,8 @@ type VerificationMethodKeyAgreement interface {
VerificationMethod
// PrivateKeyIsCompatible checks that the given PrivateKey is compatible with this method.
PrivateKeyIsCompatible(local crypto.KeyExchangePrivateKey) bool
PrivateKeyIsCompatible(local crypto.PrivateKeyKeyExchange) bool
// KeyExchange computes the shared key using the given PrivateKey.
KeyExchange(local crypto.KeyExchangePrivateKey) ([]byte, error)
KeyExchange(local crypto.PrivateKeyKeyExchange) ([]byte, error)
}

View File

@@ -21,7 +21,7 @@ func TryAllVerify(methods []VerificationMethodSignature, data []byte, sig []byte
// FindMatchingKeyAgreement tries to find a matching key agreement method for the given private key type.
// It returns the shared key as well as the selected method.
// If no matching method is found, it returns an error.
func FindMatchingKeyAgreement(methods []VerificationMethodKeyAgreement, priv crypto.KeyExchangePrivateKey) ([]byte, VerificationMethodKeyAgreement, error) {
func FindMatchingKeyAgreement(methods []VerificationMethodKeyAgreement, priv crypto.PrivateKeyKeyExchange) ([]byte, VerificationMethodKeyAgreement, error) {
for _, method := range methods {
if method.PrivateKeyIsCompatible(priv) {
key, err := method.KeyExchange(priv)

View File

@@ -9,7 +9,9 @@ import (
"github.com/INFURA/go-did/crypto/jwk"
)
// Specification: https://www.w3.org/TR/vc-jws-2020/
// Specification:
// - https://www.w3.org/TR/vc-jws-2020/
// - https://w3c-ccg.github.io/lds-jws2020/
const (
JsonLdContext = "https://w3id.org/security/suites/jws-2020/v1"
@@ -92,16 +94,16 @@ func (j JsonWebKey2020) JsonLdContext() string {
}
func (j JsonWebKey2020) Verify(data []byte, sig []byte) (bool, error) {
if pub, ok := j.pubkey.(crypto.SigningPublicKey); ok {
if pub, ok := j.pubkey.(crypto.PublicKeySigning); ok {
return pub.VerifyBytes(data, sig), nil
}
return false, errors.New("not a signing public key")
}
func (j JsonWebKey2020) PrivateKeyIsCompatible(local crypto.KeyExchangePrivateKey) bool {
func (j JsonWebKey2020) PrivateKeyIsCompatible(local crypto.PrivateKeyKeyExchange) bool {
return local.PublicKeyIsCompatible(j.pubkey)
}
func (j JsonWebKey2020) KeyExchange(local crypto.KeyExchangePrivateKey) ([]byte, error) {
func (j JsonWebKey2020) KeyExchange(local crypto.PrivateKeyKeyExchange) ([]byte, error) {
return local.KeyExchange(j.pubkey)
}

View File

@@ -96,16 +96,16 @@ func (m MultiKey) JsonLdContext() string {
}
func (m MultiKey) Verify(data []byte, sig []byte) (bool, error) {
if pub, ok := m.pubkey.(crypto.SigningPublicKey); ok {
if pub, ok := m.pubkey.(crypto.PublicKeySigning); ok {
return pub.VerifyBytes(data, sig), nil
}
return false, errors.New("not a signing public key")
}
func (m MultiKey) PrivateKeyIsCompatible(local crypto.KeyExchangePrivateKey) bool {
func (m MultiKey) PrivateKeyIsCompatible(local crypto.PrivateKeyKeyExchange) bool {
return local.PublicKeyIsCompatible(m.pubkey)
}
func (m MultiKey) KeyExchange(local crypto.KeyExchangePrivateKey) ([]byte, error) {
func (m MultiKey) KeyExchange(local crypto.PrivateKeyKeyExchange) ([]byte, error) {
return local.KeyExchange(m.pubkey)
}