diff --git a/crypto/ed25519/key.go b/crypto/ed25519/key.go index ce97eb8..fa2bd7a 100644 --- a/crypto/ed25519/key.go +++ b/crypto/ed25519/key.go @@ -6,12 +6,12 @@ import ( ) const ( - // PublicKeySize is the size, in bytes, of public keys as used in this package. - PublicKeySize = ed25519.PublicKeySize - // PrivateKeySize is the size, in bytes, of private keys as used in this package. - PrivateKeySize = ed25519.PrivateKeySize - // SignatureSize is the size, in bytes, of signatures generated and verified by this package. - SignatureSize = ed25519.SignatureSize + // PublicKeyBytesSize is the size, in bytes, of public keys in raw bytes. + PublicKeyBytesSize = ed25519.PublicKeySize + // PrivateKeyBytesSize is the size, in bytes, of private keys in raw bytes. + PrivateKeyBytesSize = ed25519.PrivateKeySize + // SignatureBytesSize is the size, in bytes, of signatures in raw bytes. + SignatureBytesSize = ed25519.SignatureSize MultibaseCode = uint64(0xed) ) diff --git a/crypto/ed25519/key_test.go b/crypto/ed25519/key_test.go index 2eaa3c5..88e1cb8 100644 --- a/crypto/ed25519/key_test.go +++ b/crypto/ed25519/key_test.go @@ -17,9 +17,9 @@ var harness = helpers.TestHarness[PublicKey, PrivateKey]{ PrivateKeyFromPKCS8DER: PrivateKeyFromPKCS8DER, PrivateKeyFromPKCS8PEM: PrivateKeyFromPKCS8PEM, MultibaseCode: MultibaseCode, - PublicKeySize: PublicKeySize, - PrivateKeySize: PrivateKeySize, - SignatureSize: SignatureSize, + PublicKeyBytesSize: PublicKeyBytesSize, + PrivateKeyBytesSize: PrivateKeyBytesSize, + SignatureBytesSize: SignatureBytesSize, } func TestSuite(t *testing.T) { diff --git a/crypto/ed25519/private.go b/crypto/ed25519/private.go index 94c1dc8..7bd2aed 100644 --- a/crypto/ed25519/private.go +++ b/crypto/ed25519/private.go @@ -21,7 +21,7 @@ type PrivateKey struct { // This compact serialization format is the raw key material, without metadata or structure. // It errors if the slice is not the right size. func PrivateKeyFromBytes(b []byte) (PrivateKey, error) { - if len(b) != PrivateKeySize { + if len(b) != PrivateKeyBytesSize { return PrivateKey{}, fmt.Errorf("invalid ed25519 private key size") } // make a copy @@ -76,7 +76,7 @@ func (p PrivateKey) SignToASN1(message []byte) ([]byte, error) { func (p PrivateKey) ToBytes() []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 + var buf [PrivateKeyBytesSize]byte return append(buf[:0], p.k...) } diff --git a/crypto/ed25519/public.go b/crypto/ed25519/public.go index 9bd0be0..e0f24bc 100644 --- a/crypto/ed25519/public.go +++ b/crypto/ed25519/public.go @@ -23,7 +23,7 @@ type PublicKey struct { // This compact serialization format is the raw key material, without metadata or structure. // It errors if the slice is not the right size. func PublicKeyFromBytes(b []byte) (PublicKey, error) { - if len(b) != PublicKeySize { + if len(b) != PublicKeyBytesSize { return PublicKey{}, fmt.Errorf("invalid ed25519 public key size") } // make a copy @@ -39,7 +39,7 @@ func PublicKeyFromPublicKeyMultibase(multibase string) (PublicKey, error) { if code != MultibaseCode { return PublicKey{}, fmt.Errorf("invalid code") } - if len(bytes) != PublicKeySize { + if len(bytes) != PublicKeyBytesSize { return PublicKey{}, fmt.Errorf("invalid ed25519 public key size") } return PublicKeyFromBytes(bytes) @@ -69,7 +69,7 @@ func PublicKeyFromX509PEM(str string) (PublicKey, error) { func (p PublicKey) ToBytes() []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 + var buf [PublicKeyBytesSize]byte return append(buf[:0], p.k...) } @@ -110,7 +110,7 @@ func (p PublicKey) VerifyASN1(message, signature []byte) bool { if !s.ReadASN1BitString(&bitString) { return false } - if bitString.BitLength != SignatureSize*8 { + if bitString.BitLength != SignatureBytesSize*8 { return false } diff --git a/crypto/internal/testsuite.go b/crypto/internal/testsuite.go index 7d24a4c..6a217cc 100644 --- a/crypto/internal/testsuite.go +++ b/crypto/internal/testsuite.go @@ -29,9 +29,9 @@ type TestHarness[PubT crypto.PublicKey, PrivT crypto.PrivateKey] struct { MultibaseCode uint64 - PublicKeySize int - PrivateKeySize int - SignatureSize int + PublicKeyBytesSize int + PrivateKeyBytesSize int + SignatureBytesSize int } func TestSuite[PubT crypto.PublicKey, PrivT crypto.PrivateKey](t *testing.T, harness TestHarness[PubT, PrivT]) { @@ -108,12 +108,14 @@ func TestSuite[PubT crypto.PublicKey, PrivT crypto.PrivateKey](t *testing.T, har 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() stats.bytesPrivSize = len(bytes) rtPriv, err := harness.PrivateKeyFromBytes(bytes) require.NoError(t, err) require.True(t, priv.Equal(rtPriv)) + require.Equal(t, harness.PrivateKeyBytesSize, len(bytes)) }) t.Run("MultibaseRoundTrip", func(t *testing.T) { @@ -193,7 +195,7 @@ func TestSuite[PubT crypto.PublicKey, PrivT crypto.PrivateKey](t *testing.T, har name: "Bytes signature", signer: spriv.SignToBytes, verifier: spub.VerifyBytes, - expectedSize: harness.SignatureSize, + expectedSize: harness.SignatureBytesSize, stats: &stats.sigRawSize, }, { diff --git a/crypto/p256/key.go b/crypto/p256/key.go index 1258a44..963576f 100644 --- a/crypto/p256/key.go +++ b/crypto/p256/key.go @@ -7,10 +7,12 @@ import ( ) const ( - // TODO - PublicKeySize = 33 - PrivateKeySize = 32 - SignatureSize = 64 + // PublicKeyBytesSize is the size, in bytes, of public keys in raw bytes. + PublicKeyBytesSize = 33 + // PrivateKeyBytesSize is the size, in bytes, of private keys in raw bytes. + PrivateKeyBytesSize = 32 + // SignatureBytesSize is the size, in bytes, of signatures in raw bytes. + SignatureBytesSize = 64 MultibaseCode = uint64(0x1200) ) diff --git a/crypto/p256/key_test.go b/crypto/p256/key_test.go index b3aefea..94b5d08 100644 --- a/crypto/p256/key_test.go +++ b/crypto/p256/key_test.go @@ -17,9 +17,9 @@ var harness = helpers.TestHarness[*PublicKey, *PrivateKey]{ PrivateKeyFromPKCS8DER: PrivateKeyFromPKCS8DER, PrivateKeyFromPKCS8PEM: PrivateKeyFromPKCS8PEM, MultibaseCode: MultibaseCode, - PublicKeySize: PublicKeySize, - PrivateKeySize: PrivateKeySize, - SignatureSize: SignatureSize, + PublicKeyBytesSize: PublicKeyBytesSize, + PrivateKeyBytesSize: PrivateKeyBytesSize, + SignatureBytesSize: SignatureBytesSize, } func TestSuite(t *testing.T) { diff --git a/crypto/p256/private.go b/crypto/p256/private.go index 7e0fa9d..adf4fa3 100644 --- a/crypto/p256/private.go +++ b/crypto/p256/private.go @@ -22,7 +22,7 @@ type PrivateKey ecdsa.PrivateKey // This compact serialization format is the raw key material, without metadata or structure. // It errors if the slice is not the right size. func PrivateKeyFromBytes(b []byte) (*PrivateKey, error) { - if len(b) != PrivateKeySize { + if len(b) != PrivateKeyBytesSize { return nil, fmt.Errorf("invalid P-256 private key size") } @@ -73,7 +73,7 @@ func (p *PrivateKey) Public() crypto.PublicKey { func (p *PrivateKey) ToBytes() []byte { // fixed size buffer that can get allocated on the caller's stack after inlining. - var buf [PrivateKeySize]byte + var buf [PrivateKeyBytesSize]byte ((*ecdsa.PrivateKey)(p)).D.FillBytes(buf[:]) return buf[:] } diff --git a/crypto/p256/public.go b/crypto/p256/public.go index 0ee4bd2..e794970 100644 --- a/crypto/p256/public.go +++ b/crypto/p256/public.go @@ -21,7 +21,7 @@ type PublicKey ecdsa.PublicKey // This compact serialization format is the raw key material, without metadata or structure. // It errors if the slice is not the right size. func PublicKeyFromBytes(b []byte) (*PublicKey, error) { - if len(b) != PublicKeySize { + if len(b) != PublicKeyBytesSize { return nil, fmt.Errorf("invalid P-256 public key size") } x, y := elliptic.UnmarshalCompressed(elliptic.P256(), b) @@ -103,7 +103,7 @@ func (p *PublicKey) ToX509PEM() string { */ func (p *PublicKey) VerifyBytes(message, signature []byte) bool { - if len(signature) != SignatureSize { + if len(signature) != SignatureBytesSize { return false } diff --git a/crypto/x25519/key.go b/crypto/x25519/key.go index 7d03a8f..95e7964 100644 --- a/crypto/x25519/key.go +++ b/crypto/x25519/key.go @@ -6,12 +6,10 @@ import ( ) const ( - // PublicKeySize is the size, in bytes, of public keys as used in this package. - PublicKeySize = 32 - // PrivateKeySize is the size, in bytes, of private keys as used in this package. - PrivateKeySize = 32 - // SignatureSize is the size, in bytes, of signatures generated and verified by this package. - SignatureSize = 32 + // PublicKeyBytesSize is the size, in bytes, of public keys in raw bytes. + PublicKeyBytesSize = 32 + // PrivateKeyBytesSize is the size, in bytes, of private keys in raw bytes. + PrivateKeyBytesSize = 32 MultibaseCode = uint64(0xec) ) diff --git a/crypto/x25519/key_test.go b/crypto/x25519/key_test.go index 6a7bcba..c8c7f20 100644 --- a/crypto/x25519/key_test.go +++ b/crypto/x25519/key_test.go @@ -20,9 +20,9 @@ var harness = helpers.TestHarness[*PublicKey, *PrivateKey]{ PrivateKeyFromPKCS8DER: PrivateKeyFromPKCS8DER, PrivateKeyFromPKCS8PEM: PrivateKeyFromPKCS8PEM, MultibaseCode: MultibaseCode, - PublicKeySize: PublicKeySize, - PrivateKeySize: PrivateKeySize, - SignatureSize: SignatureSize, + PublicKeyBytesSize: PublicKeyBytesSize, + PrivateKeyBytesSize: PrivateKeyBytesSize, + SignatureBytesSize: -1, } func TestSuite(t *testing.T) { diff --git a/crypto/x25519/private.go b/crypto/x25519/private.go index 5aaf1cd..e18cc93 100644 --- a/crypto/x25519/private.go +++ b/crypto/x25519/private.go @@ -17,7 +17,7 @@ type PrivateKey ecdh.PrivateKey // PrivateKeyFromBytes converts a serialized private key to a PrivateKey. // This compact serialization format is the raw key material, without metadata or structure. -// It errors if len(privateKey) is not [PrivateKeySize]. +// It errors if len(privateKey) is not [PrivateKeyBytesSize]. func PrivateKeyFromBytes(b []byte) (*PrivateKey, error) { // this already check the size of b priv, err := ecdh.X25519().NewPrivateKey(b) diff --git a/crypto/x25519/public.go b/crypto/x25519/public.go index 8946786..62da6bc 100644 --- a/crypto/x25519/public.go +++ b/crypto/x25519/public.go @@ -40,7 +40,7 @@ func PublicKeyFromEd25519(pub ed25519.PublicKey) (*PublicKey, error) { // Clear the sign bit (MSB of last byte) // This is because ed25519 serialize as bytes with 255 bit for Y, and one bit for the sign. // We only want Y, and the sign is irrelevant for the conversion. - pubBytes[ed25519.PublicKeySize-1] &= 0x7F + pubBytes[ed25519.PublicKeyBytesSize-1] &= 0x7F // ed25519 are little-endian, but big.Int expects big-endian // See https://www.rfc-editor.org/rfc/rfc8032 @@ -75,8 +75,8 @@ func PublicKeyFromEd25519(pub ed25519.PublicKey) (*PublicKey, error) { // make sure we get 32 bytes, pad if necessary uBytes := u.Bytes() - res := make([]byte, PublicKeySize) - copy(res[PublicKeySize-len(uBytes):], uBytes) + res := make([]byte, PublicKeyBytesSize) + copy(res[PublicKeyBytesSize-len(uBytes):], uBytes) // x25519 are little-endian, but big.Int gives us big-endian. // See https://www.ietf.org/rfc/rfc7748.txt diff --git a/design.md b/design.md index e28af8b..e0cd3f3 100644 --- a/design.md +++ b/design.md @@ -8,18 +8,14 @@ General: - code should be decently tested and profiled - specifications and test vectors used MUST be referenced in a comment - if something differs from a specification, it should be documented and explained -- generally, follow the existing structure of did:key, ed25519 or x25519 - consider how an average user will read and understand your code, rather than how you read it DIDs: - DID and document structs are minimal/lightweight and get expanded into the relevant interface (DID, Document). -- They get flattened when marshalling into JSON but not otherwise. DID Documents are for out-of-process communication, not the normal path. -- this library should also have a generic Document struct, to accept arbitrary DID documents in JSON format +- They get expanded when marshalling into JSON but not otherwise. DID Documents are for out-of-process communication, not the normal path. Crypto: -- each type of crypto handling should be self-contained in the relevant verification method package (e.g. everything ed25519 is in /verifications/ed25519). This includes the JSON (un)marshalling of the VerificationMethod. - a user of the library shouldn't have to know or care about the underlying crypto to use it "server side" (signature verification, key agreement). Thus, it should be abstracted behind the VerificationMethod interfaces. -- for the same reason, each of those packages should expose or alias the relevant types (ex: PublicKey/PrivateKey in /verifications/ed25519) to expose a regular way to work with crypto primitives, as well as allowing behind the scene upgrades. - for each, we should expose some generally useful functions to handle private keys (generation, marshalling...) ## Minimal target features