2025-06-24 18:10:36 +02:00
|
|
|
package testsuite
|
2025-06-19 18:17:54 +02:00
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"strings"
|
|
|
|
|
"testing"
|
|
|
|
|
"text/tabwriter"
|
|
|
|
|
|
|
|
|
|
mbase "github.com/multiformats/go-multibase"
|
|
|
|
|
"github.com/multiformats/go-varint"
|
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
|
|
2025-07-10 15:56:45 +02:00
|
|
|
"github.com/ucan-wg/go-did-it/crypto"
|
2025-06-19 18:17:54 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type TestHarness[PubT crypto.PublicKey, PrivT crypto.PrivateKey] struct {
|
|
|
|
|
Name string
|
|
|
|
|
|
|
|
|
|
GenerateKeyPair func() (PubT, PrivT, error)
|
|
|
|
|
|
|
|
|
|
PublicKeyFromBytes func(b []byte) (PubT, error)
|
|
|
|
|
PublicKeyFromPublicKeyMultibase func(multibase string) (PubT, error)
|
|
|
|
|
PublicKeyFromX509DER func(bytes []byte) (PubT, error)
|
|
|
|
|
PublicKeyFromX509PEM func(str string) (PubT, error)
|
|
|
|
|
|
|
|
|
|
PrivateKeyFromBytes func(b []byte) (PrivT, error)
|
|
|
|
|
PrivateKeyFromPKCS8DER func(bytes []byte) (PrivT, error)
|
|
|
|
|
PrivateKeyFromPKCS8PEM func(str string) (PrivT, error)
|
|
|
|
|
|
|
|
|
|
MultibaseCode uint64
|
|
|
|
|
|
2025-07-08 12:59:23 +02:00
|
|
|
DefaultHash crypto.Hash
|
|
|
|
|
OtherHashes []crypto.Hash
|
|
|
|
|
|
2025-06-24 16:04:54 +02:00
|
|
|
PublicKeyBytesSize int
|
|
|
|
|
PrivateKeyBytesSize int
|
|
|
|
|
SignatureBytesSize int
|
2025-06-19 18:17:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestSuite[PubT crypto.PublicKey, PrivT crypto.PrivateKey](t *testing.T, harness TestHarness[PubT, PrivT]) {
|
|
|
|
|
stats := struct {
|
|
|
|
|
bytesPubSize int
|
|
|
|
|
bytesPrivSize int
|
|
|
|
|
|
|
|
|
|
x509DerPubSize int
|
|
|
|
|
pkcs8DerPrivSize int
|
|
|
|
|
|
|
|
|
|
x509PemPubSize int
|
|
|
|
|
pkcs8PemPrivSize int
|
2025-06-23 14:13:48 +02:00
|
|
|
|
|
|
|
|
sigRawSize int
|
|
|
|
|
sigAsn1Size int
|
2025-06-19 18:17:54 +02:00
|
|
|
}{}
|
|
|
|
|
|
|
|
|
|
t.Cleanup(func() {
|
|
|
|
|
out := strings.Builder{}
|
|
|
|
|
|
2025-06-23 14:13:48 +02:00
|
|
|
out.WriteString("\nKeypairs (in bytes):\n")
|
|
|
|
|
w := tabwriter.NewWriter(&out, 0, 0, 3, ' ', 0)
|
2025-06-19 18:17:54 +02:00
|
|
|
_, _ = fmt.Fprintln(w, "\tPublic key\tPrivate key")
|
|
|
|
|
_, _ = fmt.Fprintf(w, "Bytes\t%v\t%v\n", stats.bytesPubSize, stats.bytesPrivSize)
|
|
|
|
|
_, _ = fmt.Fprintf(w, "DER (pub:x509, priv:PKCS#8)\t%v\t%v\n", stats.x509DerPubSize, stats.pkcs8DerPrivSize)
|
|
|
|
|
_, _ = fmt.Fprintf(w, "PEM (pub:x509, priv:PKCS#8)\t%v\t%v\n", stats.x509PemPubSize, stats.pkcs8PemPrivSize)
|
|
|
|
|
_ = w.Flush()
|
|
|
|
|
|
2025-06-23 14:13:48 +02:00
|
|
|
out.WriteString("\nSignatures (in bytes):\n")
|
|
|
|
|
w.Init(&out, 0, 0, 3, ' ', 0)
|
|
|
|
|
_, _ = fmt.Fprintln(w, "Raw bytes\tASN.1")
|
|
|
|
|
_, _ = fmt.Fprintf(w, "%v\t%v\n", stats.sigRawSize, stats.sigAsn1Size)
|
|
|
|
|
_ = w.Flush()
|
|
|
|
|
|
2025-06-19 18:17:54 +02:00
|
|
|
t.Logf("Test result for %s:\n%s\n", harness.Name, out.String())
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("GenerateKeyPair", func(t *testing.T) {
|
|
|
|
|
pub, priv, err := harness.GenerateKeyPair()
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.NotNil(t, pub)
|
|
|
|
|
require.NotNil(t, priv)
|
|
|
|
|
require.True(t, pub.Equal(priv.Public()))
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("Equality", func(t *testing.T) {
|
2025-07-03 15:55:58 +02:00
|
|
|
if !pubImplements[PubT, crypto.PublicKeyToBytes]() {
|
|
|
|
|
t.Skip("Public key does not implement crypto.PublicKeyToBytes")
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-19 18:17:54 +02:00
|
|
|
pub1, priv1, err := harness.GenerateKeyPair()
|
|
|
|
|
require.NoError(t, err)
|
2025-07-03 15:55:58 +02:00
|
|
|
pub1Tb := (crypto.PublicKey(pub1)).(crypto.PublicKeyToBytes)
|
|
|
|
|
priv1Tb := (crypto.PrivateKey(priv1)).(crypto.PrivateKeyToBytes)
|
2025-06-19 18:17:54 +02:00
|
|
|
pub2, priv2, err := harness.GenerateKeyPair()
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
require.True(t, pub1.Equal(pub1))
|
|
|
|
|
require.True(t, priv1.Equal(priv1))
|
|
|
|
|
require.False(t, pub1.Equal(pub2))
|
|
|
|
|
require.False(t, priv1.Equal(priv2))
|
|
|
|
|
|
2025-07-03 15:55:58 +02:00
|
|
|
pub1copy, err := harness.PublicKeyFromBytes(pub1Tb.ToBytes())
|
2025-06-19 18:17:54 +02:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.True(t, pub1.Equal(pub1copy))
|
|
|
|
|
require.True(t, pub1copy.Equal(pub1))
|
|
|
|
|
|
2025-07-03 15:55:58 +02:00
|
|
|
priv1copy, err := harness.PrivateKeyFromBytes(priv1Tb.ToBytes())
|
2025-06-19 18:17:54 +02:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.True(t, priv1.Equal(priv1copy))
|
|
|
|
|
require.True(t, priv1copy.Equal(priv1))
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("BytesRoundTrip", func(t *testing.T) {
|
2025-07-03 15:55:58 +02:00
|
|
|
if !pubImplements[PubT, crypto.PublicKeyToBytes]() {
|
|
|
|
|
t.Skip("Public key does not implement crypto.PublicKeyToBytes")
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-19 18:17:54 +02:00
|
|
|
pub, priv, err := harness.GenerateKeyPair()
|
|
|
|
|
require.NoError(t, err)
|
2025-07-03 15:55:58 +02:00
|
|
|
pubTb := (crypto.PublicKey(pub)).(crypto.PublicKeyToBytes)
|
|
|
|
|
privTb := (crypto.PrivateKey(priv)).(crypto.PrivateKeyToBytes)
|
2025-06-19 18:17:54 +02:00
|
|
|
|
2025-07-03 15:55:58 +02:00
|
|
|
bytes := pubTb.ToBytes()
|
2025-06-19 18:17:54 +02:00
|
|
|
stats.bytesPubSize = len(bytes)
|
|
|
|
|
rtPub, err := harness.PublicKeyFromBytes(bytes)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.True(t, pub.Equal(rtPub))
|
2025-06-24 16:04:54 +02:00
|
|
|
require.Equal(t, harness.PublicKeyBytesSize, len(bytes))
|
2025-06-19 18:17:54 +02:00
|
|
|
|
2025-07-03 15:55:58 +02:00
|
|
|
bytes = privTb.ToBytes()
|
2025-06-19 18:17:54 +02:00
|
|
|
stats.bytesPrivSize = len(bytes)
|
|
|
|
|
rtPriv, err := harness.PrivateKeyFromBytes(bytes)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.True(t, priv.Equal(rtPriv))
|
2025-06-24 16:04:54 +02:00
|
|
|
require.Equal(t, harness.PrivateKeyBytesSize, len(bytes))
|
2025-06-19 18:17:54 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("MultibaseRoundTrip", func(t *testing.T) {
|
|
|
|
|
pub, _, err := harness.GenerateKeyPair()
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
mb := pub.ToPublicKeyMultibase()
|
|
|
|
|
rt, err := harness.PublicKeyFromPublicKeyMultibase(mb)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.Equal(t, pub, rt)
|
|
|
|
|
|
|
|
|
|
encoding, bytes, err := mbase.Decode(mb)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.Equal(t, mbase.Base58BTC, int32(encoding)) // according to the DID spec
|
|
|
|
|
code, _, err := varint.FromUvarint(bytes)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.Equal(t, harness.MultibaseCode, code)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("PublicKeyX509RoundTrip", func(t *testing.T) {
|
|
|
|
|
pub, _, err := harness.GenerateKeyPair()
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
der := pub.ToX509DER()
|
|
|
|
|
stats.x509DerPubSize = len(der)
|
|
|
|
|
rt, err := harness.PublicKeyFromX509DER(der)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.True(t, pub.Equal(rt))
|
|
|
|
|
|
|
|
|
|
pem := pub.ToX509PEM()
|
|
|
|
|
stats.x509PemPubSize = len(pem)
|
|
|
|
|
rt, err = harness.PublicKeyFromX509PEM(pem)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.True(t, pub.Equal(rt))
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("PrivateKeyPKCS8RoundTrip", func(t *testing.T) {
|
|
|
|
|
pub, priv, err := harness.GenerateKeyPair()
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
der := priv.ToPKCS8DER()
|
|
|
|
|
stats.pkcs8DerPrivSize = len(der)
|
|
|
|
|
rt, err := harness.PrivateKeyFromPKCS8DER(der)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.True(t, priv.Equal(rt))
|
|
|
|
|
require.True(t, pub.Equal(rt.Public()))
|
|
|
|
|
|
|
|
|
|
pem := priv.ToPKCS8PEM()
|
|
|
|
|
stats.pkcs8PemPrivSize = len(pem)
|
|
|
|
|
rt, err = harness.PrivateKeyFromPKCS8PEM(pem)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.True(t, priv.Equal(rt))
|
|
|
|
|
require.True(t, pub.Equal(rt.Public()))
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("Signature", func(t *testing.T) {
|
|
|
|
|
pub, priv, err := harness.GenerateKeyPair()
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
2025-07-09 17:58:09 +02:00
|
|
|
type testcase struct {
|
2025-06-23 14:13:48 +02:00
|
|
|
name string
|
2025-07-08 12:59:23 +02:00
|
|
|
signer func(msg []byte, opts ...crypto.SigningOption) ([]byte, error)
|
|
|
|
|
verifier func(msg []byte, sig []byte, opts ...crypto.SigningOption) bool
|
2025-06-23 14:13:48 +02:00
|
|
|
expectedSize int
|
|
|
|
|
stats *int
|
2025-07-08 12:59:23 +02:00
|
|
|
defaultHash crypto.Hash
|
|
|
|
|
otherHashes []crypto.Hash
|
2025-07-09 17:58:09 +02:00
|
|
|
}
|
|
|
|
|
var tcs []testcase
|
|
|
|
|
|
|
|
|
|
if pubImplements[PubT, crypto.PublicKeySigningBytes]() {
|
|
|
|
|
t.Run("Bytes signature", func(t *testing.T) {
|
|
|
|
|
spub := (crypto.PublicKey(pub)).(crypto.PublicKeySigningBytes)
|
|
|
|
|
spriv := (crypto.PrivateKey(priv)).(crypto.PrivateKeySigningBytes)
|
|
|
|
|
|
|
|
|
|
tcs = append(tcs, testcase{
|
|
|
|
|
name: "Bytes signature",
|
|
|
|
|
signer: spriv.SignToBytes,
|
|
|
|
|
verifier: spub.VerifyBytes,
|
|
|
|
|
expectedSize: harness.SignatureBytesSize,
|
|
|
|
|
stats: &stats.sigRawSize,
|
|
|
|
|
defaultHash: harness.DefaultHash,
|
|
|
|
|
otherHashes: harness.OtherHashes,
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if pubImplements[PubT, crypto.PublicKeySigningASN1]() {
|
|
|
|
|
t.Run("ASN.1 signature", func(t *testing.T) {
|
|
|
|
|
spub := (crypto.PublicKey(pub)).(crypto.PublicKeySigningASN1)
|
|
|
|
|
spriv := (crypto.PrivateKey(priv)).(crypto.PrivateKeySigningASN1)
|
|
|
|
|
|
|
|
|
|
tcs = append(tcs, testcase{
|
|
|
|
|
name: "ASN.1 signature",
|
|
|
|
|
signer: spriv.SignToASN1,
|
|
|
|
|
verifier: spub.VerifyASN1,
|
|
|
|
|
stats: &stats.sigAsn1Size,
|
|
|
|
|
defaultHash: harness.DefaultHash,
|
|
|
|
|
otherHashes: harness.OtherHashes,
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, tc := range tcs {
|
2025-06-23 14:13:48 +02:00
|
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
|
|
|
msg := []byte("message")
|
|
|
|
|
|
2025-07-08 12:59:23 +02:00
|
|
|
sigNoParams, err := tc.signer(msg)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.NotEmpty(t, sigNoParams)
|
|
|
|
|
|
|
|
|
|
sigDefault, err := tc.signer(msg, crypto.WithSigningHash(tc.defaultHash))
|
2025-06-23 14:13:48 +02:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
if tc.expectedSize > 0 {
|
2025-07-08 12:59:23 +02:00
|
|
|
require.Equal(t, tc.expectedSize, len(sigNoParams))
|
2025-06-23 14:13:48 +02:00
|
|
|
}
|
2025-07-08 12:59:23 +02:00
|
|
|
*tc.stats = len(sigNoParams)
|
2025-06-23 14:13:48 +02:00
|
|
|
|
2025-07-08 12:59:23 +02:00
|
|
|
// 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, sigDefault)
|
2025-06-23 14:13:48 +02:00
|
|
|
require.True(t, valid)
|
|
|
|
|
|
2025-07-08 12:59:23 +02:00
|
|
|
valid = tc.verifier([]byte("wrong message"), sigNoParams)
|
|
|
|
|
require.False(t, valid)
|
|
|
|
|
valid = tc.verifier([]byte("wrong message"), sigDefault)
|
2025-06-23 14:13:48 +02:00
|
|
|
require.False(t, valid)
|
|
|
|
|
})
|
2025-07-08 12:59:23 +02:00
|
|
|
for _, hash := range tc.otherHashes {
|
|
|
|
|
t.Run(fmt.Sprintf("%s-%s", tc.name, hash.String()), func(t *testing.T) {
|
|
|
|
|
msg := []byte("message")
|
|
|
|
|
|
2025-07-10 15:23:08 +02:00
|
|
|
sig, err := tc.signer(msg, crypto.WithSigningHash(hash))
|
2025-07-08 12:59:23 +02:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.NotEmpty(t, sig)
|
|
|
|
|
|
2025-07-10 15:23:08 +02:00
|
|
|
valid := tc.verifier(msg, sig, crypto.WithSigningHash(hash))
|
2025-07-08 12:59:23 +02:00
|
|
|
require.True(t, valid)
|
|
|
|
|
|
|
|
|
|
valid = tc.verifier([]byte("wrong message"), sig)
|
|
|
|
|
require.False(t, valid)
|
|
|
|
|
})
|
|
|
|
|
}
|
2025-06-23 14:13:48 +02:00
|
|
|
}
|
2025-06-19 18:17:54 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("KeyExchange", func(t *testing.T) {
|
|
|
|
|
pub1, priv1, err := harness.GenerateKeyPair()
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
pub2, priv2, err := harness.GenerateKeyPair()
|
|
|
|
|
require.NoError(t, err)
|
2025-06-24 14:05:42 +02:00
|
|
|
pub3, _, err := harness.GenerateKeyPair()
|
|
|
|
|
require.NoError(t, err)
|
2025-06-19 18:17:54 +02:00
|
|
|
|
2025-07-03 15:55:58 +02:00
|
|
|
kePriv1, ok := crypto.PrivateKey(priv1).(crypto.PrivateKeyKeyExchange)
|
2025-06-19 18:17:54 +02:00
|
|
|
if !ok {
|
|
|
|
|
t.Skip("Key exchange is not implemented")
|
|
|
|
|
}
|
2025-07-03 15:55:58 +02:00
|
|
|
kePriv2 := crypto.PrivateKey(priv2).(crypto.PrivateKeyKeyExchange)
|
2025-06-19 18:17:54 +02:00
|
|
|
|
2025-06-24 14:05:42 +02:00
|
|
|
// TODO: test with incompatible public keys
|
|
|
|
|
require.True(t, kePriv1.PublicKeyIsCompatible(pub2))
|
|
|
|
|
require.True(t, kePriv2.PublicKeyIsCompatible(pub1))
|
2025-06-19 18:17:54 +02:00
|
|
|
|
2025-06-24 14:05:42 +02:00
|
|
|
// 1 --> 2
|
|
|
|
|
kA, err := kePriv1.KeyExchange(pub2)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.NotEmpty(t, kA)
|
|
|
|
|
// 2 --> 1
|
|
|
|
|
kB, err := kePriv2.KeyExchange(pub1)
|
2025-06-19 18:17:54 +02:00
|
|
|
require.NoError(t, err)
|
2025-06-24 14:05:42 +02:00
|
|
|
require.NotEmpty(t, kB)
|
|
|
|
|
// 2 --> 3
|
|
|
|
|
kC, err := kePriv2.KeyExchange(pub3)
|
2025-06-19 18:17:54 +02:00
|
|
|
require.NoError(t, err)
|
2025-06-24 14:05:42 +02:00
|
|
|
require.NotEmpty(t, kC)
|
2025-06-19 18:17:54 +02:00
|
|
|
|
2025-06-24 14:05:42 +02:00
|
|
|
require.Equal(t, kA, kB)
|
|
|
|
|
require.NotEqual(t, kB, kC)
|
2025-06-19 18:17:54 +02:00
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func BenchSuite[PubT crypto.PublicKey, PrivT crypto.PrivateKey](b *testing.B, harness TestHarness[PubT, PrivT]) {
|
|
|
|
|
b.Run("GenerateKeyPair", func(b *testing.B) {
|
|
|
|
|
b.ReportAllocs()
|
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
|
_, _, _ = harness.GenerateKeyPair()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
b.Run("Bytes", func(b *testing.B) {
|
2025-07-03 15:55:58 +02:00
|
|
|
if !pubImplements[PubT, crypto.PublicKeyToBytes]() {
|
|
|
|
|
b.Skip("Public key does not implement crypto.PublicKeyToBytes")
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-19 18:17:54 +02:00
|
|
|
b.Run("PubToBytes", func(b *testing.B) {
|
|
|
|
|
pub, _, err := harness.GenerateKeyPair()
|
|
|
|
|
require.NoError(b, err)
|
2025-07-03 15:55:58 +02:00
|
|
|
pubTb := (crypto.PublicKey(pub)).(crypto.PublicKeyToBytes)
|
2025-06-19 18:17:54 +02:00
|
|
|
b.ResetTimer()
|
|
|
|
|
b.ReportAllocs()
|
|
|
|
|
for i := 0; i < b.N; i++ {
|
2025-07-03 15:55:58 +02:00
|
|
|
_ = pubTb.ToBytes()
|
2025-06-19 18:17:54 +02:00
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
b.Run("PubFromBytes", func(b *testing.B) {
|
|
|
|
|
pub, _, err := harness.GenerateKeyPair()
|
|
|
|
|
require.NoError(b, err)
|
2025-07-03 15:55:58 +02:00
|
|
|
pubTb := (crypto.PublicKey(pub)).(crypto.PublicKeyToBytes)
|
|
|
|
|
buf := pubTb.ToBytes()
|
2025-06-19 18:17:54 +02:00
|
|
|
b.ResetTimer()
|
|
|
|
|
b.ReportAllocs()
|
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
|
_, _ = harness.PublicKeyFromBytes(buf)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
b.Run("PrivToBytes", func(b *testing.B) {
|
|
|
|
|
_, priv, err := harness.GenerateKeyPair()
|
|
|
|
|
require.NoError(b, err)
|
2025-07-03 15:55:58 +02:00
|
|
|
privTb := (crypto.PrivateKey(priv)).(crypto.PrivateKeyToBytes)
|
2025-06-19 18:17:54 +02:00
|
|
|
b.ResetTimer()
|
|
|
|
|
b.ReportAllocs()
|
|
|
|
|
for i := 0; i < b.N; i++ {
|
2025-07-03 15:55:58 +02:00
|
|
|
_ = privTb.ToBytes()
|
2025-06-19 18:17:54 +02:00
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
b.Run("PrivFromBytes", func(b *testing.B) {
|
|
|
|
|
_, priv, err := harness.GenerateKeyPair()
|
|
|
|
|
require.NoError(b, err)
|
2025-07-03 15:55:58 +02:00
|
|
|
privTb := (crypto.PrivateKey(priv)).(crypto.PrivateKeyToBytes)
|
|
|
|
|
buf := privTb.ToBytes()
|
2025-06-19 18:17:54 +02:00
|
|
|
b.ResetTimer()
|
|
|
|
|
b.ReportAllocs()
|
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
|
_, _ = harness.PrivateKeyFromBytes(buf)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
b.Run("DER", func(b *testing.B) {
|
|
|
|
|
b.Run("PubToDER", func(b *testing.B) {
|
|
|
|
|
pub, _, err := harness.GenerateKeyPair()
|
|
|
|
|
require.NoError(b, err)
|
|
|
|
|
b.ResetTimer()
|
|
|
|
|
b.ReportAllocs()
|
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
|
_ = pub.ToX509DER()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
b.Run("PubFromDER", func(b *testing.B) {
|
|
|
|
|
pub, _, err := harness.GenerateKeyPair()
|
|
|
|
|
require.NoError(b, err)
|
|
|
|
|
buf := pub.ToX509DER()
|
|
|
|
|
b.ResetTimer()
|
|
|
|
|
b.ReportAllocs()
|
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
|
_, _ = harness.PublicKeyFromX509DER(buf)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
b.Run("PrivToDER", func(b *testing.B) {
|
|
|
|
|
_, priv, err := harness.GenerateKeyPair()
|
|
|
|
|
require.NoError(b, err)
|
|
|
|
|
b.ResetTimer()
|
|
|
|
|
b.ReportAllocs()
|
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
|
_ = priv.ToPKCS8DER()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
b.Run("PrivFromDER", func(b *testing.B) {
|
|
|
|
|
_, priv, err := harness.GenerateKeyPair()
|
|
|
|
|
require.NoError(b, err)
|
|
|
|
|
buf := priv.ToPKCS8DER()
|
|
|
|
|
b.ResetTimer()
|
|
|
|
|
b.ReportAllocs()
|
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
|
_, _ = harness.PrivateKeyFromPKCS8DER(buf)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
b.Run("PEM", func(b *testing.B) {
|
|
|
|
|
b.Run("PubToPEM", func(b *testing.B) {
|
|
|
|
|
pub, _, err := harness.GenerateKeyPair()
|
|
|
|
|
require.NoError(b, err)
|
|
|
|
|
b.ResetTimer()
|
|
|
|
|
b.ReportAllocs()
|
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
|
_ = pub.ToX509PEM()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
b.Run("PubFromPEM", func(b *testing.B) {
|
|
|
|
|
pub, _, err := harness.GenerateKeyPair()
|
|
|
|
|
require.NoError(b, err)
|
|
|
|
|
buf := pub.ToX509PEM()
|
|
|
|
|
b.ResetTimer()
|
|
|
|
|
b.ReportAllocs()
|
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
|
_, _ = harness.PublicKeyFromX509PEM(buf)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
b.Run("PrivToPEM", func(b *testing.B) {
|
|
|
|
|
_, priv, err := harness.GenerateKeyPair()
|
|
|
|
|
require.NoError(b, err)
|
|
|
|
|
b.ResetTimer()
|
|
|
|
|
b.ReportAllocs()
|
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
|
_ = priv.ToPKCS8PEM()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
b.Run("PrivFromPEM", func(b *testing.B) {
|
|
|
|
|
_, priv, err := harness.GenerateKeyPair()
|
|
|
|
|
require.NoError(b, err)
|
|
|
|
|
buf := priv.ToPKCS8PEM()
|
|
|
|
|
b.ResetTimer()
|
|
|
|
|
b.ReportAllocs()
|
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
|
_, _ = harness.PrivateKeyFromPKCS8PEM(buf)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
b.Run("Signatures", func(b *testing.B) {
|
2025-06-23 14:13:48 +02:00
|
|
|
b.Run("Sign to Bytes signature", func(b *testing.B) {
|
2025-07-09 17:58:09 +02:00
|
|
|
if !pubImplements[PubT, crypto.PublicKeySigningBytes]() {
|
|
|
|
|
b.Skip("Signature to bytes is not implemented")
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-23 14:13:48 +02:00
|
|
|
_, priv, err := harness.GenerateKeyPair()
|
|
|
|
|
require.NoError(b, err)
|
|
|
|
|
|
2025-07-09 17:58:09 +02:00
|
|
|
spriv := (crypto.PrivateKey(priv)).(crypto.PrivateKeySigningBytes)
|
2025-06-23 14:13:48 +02:00
|
|
|
|
|
|
|
|
b.ResetTimer()
|
|
|
|
|
b.ReportAllocs()
|
|
|
|
|
|
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
|
_, _ = spriv.SignToBytes([]byte("message"))
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
b.Run("Verify from Bytes signature", func(b *testing.B) {
|
2025-07-09 17:58:09 +02:00
|
|
|
if !pubImplements[PubT, crypto.PublicKeySigningBytes]() {
|
|
|
|
|
b.Skip("Signature to bytes is not implemented")
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-23 14:13:48 +02:00
|
|
|
pub, priv, err := harness.GenerateKeyPair()
|
|
|
|
|
require.NoError(b, err)
|
|
|
|
|
|
2025-07-09 17:58:09 +02:00
|
|
|
spub := (crypto.PublicKey(pub)).(crypto.PublicKeySigningBytes)
|
|
|
|
|
spriv := (crypto.PrivateKey(priv)).(crypto.PrivateKeySigningBytes)
|
2025-06-23 14:13:48 +02:00
|
|
|
sig, err := spriv.SignToBytes([]byte("message"))
|
|
|
|
|
require.NoError(b, err)
|
|
|
|
|
|
|
|
|
|
b.ResetTimer()
|
|
|
|
|
b.ReportAllocs()
|
|
|
|
|
|
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
|
spub.VerifyBytes([]byte("message"), sig)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
b.Run("Sign to ASN.1 signature", func(b *testing.B) {
|
2025-07-09 17:58:09 +02:00
|
|
|
if !pubImplements[PubT, crypto.PublicKeySigningASN1]() {
|
|
|
|
|
b.Skip("Signature to ASN.1 is not implemented")
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-19 18:17:54 +02:00
|
|
|
_, priv, err := harness.GenerateKeyPair()
|
|
|
|
|
require.NoError(b, err)
|
|
|
|
|
|
2025-07-09 17:58:09 +02:00
|
|
|
spriv := (crypto.PrivateKey(priv)).(crypto.PrivateKeySigningASN1)
|
2025-06-19 18:17:54 +02:00
|
|
|
|
|
|
|
|
b.ResetTimer()
|
|
|
|
|
b.ReportAllocs()
|
|
|
|
|
|
|
|
|
|
for i := 0; i < b.N; i++ {
|
2025-06-23 14:13:48 +02:00
|
|
|
_, _ = spriv.SignToASN1([]byte("message"))
|
2025-06-19 18:17:54 +02:00
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
2025-06-23 14:13:48 +02:00
|
|
|
b.Run("Verify from ASN.1 signature", func(b *testing.B) {
|
2025-07-09 17:58:09 +02:00
|
|
|
if !pubImplements[PubT, crypto.PublicKeySigningASN1]() {
|
|
|
|
|
b.Skip("Signature to ASN.1 is not implemented")
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-19 18:17:54 +02:00
|
|
|
pub, priv, err := harness.GenerateKeyPair()
|
|
|
|
|
require.NoError(b, err)
|
|
|
|
|
|
2025-07-09 17:58:09 +02:00
|
|
|
spub := (crypto.PublicKey(pub)).(crypto.PublicKeySigningASN1)
|
|
|
|
|
spriv := (crypto.PrivateKey(priv)).(crypto.PrivateKeySigningASN1)
|
2025-06-23 14:13:48 +02:00
|
|
|
sig, err := spriv.SignToASN1([]byte("message"))
|
2025-06-19 18:17:54 +02:00
|
|
|
require.NoError(b, err)
|
|
|
|
|
|
|
|
|
|
b.ResetTimer()
|
|
|
|
|
b.ReportAllocs()
|
|
|
|
|
|
|
|
|
|
for i := 0; i < b.N; i++ {
|
2025-06-23 14:13:48 +02:00
|
|
|
spub.VerifyASN1([]byte("message"), sig)
|
2025-06-19 18:17:54 +02:00
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
|
2025-06-24 14:05:42 +02:00
|
|
|
b.Run("Key exchange", func(b *testing.B) {
|
2025-07-03 15:55:58 +02:00
|
|
|
if !privImplements[PrivT, crypto.PrivateKeyKeyExchange]() {
|
2025-07-09 17:58:09 +02:00
|
|
|
b.Skip("Key exchange is not implemented")
|
2025-06-24 14:05:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
b.Run("KeyExchange", func(b *testing.B) {
|
|
|
|
|
_, priv1, err := harness.GenerateKeyPair()
|
|
|
|
|
require.NoError(b, err)
|
2025-07-03 15:55:58 +02:00
|
|
|
kePriv1 := (crypto.PrivateKey(priv1)).(crypto.PrivateKeyKeyExchange)
|
2025-06-24 14:05:42 +02:00
|
|
|
pub2, _, err := harness.GenerateKeyPair()
|
|
|
|
|
require.NoError(b, err)
|
|
|
|
|
|
|
|
|
|
b.ResetTimer()
|
|
|
|
|
b.ReportAllocs()
|
|
|
|
|
|
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
|
_, _ = kePriv1.KeyExchange(pub2)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
})
|
2025-06-19 18:17:54 +02:00
|
|
|
}
|
2025-07-03 15:55:58 +02:00
|
|
|
|
|
|
|
|
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
|
|
|
|
|
}
|