WIP: P-256 support, serialization improvements
This commit is contained in:
@@ -12,7 +12,6 @@ import (
|
||||
// Specification: https://w3c.github.io/cg-reports/credentials/CG-FINAL-di-eddsa-2020-20220724/
|
||||
|
||||
const (
|
||||
MultibaseCode = uint64(0xed)
|
||||
JsonLdContext = "https://w3id.org/security/suites/ed25519-2020/v1"
|
||||
Type = "Ed25519VerificationKey2020"
|
||||
)
|
||||
|
||||
@@ -18,6 +18,8 @@ const (
|
||||
PrivateKeySize = ed25519.PrivateKeySize
|
||||
// SignatureSize is the size, in bytes, of signatures generated and verified by this package.
|
||||
SignatureSize = ed25519.SignatureSize
|
||||
|
||||
MultibaseCode = uint64(0xed)
|
||||
)
|
||||
|
||||
func GenerateKeyPair() (PublicKey, PrivateKey, error) {
|
||||
@@ -30,7 +32,16 @@ func PublicKeyFromBytes(b []byte) (PublicKey, error) {
|
||||
if len(b) != PublicKeySize {
|
||||
return nil, fmt.Errorf("invalid ed25519 public key size")
|
||||
}
|
||||
return PublicKey(b), nil
|
||||
// make a copy
|
||||
return PublicKey(append([]byte{}, b...)), nil
|
||||
}
|
||||
|
||||
// PublicKeyToBytes converts a public key to a byte slice.
|
||||
func PublicKeyToBytes(pub PublicKey) []byte {
|
||||
// Copy the private key to a fixed size buffer that can get allocated on the
|
||||
// caller's stack after inlining.
|
||||
var buf [PublicKeySize]byte
|
||||
return append(buf[:0], pub...)
|
||||
}
|
||||
|
||||
// PublicKeyFromMultibase decodes the public key from its Multibase form
|
||||
@@ -45,7 +56,7 @@ func PublicKeyFromMultibase(multibase string) (PublicKey, error) {
|
||||
if len(bytes) != PublicKeySize {
|
||||
return nil, fmt.Errorf("invalid ed25519 public key size")
|
||||
}
|
||||
return bytes, nil
|
||||
return PublicKeyFromBytes(bytes)
|
||||
}
|
||||
|
||||
// PublicKeyToMultibase encodes the public key in a suitable way for publicKeyMultibase
|
||||
@@ -53,13 +64,22 @@ func PublicKeyToMultibase(pub PublicKey) string {
|
||||
return helpers.MultibaseEncode(MultibaseCode, pub)
|
||||
}
|
||||
|
||||
// PrivateKeyFromBytes converts a serialized public key to a PrivateKey.
|
||||
// PrivateKeyFromBytes converts a serialized private key to a PrivateKey.
|
||||
// It errors if the slice is not the right size.
|
||||
func PrivateKeyFromBytes(b []byte) (PrivateKey, error) {
|
||||
if len(b) != ed25519.PrivateKeySize {
|
||||
if len(b) != PrivateKeySize {
|
||||
return nil, fmt.Errorf("invalid ed25519 private key size")
|
||||
}
|
||||
return b, nil
|
||||
// make a copy
|
||||
return append([]byte{}, b...), nil
|
||||
}
|
||||
|
||||
// PrivateKeyToBytes converts a private key to a byte slice.
|
||||
func PrivateKeyToBytes(priv PrivateKey) []byte {
|
||||
// Copy the private key to a fixed size buffer that can get allocated on the
|
||||
// caller's stack after inlining.
|
||||
var buf [PrivateKeySize]byte
|
||||
return append(buf[:0], priv...)
|
||||
}
|
||||
|
||||
// Sign signs the message with privateKey and returns a signature.
|
||||
|
||||
@@ -16,6 +16,21 @@ func TestGenerateKey(t *testing.T) {
|
||||
require.True(t, pub.Equal(priv.Public()))
|
||||
}
|
||||
|
||||
func TestBytesRoundTrip(t *testing.T) {
|
||||
pub, priv, err := ed25519.GenerateKeyPair()
|
||||
require.NoError(t, err)
|
||||
|
||||
bytes := ed25519.PublicKeyToBytes(pub)
|
||||
rtPub, err := ed25519.PublicKeyFromBytes(bytes)
|
||||
require.NoError(t, err)
|
||||
require.True(t, pub.Equal(rtPub))
|
||||
|
||||
bytes = ed25519.PrivateKeyToBytes(priv)
|
||||
rtPriv, err := ed25519.PrivateKeyFromBytes(bytes)
|
||||
require.NoError(t, err)
|
||||
require.True(t, priv.Equal(rtPriv))
|
||||
}
|
||||
|
||||
func TestMultibaseRoundTrip(t *testing.T) {
|
||||
pub, _, err := ed25519.GenerateKeyPair()
|
||||
require.NoError(t, err)
|
||||
|
||||
84
verifications/p256/key.go
Normal file
84
verifications/p256/key.go
Normal file
@@ -0,0 +1,84 @@
|
||||
package p256
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
|
||||
helpers "github.com/INFURA/go-did/verifications/internal"
|
||||
)
|
||||
|
||||
type PublicKey = *ecdsa.PublicKey
|
||||
type PrivateKey = *ecdsa.PrivateKey
|
||||
|
||||
const (
|
||||
// TODO
|
||||
PublicKeySize = 123456
|
||||
PrivateKeySize = 123456
|
||||
SignatureSize = 123456
|
||||
|
||||
MultibaseCode = uint64(0x1200)
|
||||
)
|
||||
|
||||
func GenerateKeyPair() (PublicKey, PrivateKey, error) {
|
||||
priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return priv.Public().(PublicKey), priv, nil
|
||||
}
|
||||
|
||||
// PublicKeyFromBytes converts a serialized public key to a PublicKey.
|
||||
// It errors if the slice is not the right size.
|
||||
func PublicKeyFromBytes(b []byte) (PublicKey, error) {
|
||||
if len(b) != PublicKeySize {
|
||||
return nil, fmt.Errorf("invalid P-256 public key size")
|
||||
}
|
||||
x, y := elliptic.UnmarshalCompressed(elliptic.P256(), b)
|
||||
if x == nil {
|
||||
return nil, fmt.Errorf("invalid P-256 public key")
|
||||
}
|
||||
return &ecdsa.PublicKey{Curve: elliptic.P256(), X: x, Y: y}, nil
|
||||
}
|
||||
|
||||
// PublicKeyToBytes converts a public key to a byte slice.
|
||||
func PublicKeyToBytes(pub PublicKey) (res []byte, err error) {
|
||||
defer func() {
|
||||
if rerr := recover(); rerr != nil {
|
||||
err = fmt.Errorf("recovered panic: %s", rerr)
|
||||
res = nil
|
||||
}
|
||||
}()
|
||||
return x509.MarshalPKIXPublicKey(pub)
|
||||
}
|
||||
|
||||
// PublicKeyFromMultibase decodes the public key from its Multibase form
|
||||
func PublicKeyFromMultibase(multibase string) (PublicKey, error) {
|
||||
code, bytes, err := helpers.MultibaseDecode(multibase)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if code != MultibaseCode {
|
||||
return nil, fmt.Errorf("invalid code")
|
||||
}
|
||||
return PublicKeyFromBytes(bytes)
|
||||
}
|
||||
|
||||
// PublicKeyToMultibase encodes the public key in a suitable way for publicKeyMultibase
|
||||
func PublicKeyToMultibase(pub PublicKey) string {
|
||||
bytes := elliptic.MarshalCompressed(elliptic.P256(), pub.X, pub.Y)
|
||||
return helpers.MultibaseEncode(MultibaseCode, bytes)
|
||||
}
|
||||
|
||||
// PrivateKeyFromBytes converts a serialized public key to a PrivateKey.
|
||||
// It errors if the slice is not the right size.
|
||||
func PrivateKeyFromBytes(b []byte) (PrivateKey, error) {
|
||||
if len(b) != PrivateKeySize {
|
||||
return nil, fmt.Errorf("invalid P-256 private key size")
|
||||
}
|
||||
// TODO
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
43
verifications/p256/key_test.go
Normal file
43
verifications/p256/key_test.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package p256_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/INFURA/go-did/verifications/ed25519"
|
||||
"github.com/INFURA/go-did/verifications/p256"
|
||||
)
|
||||
|
||||
func TestGenerateKey(t *testing.T) {
|
||||
pub, priv, err := p256.GenerateKeyPair()
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, pub)
|
||||
require.NotNil(t, priv)
|
||||
require.True(t, pub.Equal(priv.Public()))
|
||||
}
|
||||
|
||||
func TestBytesRoundTrip(t *testing.T) {
|
||||
pub, priv, err := p256.GenerateKeyPair()
|
||||
require.NoError(t, err)
|
||||
|
||||
bytes := p256.PublicKeyToBytes(pub)
|
||||
rtPub, err := p256.PublicKeyFromBytes(bytes)
|
||||
require.NoError(t, err)
|
||||
require.True(t, pub.Equal(rtPub))
|
||||
|
||||
bytes = p256.PrivateKeyToBytes(priv)
|
||||
rtPriv, err := p256.PrivateKeyFromBytes(bytes)
|
||||
require.NoError(t, err)
|
||||
require.True(t, priv.Equal(rtPriv))
|
||||
}
|
||||
|
||||
func TestMultibaseRoundTrip(t *testing.T) {
|
||||
pub, _, err := p256.GenerateKeyPair()
|
||||
require.NoError(t, err)
|
||||
|
||||
mb := p256.PublicKeyToMultibase(pub)
|
||||
rt, err := p256.PublicKeyFromMultibase(mb)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, pub, rt)
|
||||
}
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
// Specification: https://w3c-ccg.github.io/did-method-key/#ed25519-x25519
|
||||
|
||||
const (
|
||||
MultibaseCode = uint64(0xec)
|
||||
JsonLdContext = "https://w3id.org/security/suites/x25519-2020/v1"
|
||||
Type = "X25519KeyAgreementKey2020"
|
||||
)
|
||||
|
||||
@@ -21,6 +21,8 @@ const (
|
||||
PrivateKeySize = 32
|
||||
// SignatureSize is the size, in bytes, of signatures generated and verified by this package.
|
||||
SignatureSize = 32
|
||||
|
||||
MultibaseCode = uint64(0xec)
|
||||
)
|
||||
|
||||
func GenerateKeyPair() (PublicKey, PrivateKey, error) {
|
||||
@@ -37,6 +39,11 @@ func PublicKeyFromBytes(b []byte) (PublicKey, error) {
|
||||
return ecdh.X25519().NewPublicKey(b)
|
||||
}
|
||||
|
||||
// PublicKeyToBytes converts a public key to a byte slice.
|
||||
func PublicKeyToBytes(pub PublicKey) []byte {
|
||||
return pub.Bytes()
|
||||
}
|
||||
|
||||
// PublicKeyFromEd25519 converts an ed25519 public key to a x25519 public key.
|
||||
// It errors if the slice is not the right size.
|
||||
//
|
||||
@@ -106,7 +113,7 @@ func PublicKeyFromMultibase(multibase string) (PublicKey, error) {
|
||||
if code != MultibaseCode {
|
||||
return nil, fmt.Errorf("invalid code")
|
||||
}
|
||||
return ecdh.X25519().NewPublicKey(bytes)
|
||||
return PublicKeyFromBytes(bytes)
|
||||
}
|
||||
|
||||
// PublicKeyToMultibase encodes the public key in a suitable way for publicKeyMultibase
|
||||
@@ -114,12 +121,17 @@ func PublicKeyToMultibase(pub PublicKey) string {
|
||||
return helpers.MultibaseEncode(MultibaseCode, pub.Bytes())
|
||||
}
|
||||
|
||||
// PrivateKeyFromBytes converts a serialized public key to a PrivateKey.
|
||||
// PrivateKeyFromBytes converts a serialized private key to a PrivateKey.
|
||||
// It errors if len(privateKey) is not [PrivateKeySize].
|
||||
func PrivateKeyFromBytes(b []byte) (PrivateKey, error) {
|
||||
return ecdh.X25519().NewPrivateKey(b)
|
||||
}
|
||||
|
||||
// PrivateKeyToBytes converts a private key to a byte slice.
|
||||
func PrivateKeyToBytes(priv PrivateKey) []byte {
|
||||
return priv.Bytes()
|
||||
}
|
||||
|
||||
// PrivateKeyFromEd25519 converts an ed25519 private key to a x25519 private key.
|
||||
// It errors if the slice is not the right size.
|
||||
//
|
||||
|
||||
@@ -20,6 +20,21 @@ func TestGenerateKey(t *testing.T) {
|
||||
require.True(t, pub.Equal(priv.Public()))
|
||||
}
|
||||
|
||||
func TestBytesRoundTrip(t *testing.T) {
|
||||
pub, priv, err := x25519.GenerateKeyPair()
|
||||
require.NoError(t, err)
|
||||
|
||||
bytes := x25519.PublicKeyToBytes(pub)
|
||||
rtPub, err := x25519.PublicKeyFromBytes(bytes)
|
||||
require.NoError(t, err)
|
||||
require.True(t, pub.Equal(rtPub))
|
||||
|
||||
bytes = x25519.PrivateKeyToBytes(priv)
|
||||
rtPriv, err := x25519.PrivateKeyFromBytes(bytes)
|
||||
require.NoError(t, err)
|
||||
require.True(t, priv.Equal(rtPriv))
|
||||
}
|
||||
|
||||
func TestMultibaseRoundTrip(t *testing.T) {
|
||||
pub, _, err := x25519.GenerateKeyPair()
|
||||
require.NoError(t, err)
|
||||
|
||||
Reference in New Issue
Block a user