Skip to content

Commit

Permalink
feat: add BBS and NISTP did key creation
Browse files Browse the repository at this point in the history
This change introduces NIST P ECDSA and BBS did:key creation
And did:key resolution for ECDSA keys.

closes hyperledger-archives#2319

Signed-off-by: Baha Shaaban <[email protected]>
  • Loading branch information
Baha Shaaban authored and sudeshrshetty committed Oct 14, 2021
1 parent 35e2c7e commit 07f0d23
Show file tree
Hide file tree
Showing 8 changed files with 624 additions and 65 deletions.
5 changes: 3 additions & 2 deletions pkg/doc/util/jwkkid/kid_creator.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func CreateKID(keyBytes []byte, kt kms.KeyType) (string, error) {
return bbsKID, nil
}

jwk, err := buildJWK(keyBytes, kt)
jwk, err := BuildJWK(keyBytes, kt)
if err != nil {
return "", fmt.Errorf("createKID: failed to build jwk: %w", err)
}
Expand All @@ -75,7 +75,8 @@ func CreateKID(keyBytes []byte, kt kms.KeyType) (string, error) {
return base64.RawURLEncoding.EncodeToString(tp), nil
}

func buildJWK(keyBytes []byte, kt kms.KeyType) (*jose.JWK, error) {
// BuildJWK builds a go jose JWK from keyBytes with key type kt.
func BuildJWK(keyBytes []byte, kt kms.KeyType) (*jose.JWK, error) {
var (
jwk *jose.JWK
err error
Expand Down
30 changes: 25 additions & 5 deletions pkg/vdr/fingerprint/fingerprint.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,30 @@ import (
)

const (
// X25519PubKeyMultiCodec for Curve25519 public key in multicodec table.
// source: https://github.com/multiformats/multicodec/blob/master/table.csv.
ed25519pub = 0xed // Ed25519 public key in multicodec table
X25519PubKeyMultiCodec = 0xec
// ED25519PubKeyMultiCodec for Ed25519 public key in multicodec table.
ED25519PubKeyMultiCodec = 0xed
// BLS12381g2PubKeyMultiCodec for BLS12-381 G2 public key in multicodec table.
BLS12381g2PubKeyMultiCodec = 0xeb
// P256PubKeyMultiCodec for NIST P-256 public key in multicodec table.
P256PubKeyMultiCodec = 0x1200
// P384PubKeyMultiCodec for NIST P-384 public key in multicodec table.
P384PubKeyMultiCodec = 0x1201
// P521PubKeyMultiCodec for NIST P-521 public key in multicodec table.
P521PubKeyMultiCodec = 0x1202
)

// CreateDIDKey creates a did:key ID using the multicodec key fingerprint as per the did:key format spec found at:
// https://w3c-ccg.github.io/did-method-key/#format.
// CreateDIDKey calls CreateDIDKeyByCode with Ed25519 key code.
func CreateDIDKey(pubKey []byte) (string, string) {
methodID := KeyFingerprint(ed25519pub, pubKey)
return CreateDIDKeyByCode(ED25519PubKeyMultiCodec, pubKey)
}

// CreateDIDKeyByCode creates a did:key ID using the multicodec key fingerprint as per the did:key format spec found at:
// https://w3c-ccg.github.io/did-method-key/#format.
func CreateDIDKeyByCode(code uint64, pubKey []byte) (string, string) {
methodID := KeyFingerprint(code, pubKey)
didKey := fmt.Sprintf("did:key:%s", methodID)
keyID := fmt.Sprintf("%s#%s", didKey, methodID)

Expand Down Expand Up @@ -76,6 +92,9 @@ func PubKeyFromFingerprint(fingerprint string) ([]byte, uint64, error) {
}

// PubKeyFromDIDKey parses the did:key DID and returns the key's raw value.
// note: for NIST P ECDSA keys, the raw value does not have the compression point.
// In order to use elliptic.Unmarshal() with the raw value, the uncompressed point ([]byte{4}) must be prepended.
// see https://github.com/golang/go/blob/master/src/crypto/elliptic/elliptic.go#L319.
func PubKeyFromDIDKey(didKey string) ([]byte, error) {
id, err := did.Parse(didKey)
if err != nil {
Expand All @@ -95,7 +114,8 @@ func PubKeyFromDIDKey(didKey string) ([]byte, error) {
}

switch code {
case ed25519pub:
case X25519PubKeyMultiCodec, ED25519PubKeyMultiCodec, BLS12381g2PubKeyMultiCodec,
P256PubKeyMultiCodec, P384PubKeyMultiCodec, P521PubKeyMultiCodec:
break
default:
return nil, fmt.Errorf("unsupported key multicodec code [0x%x]", code)
Expand Down
107 changes: 92 additions & 15 deletions pkg/vdr/fingerprint/fingerprint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,98 @@ import (
)

func TestCreateDIDKey(t *testing.T) {
pubKeyBase58 := "B12NYF8RrR3h41TDCTJojY59usg3mbtbjnFs7Eud1Y6u"
expectedDIDKey := "did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH"
expectedDIDKeyID := "did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH#z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH" //nolint:lll
const (
edPubKeyBase58 = "B12NYF8RrR3h41TDCTJojY59usg3mbtbjnFs7Eud1Y6u"
edExpectedDIDKey = "did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH"
edExpectedDIDKeyID = "did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH#z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH" //nolint:lll

t.Run("test CreateDIDKey", func(t *testing.T) {
didKey, keyID := CreateDIDKey(base58.Decode(pubKeyBase58))
bbsPubKeyBase58 = "25EEkQtcLKsEzQ6JTo9cg4W7NHpaurn4Wg6LaNPFq6JQXnrP91SDviUz7KrJVMJd76CtAZFsRLYzvgX2JGxo2ccUHtuHk7ELCWwrkBDfrXCFVfqJKDootee9iVaF6NpdJtBE" //nolint:lll
bbsExpectedDIDKey = "did:key:zUC7K4ndUaGZgV7Cp2yJy6JtMoUHY6u7tkcSYUvPrEidqBmLCTLmi6d5WvwnUqejscAkERJ3bfjEiSYtdPkRSE8kSa11hFBr4sTgnbZ95SJj19PN2jdvJjyzpSZgxkyyxNnBNnY" //nolint:lll
bbsExpectedDIDKeyID = "did:key:zUC7K4ndUaGZgV7Cp2yJy6JtMoUHY6u7tkcSYUvPrEidqBmLCTLmi6d5WvwnUqejscAkERJ3bfjEiSYtdPkRSE8kSa11hFBr4sTgnbZ95SJj19PN2jdvJjyzpSZgxkyyxNnBNnY#zUC7K4ndUaGZgV7Cp2yJy6JtMoUHY6u7tkcSYUvPrEidqBmLCTLmi6d5WvwnUqejscAkERJ3bfjEiSYtdPkRSE8kSa11hFBr4sTgnbZ95SJj19PN2jdvJjyzpSZgxkyyxNnBNnY" //nolint:lll

require.Equal(t, didKey, expectedDIDKey)
require.Equal(t, keyID, expectedDIDKeyID)
})
ecP256PubKeyBase58 = "3YRwdf868zp2t8c4oT4XdYfCihMsfR1zrVYyXS5SS4FwQ7wftDfoY5nohvhdgSk9LxyfzjTLzffJPmHgFBqizX9v"
ecP256ExpectedDIDKey = "did:key:zrurwcJZss4ruepVNu1H3xmSirvNbzgBk9qrCktB6kaewXnJAhYWwtP3bxACqBpzjZdN7TyHNzzGGSSH5qvZsSDir9z" //nolint:lll
ecP256ExpectedDIDKeyID = "did:key:zrurwcJZss4ruepVNu1H3xmSirvNbzgBk9qrCktB6kaewXnJAhYWwtP3bxACqBpzjZdN7TyHNzzGGSSH5qvZsSDir9z#zrurwcJZss4ruepVNu1H3xmSirvNbzgBk9qrCktB6kaewXnJAhYWwtP3bxACqBpzjZdN7TyHNzzGGSSH5qvZsSDir9z" //nolint:lll

t.Run("test PubKeyFromFingerprint success", func(t *testing.T) {
pubKey, code, err := PubKeyFromFingerprint(strings.Split(expectedDIDKeyID, "#")[1])
require.Equal(t, uint64(ed25519pub), code)
require.NoError(t, err)
ecP384PubKeyBase58 = "tAjHMcvoBXs3BSihDV85trHmstc3V3vTP7o2Si72eCWdVzeGgGvRd8h5neHEbqSL989h53yNj7M7wHckB2bKpGKQjnPDD7NphDa9nUUBggCB6aCWterfdXbH5DfWPZx5oXU" //nolint:lll
ecP384ExpectedDIDKey = "did:key:zFwfeyrSyWdksRYykTGGtagWazFB5zS4CjQcxDMQSNmCTQB5QMqokx2VJz4vBB2hN1nUrYDTuYq3kd1BM5cUCfFD4awiNuzEBuoy6rZZTMCsZsdvWkDXY6832qcAnzE7YGw43KU" //nolint:lll
ecP384ExpectedDIDKeyID = "did:key:zFwfeyrSyWdksRYykTGGtagWazFB5zS4CjQcxDMQSNmCTQB5QMqokx2VJz4vBB2hN1nUrYDTuYq3kd1BM5cUCfFD4awiNuzEBuoy6rZZTMCsZsdvWkDXY6832qcAnzE7YGw43KU#zFwfeyrSyWdksRYykTGGtagWazFB5zS4CjQcxDMQSNmCTQB5QMqokx2VJz4vBB2hN1nUrYDTuYq3kd1BM5cUCfFD4awiNuzEBuoy6rZZTMCsZsdvWkDXY6832qcAnzE7YGw43KU" //nolint:lll

require.Equal(t, base58.Encode(pubKey), pubKeyBase58)
})
ecP521PubKeyBase58 = "mTQ9pPr2wkKdiTHhVG7xmLwyJ5mrgq1FKcHFz2XJprs4zAPtjXWFiEz6vsscbseSEzGdjAVzcUhwdodT5cbrRjQqFdz8d1yYVqMHXsVCdCUrmWNNHcZLJeYCn1dCtQX9YRVdDFfnzczKFxDXe9HusLqBWTobbxVvdj9cTi7rSWVznP5Emfo" //nolint:lll
ecP521ExpectedDIDKey = "did:key:zWGhj2NTyCiehTPioanYSuSrfB7RJKwZj6bBUDNojfGEA21nr5NcBsHme7hcVSbptpWKarJpTcw814J3X8gVU9gZmeKM27JpGA5wNMzt8JZwjDyf8EzCJg5ve5GR2Xfm7d9Djp73V7s35KPeKe7VHMzmL8aPw4XBniNej5sXapPFoBs5R8m195HK" //nolint:lll
ecP521ExpectedDIDKeyID = "did:key:zWGhj2NTyCiehTPioanYSuSrfB7RJKwZj6bBUDNojfGEA21nr5NcBsHme7hcVSbptpWKarJpTcw814J3X8gVU9gZmeKM27JpGA5wNMzt8JZwjDyf8EzCJg5ve5GR2Xfm7d9Djp73V7s35KPeKe7VHMzmL8aPw4XBniNej5sXapPFoBs5R8m195HK#zWGhj2NTyCiehTPioanYSuSrfB7RJKwZj6bBUDNojfGEA21nr5NcBsHme7hcVSbptpWKarJpTcw814J3X8gVU9gZmeKM27JpGA5wNMzt8JZwjDyf8EzCJg5ve5GR2Xfm7d9Djp73V7s35KPeKe7VHMzmL8aPw4XBniNej5sXapPFoBs5R8m195HK" //nolint:lll
)

tests := []struct {
name string
keyB58 string
DIDKey string
DIDKeyID string
keyCode uint64
}{
{
name: "test ED25519",
keyB58: edPubKeyBase58,
DIDKey: edExpectedDIDKey,
DIDKeyID: edExpectedDIDKeyID,
keyCode: ED25519PubKeyMultiCodec,
},
{
name: "test BBS+",
keyB58: bbsPubKeyBase58,
DIDKey: bbsExpectedDIDKey,
DIDKeyID: bbsExpectedDIDKeyID,
keyCode: BLS12381g2PubKeyMultiCodec,
},
{
name: "test P-256",
keyB58: ecP256PubKeyBase58,
DIDKey: ecP256ExpectedDIDKey,
DIDKeyID: ecP256ExpectedDIDKeyID,
keyCode: P256PubKeyMultiCodec,
},
{
name: "test P-384",
keyB58: ecP384PubKeyBase58,
DIDKey: ecP384ExpectedDIDKey,
DIDKeyID: ecP384ExpectedDIDKeyID,
keyCode: P384PubKeyMultiCodec,
},
{
name: "test P-521",
keyB58: ecP521PubKeyBase58,
DIDKey: ecP521ExpectedDIDKey,
DIDKeyID: ecP521ExpectedDIDKeyID,
keyCode: P521PubKeyMultiCodec,
},
}

for _, test := range tests {
tc := test
t.Run(tc.name+" CreateDIDKey", func(t *testing.T) {
didKey, keyID := CreateDIDKeyByCode(tc.keyCode, base58.Decode(tc.keyB58))

require.Equal(t, didKey, tc.DIDKey)
require.Equal(t, keyID, tc.DIDKeyID)
})

t.Run(tc.name+" PubKeyFromFingerprint success", func(t *testing.T) {
pubKey, code, err := PubKeyFromFingerprint(strings.Split(tc.DIDKeyID, "#")[1])
require.Equal(t, tc.keyCode, code)
require.NoError(t, err)

require.Equal(t, base58.Encode(pubKey), tc.keyB58)
})

t.Run(tc.name+" PubKeyFromDIDKey", func(t *testing.T) {
pubKey, err := PubKeyFromDIDKey(tc.DIDKey)
require.Equal(t, tc.keyB58, base58.Encode(pubKey))
require.NoError(t, err)
})
}

t.Run("test PubKeyFromFingerprint fail", func(t *testing.T) {
badDIDKeyID := "AB" + strings.Split(expectedDIDKeyID, "#")[1][2:]
badDIDKeyID := "AB" + strings.Split(edExpectedDIDKeyID, "#")[1][2:]

_, _, err := PubKeyFromFingerprint(badDIDKeyID)
require.EqualError(t, err, "unknown key encoding")
Expand All @@ -54,8 +125,14 @@ func TestDIDKeyEd25519(t *testing.T) {
const (
k1 = "did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH"
k1Base58 = "B12NYF8RrR3h41TDCTJojY59usg3mbtbjnFs7Eud1Y6u"
k1KeyID = "did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH#z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH" //nolint:lll
)

didKey, keyID := CreateDIDKey(base58.Decode(k1Base58))

require.Equal(t, didKey, k1)
require.Equal(t, keyID, k1KeyID)

pubKey, err := PubKeyFromDIDKey(k1)
require.Equal(t, k1Base58, base58.Encode(pubKey))
require.NoError(t, err)
Expand Down
Loading

0 comments on commit 07f0d23

Please sign in to comment.