Skip to content

Commit

Permalink
Fix csigner for CIP30
Browse files Browse the repository at this point in the history
* remove internal implementation of ed25519 and edwards25519 using more
  official and maintained packages
* added support for ed25519 extended just for signing
* refactor cose pkg for ed25519 extended implementation
  • Loading branch information
safanaj committed Nov 9, 2023
1 parent d9d969a commit f18d320
Show file tree
Hide file tree
Showing 8 changed files with 255 additions and 200 deletions.
7 changes: 5 additions & 2 deletions cli/csigner/cmd/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,26 +79,29 @@ var signCmd = &cobra.Command{
if err != nil {
return fmt.Errorf("invalid private key: %v", err)
}
signer, err := cose.NewSignerFromCOSEKey(cosePrvKey)
signer, err := cose.NewExtendedSignerFromCOSEKey(cosePrvKey)
if err != nil {
return fmt.Errorf("invalid private key: %v", err)
}
outPubKeyBytes, err := cosePubKey.MarshalCBOR()
if err != nil {
return fmt.Errorf("invalid private key: %v", err)
}
msgToSign := cose.NewCOSESign1MessageWithPayload(data, kid)
_ = kid
msgToSign := cose.NewCOSESign1MessageWithPayload(data, nil /* kid */)
err = msgToSign.Sign(nil, nil, signer)
if err != nil {
return fmt.Errorf("unable to sign: %v", err)
}
sigBytes, rerr = msgToSign.MarshalCBOR()
outPubKey = hex.EncodeToString(outPubKeyBytes)

} else {
prvKey := crypto.PrvKey(prvKeyBytes)
sigBytes = prvKey.Sign([]byte(data))
outPubKey = prvKey.PubKey().String()
}

outSignature = hex.EncodeToString(sigBytes)
if rerr == nil {
if !outJson {
Expand Down
7 changes: 1 addition & 6 deletions cli/csigner/cmd/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ func getPublicKey(cmd *cobra.Command) ([]byte, bool, error) {
if vrfVKeyCborHex != "" {
useSodium = true
libsodium.Initialize_libsodium()
// vrfVKeyData := libsodium.GetVrfVKeyDataFromCborHex(vrfVKeyCborHex)
vrfVKeyData, err := cardano.GetBytesFromCBORHex(vrfVKeyCborHex)
if err != nil {
return nil, useSodium, err
Expand Down Expand Up @@ -64,7 +63,6 @@ func getPublicKey(cmd *cobra.Command) ([]byte, bool, error) {
if strings.HasPrefix(m["type"], "VrfVerificationKey_") {
useSodium = true
libsodium.Initialize_libsodium()
// vrfVKeyData := libsodium.GetVrfVKeyDataFromCborHex(m["cborHex"])
vrfVKeyData, err := cardano.GetBytesFromCBORHex(vrfVKeyCborHex)
if err != nil {
return nil, useSodium, err
Expand All @@ -73,7 +71,6 @@ func getPublicKey(cmd *cobra.Command) ([]byte, bool, error) {
}

cborData, err := hex.DecodeString(m["cborHex"])
// pubkeyData := make([]byte, 32)
var pubkeyData []byte
if err = cbor.Unmarshal(cborData, &pubkeyData); err != nil {
return nil, useSodium, err
Expand Down Expand Up @@ -104,7 +101,6 @@ func getPrivateKey(cmd *cobra.Command) ([]byte, bool, error) {
if vrfSKeyCborHex != "" {
useSodium = true
libsodium.Initialize_libsodium()
// vrfSKeyData := libsodium.GetVrfSKeyDataFromCborHex(vrfSKeyCborHex)
vrfSKeyData, err := cardano.GetBytesFromCBORHex(vrfSKeyCborHex)
if err != nil {
return nil, useSodium, err
Expand Down Expand Up @@ -144,7 +140,6 @@ func getPrivateKey(cmd *cobra.Command) ([]byte, bool, error) {
if strings.HasPrefix(m["type"], "VrfSigningKey_") {
useSodium = true
libsodium.Initialize_libsodium()
// vrfSKeyData := libsodium.GetVrfSKeyDataFromCborHex(m["cborHex"])
vrfSKeyData, err := cardano.GetBytesFromCBORHex(m["cborHex"])
if err != nil {
return nil, useSodium, err
Expand All @@ -153,7 +148,7 @@ func getPrivateKey(cmd *cobra.Command) ([]byte, bool, error) {
}

cborData, err := hex.DecodeString(m["cborHex"])
prvkeyData := make([]byte, 64)
var prvkeyData []byte
if err = cbor.Unmarshal(cborData, &prvkeyData); err != nil {
return nil, useSodium, err
}
Expand Down
14 changes: 10 additions & 4 deletions cli/csigner/cmd/verify.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package cmd

import (
"bytes"
"encoding/hex"
"fmt"

coselib "github.com/veraison/go-cose"

"github.com/safanaj/cardano-go/cose"
"github.com/safanaj/cardano-go/crypto"
"github.com/safanaj/cardano-go/libsodium"
"github.com/spf13/cobra"
Expand All @@ -15,7 +19,7 @@ var verifyCmd = &cobra.Command{
Short: "Verify a signature of a message using a public key",
RunE: func(cmd *cobra.Command, args []string) error {
// useCIP8, _ := cmd.Flags().GetBool("cip8")
// useCIP30, _ := cmd.Flags().GetBool("cip30")
useCIP30, _ := cmd.Flags().GetBool("cip30")
useCIP22, _ := cmd.Flags().GetBool("cip22")
data, _ := cmd.Flags().GetString("data")
nonce, _ := cmd.Flags().GetString("nonce")
Expand Down Expand Up @@ -56,9 +60,13 @@ var verifyCmd = &cobra.Command{

dataHashBytes := blake2b.Sum256(seedData)
_, err = libsodium.CryptoVrfVerify(pubKeyBytes, sigBytes, dataHashBytes[:])
} else if useCIP30 {

_ = bytes.Equal
_ = coselib.HeaderLabelKeyID
err = cose.VerifyFromCBORHex(sig, hex.EncodeToString(pubKeyBytes))
} else {
pubKey := crypto.PubKey(pubKeyBytes)
// if pubKey.Verify([]byte(dataHex), sigBytes) {
if pubKey.Verify([]byte(data), sigBytes) {
err = nil
} else {
Expand All @@ -68,8 +76,6 @@ var verifyCmd = &cobra.Command{

if err == nil {
fmt.Println("success, signature verified")
// } else {
// fmt.Printf("failure, error: %v\n", err)
}
return err
},
Expand Down
201 changes: 82 additions & 119 deletions cose/cip30.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cose

import (
cryptolib "crypto"
"crypto/ed25519"
"encoding/hex"
"fmt"
Expand Down Expand Up @@ -72,27 +73,32 @@ func NewCOSEKeyFromBytes(key []byte) (*COSEKey, error) {
Crv: uint64(6),
Kty: uint64(1),
Alg: int64(cose.AlgorithmEd25519),
Key: cbor.NewByteString(key),
}
copy(coseKey.Key.Bytes(), key)

var (
keyId []byte
err error
)
if len(key) == ed25519.PublicKeySize {
keyId, err = crypto.PubKey(key).Hash()
if err != nil {
return nil, err
}
} else {
keyId, err = crypto.PrvKey(key).PubKey().Hash()
if err != nil {
return nil, err
}
}
if keyId != nil {
copy(coseKey.Kid.Bytes(), keyId)
}

// if len(key) == ed25519.PublicKeySize {
// keyId, err = crypto.PubKey(key).Hash()
// if err != nil {
// return nil, err
// }
// } else {
// keyId, err = crypto.PrvKey(key).PubKey().Hash()
// if err != nil {
// return nil, err
// }
// }
// if keyId != nil {
// // copy(coseKey.Kid.Bytes(), keyId)
// coseKey.Kid = cbor.NewByteString(keyId)
// }
_ = keyId
_ = err

return coseKey, nil
}

Expand Down Expand Up @@ -157,25 +163,38 @@ func NewCOSESign1MessageWithPayload(payload string, kid []byte) *COSESign1Messag
return &COSESign1Message{sign1msg}
}

func NewSignerFromCOSEKey(key *COSEKey) (cose.Signer, error) {
// //////////////////////////////////////////////////////////////
// standard and extended hook to create a signer from COSEKey
func ed25519_NewSignerFunc(key *COSEKey) cryptolib.Signer {
return crypto.PrvKey(key.Key.Bytes()).PrivateKey()
}
func ed25519e_NewSignerFunc(key *COSEKey) cryptolib.Signer {
return crypto.PrvKey(key.Key.Bytes()).ExtendedEd25519Signer()
}

// //////////////////////////////////////////////////////////////
// generic signer factory

func newSignerFromKey(key *COSEKey, doNewSigner func(key *COSEKey) cryptolib.Signer) (cose.Signer, error) {
if len(key.Key.Bytes()) != ed25519.PrivateKeySize {
return nil, fmt.Errorf("key is wrong size (expected: %d): %d", ed25519.PrivateKeySize, len(key.Key.Bytes()))
}
if cose.Algorithm(key.Alg) != cose.AlgorithmEd25519 {
return nil, fmt.Errorf("alg is wrong, not Ed25519 (value %v): %v", cose.AlgorithmEd25519, cose.Algorithm(key.Alg))
}
return cose.NewSigner(cose.AlgorithmEd25519, ed25519.PrivateKey(key.Key.Bytes()))
return cose.NewSigner(cose.AlgorithmEd25519, doNewSigner(key))
}
func NewSignerFromCBORHex(cborHex string) (cose.Signer, error) {

func newSignerFromCBORHex(cborHex string, doNewSigner func(key *COSEKey) cryptolib.Signer) (cose.Signer, error) {
key, err := NewCOSEKeyFromCBORHex(cborHex)
if err != nil {
return nil, err
}
return NewSignerFromCOSEKey(key)
return newSignerFromKey(key, doNewSigner)
}

func SignPayloadWithKeyFromCBORHex(payload, key string) (string, error) {
signer, err := NewSignerFromCBORHex(key)
func signPayloadWithKeyFromCBORHex(payload, key string, doNewSigner func(key *COSEKey) cryptolib.Signer) (string, error) {
signer, err := newSignerFromCBORHex(key, doNewSigner)
if err != nil {
return "", err
}
Expand All @@ -190,7 +209,7 @@ func SignPayloadWithKeyFromCBORHex(payload, key string) (string, error) {
return hex.EncodeToString(cborBytes), nil
}

func SignWithKey(payload, key []byte) (string, error) {
func signWithKey(payload, key []byte, doNewSigner func(key *COSEKey) cryptolib.Signer) (string, error) {
if len(key) != ed25519.PrivateKeySize {
return "", fmt.Errorf("key is wrong size (expected: %d): %d", ed25519.PrivateKeySize, len(key))
}
Expand All @@ -200,10 +219,8 @@ func SignWithKey(payload, key []byte) (string, error) {
Alg: int64(cose.AlgorithmEd25519),
}
copy(coseKey.Key.Bytes(), key)
// keyId := ed25519.PrivateKey(key).prvKey.Public().(ed25519.PublicKey) // should be used as key id
// copy(coseKey.Kid, keyId)

signer, err := NewSignerFromCOSEKey(coseKey)
signer, err := newSignerFromKey(coseKey, doNewSigner)
if err != nil {
return "", err
}
Expand All @@ -219,6 +236,45 @@ func SignWithKey(payload, key []byte) (string, error) {
return hex.EncodeToString(cborBytes), nil
}

////////////////////////////////////////////////////////////////
// ed25519 signer

func NewSignerFromCOSEKey(key *COSEKey) (cose.Signer, error) {
return newSignerFromKey(key, ed25519_NewSignerFunc)
}
func NewSignerFromCBORHex(cborHex string) (cose.Signer, error) {
return newSignerFromCBORHex(cborHex, ed25519_NewSignerFunc)
}

func SignPayloadWithKeyFromCBORHex(payload, key string) (string, error) {
return signPayloadWithKeyFromCBORHex(payload, key, ed25519_NewSignerFunc)
}

func SignWithKey(payload, key []byte) (string, error) {
return signWithKey(payload, key, ed25519_NewSignerFunc)
}

// //////////////////////////////////////////////////////////////
// extended signer (ed25519e)
func NewExtendedSignerFromCOSEKey(key *COSEKey) (cose.Signer, error) {
return newSignerFromKey(key, ed25519e_NewSignerFunc)

}
func NewExtendedSignerFromCBORHex(cborHex string) (cose.Signer, error) {
return newSignerFromCBORHex(cborHex, ed25519e_NewSignerFunc)
}

func SignExtendedPayloadWithKeyFromCBORHex(payload, key string) (string, error) {
return signPayloadWithKeyFromCBORHex(payload, key, ed25519e_NewSignerFunc)
}

func SignExtendedWithKey(payload, key []byte) (string, error) {
return signWithKey(payload, key, ed25519e_NewSignerFunc)
}

////////////////////////////////////////////////////////////////
// verifier

func NewVerifierFromCOSEKey(key *COSEKey) (cose.Verifier, error) {
if len(key.Key.Bytes()) != ed25519.PublicKeySize {
return nil, fmt.Errorf("key is wrong size (expected: %d): %d", ed25519.PublicKeySize, len(key.Key.Bytes()))
Expand All @@ -245,98 +301,5 @@ func VerifyFromCBORHex(signature, key string) error {
if err != nil {
return err
}
return msgToVerify.Sign1Message.Verify(nil, verifier)
return msgToVerify.Verify(nil, verifier)
}

////////////////////////////////////////////////////////////////

// const (
// kCrvKey int64 = -1
// kKeyKey int64 = -2
// kKtyKey uint64 = 1
// kKidKey uint64 = 2
// kAlgKey uint64 = 3
// )

// func (k *COSEKey) UnmarshalCBOR_viaMap(data []byte) error {
// var rck map[any]any
// err := cbor.Unmarshal(data, &rck)
// if err != nil {
// return err
// }
// if vI, ok := rck[kCrvKey]; !ok {
// return fmt.Errorf("crv key missing")
// } else {
// if v, ok := vI.(uint64); !ok {
// return fmt.Errorf("crv key value is not a uint64: %T", vI)
// } else if v != uint64(6) {
// return fmt.Errorf("crv key is not Ed25519 (value 6): %v", v)
// } else {
// k.Crv = v
// }
// }

// if vI, ok := rck[kKeyKey]; !ok {
// return fmt.Errorf("key key missing")
// } else {
// if v, ok := vI.([]byte); !ok {
// return fmt.Errorf("key key value is not a []byte: %T", vI)
// } else {
// if len(v) != ed25519.PublicKeySize && len(v) != ed25519.PrivateKeySize {
// return fmt.Errorf("key is wrong size (expected %d or %d): %d", ed25519.PublicKeySize, ed25519.PrivateKeySize, len(v))
// } else {
// k.Key = make([]byte, len(v))
// copy(k.Key, v)
// }
// }
// }

// if vI, ok := rck[kKtyKey]; !ok {
// return fmt.Errorf("kty key missing")
// } else {
// if v, ok := vI.(uint64); !ok {
// return fmt.Errorf("kty key value is not a uint64: %T", vI)
// } else if v != uint64(1) {
// return fmt.Errorf("kty key is not OKP (value 1): %v", v)
// } else {
// k.Kty = v
// }
// }

// if vI, ok := rck[kAlgKey]; !ok {
// return fmt.Errorf("alg key missing")
// } else {
// if v, ok := vI.(int64); !ok {
// return fmt.Errorf("alg key value is not a int64: %T", vI)
// } else if cose.Algorithm(v) != cose.AlgorithmEd25519 {
// return fmt.Errorf("alg is wrong, not Ed25519 (value %v): %v", cose.AlgorithmEd25519, cose.Algorithm(v))
// } else {
// k.Alg = v
// }
// }

// if vI, ok := rck[kKidKey]; ok {
// if v, ok := vI.([]byte); !ok {
// return fmt.Errorf("kid key value is not a []byte: %T", vI)
// } else {
// k.Kid = make([]byte, len(v))
// copy(k.Kid, v)
// }
// }
// return nil
// }

// func (k *COSEKey) MarshalCBOR_viaMap() ([]byte, error) {
// rck := make(map[any]any)
// rck[kCrvKey] = uint64(6)
// rck[kKtyKey] = uint64(1)
// rck[kAlgKey] = int64(cose.AlgorithmEd25519)
// keyBuf := make([]byte, len(k.Key))
// copy(keyBuf, k.Key)
// rck[kKeyKey] = keyBuf
// if k.Kid != nil {
// kidBuf := make([]byte, len(k.Kid))
// copy(kidBuf, k.Kid)
// rck[kKidKey] = kidBuf
// }
// }
Loading

0 comments on commit f18d320

Please sign in to comment.