10000 refactor(crypto): handle errors and more in `bls12381` by melekes · Pull Request #2832 · cometbft/cometbft · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

refactor(crypto): handle errors and more in bls12381 #2832

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Apr 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .changelog/unreleased/features/2765-bls12-381-curve.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
- `[crypto]` Add support for BLS12-381 keys. Use `bls12381` build flag to enable
it ([\#2765](https://github.com/cometbft/cometbft/pull/2765))
- `[crypto]` Add support for BLS12-381 keys. Since the implementation needs
`cgo` and brings in new dependencies, we use the `bls12381` build flag to
enable it ([\#2765](https://github.com/cometbft/cometbft/pull/2765))
18 changes: 18 additions & 0 deletions crypto/bls12381/const.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package bls12381

const (
// PrivKeySize defines the length of the PrivKey byte array.
PrivKeySize = 32
// PubKeySize defines the length of the PubKey byte array.
PubKeySize = 48
// SignatureLength defines the byte length of a BLS signature.
SignatureLength = 96
// KeyType is the string constant for the BLS12-381 algorithm.
KeyType = "bls12_381"
// MaxMsgLen defines the maximum length of the message bytes as passed to Sign.
MaxMsgLen = 32
// BLS12-381 private key name.
PrivKeyName = "cometbft/PrivKeyBls12_381"
// BLS12-381 public key name.
PubKeyName = "cometbft/PubKeyBls12_381"
)
52 changes: 23 additions & 29 deletions crypto/bls12381/key.go
Original file line number Diff line number Diff line change
@@ -1,72 +1,66 @@
//go:build !bls12381 || !((linux && amd64) || (linux && arm64) || (darwin && amd64) || (darwin && arm64) || (windows && amd64))
//go:build !(((linux && amd64) || (linux && arm64) || (darwin && amd64) || (darwin && arm64) || (windows && amd64)) && bls12381)

package bls12381

import (
"errors"

"github.com/cometbft/cometbft/crypto"
)

const (
// PrivKeySize defines the length of the PrivKey byte array.
PrivKeySize = 32
// PubKeySize defines the length of the PubKey byte array.
PubKeySize = 48
// SignatureLength defines the byte length of a BLS signature.
SignatureLength = 96
// KeyType is the string constant for the bls12_381 algorithm.
KeyType = "bls12_381"
// Enabled indicates if this curve is enabled.
Enabled = false
)

// -------------------------------------.
const (
PubKeyName = "cometbft/PubKeyBLS12_381"
)
// ErrDisabled is returned if the caller didn't use the `bls12381` build tag or has an incompatible OS.
var ErrDisabled = errors.New("bls12_381 is disabled")

// ===============================================================================================
// Private Key
// ===============================================================================================

// PrivKey is a wrapper around the Ethereum bls12_381 private key type. This
// PrivKey is a wrapper around the Ethereum BLS12-381 private key type. This
// wrapper conforms to crypto.Pubkey to allow for the use of the Ethereum
// bls12_381 private key type.
// BLS12-381 private key type.

// Compile-time type assertion.
var _ crypto.PrivKey = &PrivKey{}

// PrivKey represents a BLS private key noop when blst is not set as a build flag and cgo is disabled.
type PrivKey []byte

// NewPrivateKeyFromBytes returns ErrDisabled.
func NewPrivateKeyFromBytes([]byte) (PrivKey, error) {
panic("bls12_381 is disabled")
return nil, ErrDisabled
}

// GenPrivKey returns ErrDisabled.
func GenPrivKey() (PrivKey, error) {
panic("bls12_381 is disabled")
return nil, ErrDisabled
}

// Bytes returns the byte representation of the ECDSA Private Key.
// Bytes returns the byte representation of the Key.
func (privKey PrivKey) Bytes() []byte {
return privKey
}

// PubKey returns the ECDSA private key's public key. If the privkey is not valid
// it returns a nil value.
// PubKey always panics.
func (PrivKey) PubKey() crypto.PubKey {
panic("bls12_381 is disabled")
}

// Equals returns true if two ECDSA private keys are equal and false otherwise.
// Equals always panics.
func (PrivKey) Equals(crypto.PrivKey) bool {
panic("bls12_381 is disabled")
}

// Type returns eth_bls12_381.
// Type returns the key's type.
func (PrivKey) Type() string {
return KeyType
}

// Sign always panics.
func (PrivKey) Sign([]byte) ([]byte, error) {
panic("bls12_381 is disabled")
}
Expand All @@ -75,37 +69,37 @@ func (PrivKey) Sign([]byte) ([]byte, error) {
// Public Key
// ===============================================================================================

// Pubkey is a wrapper around the Ethereum bls12_381 public key type. This
// Pubkey is a wrapper around the Ethereum BLS12-381 public key type. This
// wrapper conforms to crypto.Pubkey to allow for the use of the Ethereum
// bls12_381 public key type.
// BLS12-381 public key type.

// Compile-time type assertion.
var _ crypto.PubKey = &PubKey{}

// PubKey represents a BLS private key noop when blst is not set as a build flag and cgo is disabled.
type PubKey []byte

// Address returns the address of the ECDSA public key.
// The function will return an empty address if the public key is invalid.
// Address always panics.
func (PubKey) Address() crypto.Address {
panic("bls12_381 is disabled")
}

// VerifySignature always panics.
func (PubKey) VerifySignature([]byte, []byte) bool {
panic("bls12_381 is disabled")
}

// Bytes returns the pubkey byte format.
// Bytes always panics.
func (PubKey) Bytes() []byte {
panic("bls12_381 is disabled")
}

// Type returns eth_bls12_381.
// Type returns the key's type.
func (PubKey) Type() string {
return KeyType
}

// Equals returns true if the pubkey type is the same and their bytes are deeply equal.
// Equals always panics.
func (PubKey) Equals(crypto.PubKey) bool {
panic("bls12_381 is disabled")
}
76 changes: 38 additions & 38 deletions crypto/bls12381/key_bls12381.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,11 @@ import (
)

const (
// PrivKeySize defines the length of the PrivKey byte array.
PrivKeySize = 32
// PubKeySize defines the length of the PubKey byte array.
PubKeySize = 48
// SignatureLength defines the byte length of a BLS signature.
SignatureLength = 96
// KeyType is the string constant for the bls12_381 algorithm.
KeyType = "bls12_381"
// Enabled indicates if this curve is enabled.
Enabled = true
)

// -------------------------------------.
const (
PrivKeyName = "cometbft/PrivKeyBLS12_381"
PubKeyName = "cometbft/PubKeyBLS12_381"
)

func init() {
cmtjson.RegisterType(PubKey{}, PubKeyName)
Expand All @@ -42,14 +30,15 @@ func init() {
// Private Key
// ===============================================================================================

// PrivKey is a wrapper around the Ethereum bls12_381 private key type. This
// PrivKey is a wrapper around the Ethereum BLS12-381 private key type. This
// wrapper conforms to crypto.Pubkey to allow for the use of the Ethereum
// bls12_381 private key type.
// BLS12-381 private key type.

var _ crypto.PrivKey = &PrivKey{}

type PrivKey []byte

// NewPrivateKeyFromBytes build a new key from the given bytes.
func NewPrivateKeyFromBytes(bz []byte) (PrivKey, error) {
secretKey, err := bls12381.SecretKeyFromBytes(bz)
if err != nil {
Expand All @@ -58,102 +47,113 @@ func NewPrivateKeyFromBytes(bz []byte) (PrivKey, error) {
return secretKey.Marshal(), nil
}

// GenPrivKey generates a new key.
func GenPrivKey() (PrivKey, error) {
secretKey, err := bls12381.RandKey()
return PrivKey(secretKey.Marshal()), err
}

// Bytes returns the byte representation of the Private Key.
// Bytes returns the byte representation of the Key.
func (privKey PrivKey) Bytes() []byte {
return privKey
}

// PubKey returns the private key's public key. If the privkey is not valid
// it returns a nil value.
func (privKey PrivKey) PubKey() crypto.PubKey {
secretKey, _ := bls12381.SecretKeyFromBytes(privKey)
secretKey, err := bls12381.SecretKeyFromBytes(privKey)
if err != nil {
return nil
}

return PubKey(secretKey.PublicKey().Marshal())
}

// Equals returns true if two private keys are equal and false otherwise.
// Equals returns true if two keys are equal and false otherwise.
func (privKey PrivKey) Equals(other crypto.PrivKey) bool {
return privKey.Type() == other.Type() && bytes.Equal(privKey.Bytes(), other.Bytes())
}

// Type returns eth_bls12_381.
// Type returns the type.
func (PrivKey) Type() string {
return KeyType
}

func (privKey PrivKey) Sign(digestBz []byte) ([]byte, error) {
// Sign signs the given byte array. If msg is larger than
// MaxMsgLen, SHA256 sum will be signed instead of the raw bytes.
func (privKey PrivKey) Sign(msg []byte) ([]byte, error) {
secretKey, err := bls12381.SecretKeyFromBytes(privKey)
if err != nil {
return nil, err
}

bz := digestBz
if len(bz) > 32 {
hash := sha256.Sum256(bz)
bz = hash[:]
if len(msg) > MaxMsgLen {
hash := sha256.Sum256(msg)
sig := secretKey.Sign(hash[:])
return sig.Marshal(), nil
}

sig := secretKey.Sign(bz)
sig := secretKey.Sign(msg)
return sig.Marshal(), nil
}

// ===============================================================================================
// Public Key
// ===============================================================================================

// Pubkey is a wrapper around the Ethereum bls12_381 public key type. This
// Pubkey is a wrapper around the Ethereum BLS12-381 public key type. This
// wrapper conforms to crypto.Pubkey to allow for the use of the Ethereum
// bls12_381 public key type.
// BLS12-381 public key type.

var _ crypto.PubKey = &PubKey{}

type PubKey []byte

// Address returns the address of the public key.
// Address returns the address of the key.
//
// The function will panic if the public key is invalid.
func (pubKey PubKey) Address() crypto.Address {
pk, _ := bls12381.PublicKeyFromBytes(pubKey)
if len(pk.Marshal()) != PubKeySize {
panic("pubkey is incorrect size")
}
// TODO: do we want to keep this address format?
return crypto.Address(tmhash.SumTruncated(pubKey))
}

// VerifySignature verifies the given signature.
func (pubKey PubKey) VerifySignature(msg, sig []byte) bool {
if len(sig) != SignatureLength {
return false
}
bz := msg
if len(msg) > 32 {

pubK, err := bls12381.PublicKeyFromBytes(pubKey)
if err != nil { // invalid pubkey
return false
}

if len(msg) > MaxMsgLen {
hash := sha256.Sum256(msg)
bz = hash[:]
msg = hash[:]
}

pubK, _ := bls12381.PublicKeyFromBytes(pubKey)
ok, err := bls12381.VerifySignature(sig, [32]byte(bz[:32]), pubK)
if err != nil {
ok, err := bls12381.VerifySignature(sig, [MaxMsgLen]byte(msg[:MaxMsgLen]), pubK)
if err != nil { // bad signature
return false
}

return ok
}

// Bytes returns the pubkey byte format.
// Bytes returns the byte format.
func (pubKey PubKey) Bytes() []byte {
return pubKey
}

// Type returns eth_bls12_381.
// Type returns the key's type.
func (PubKey) Type() string {
return KeyType
}

// Equals returns true if the pubkey type is the same and their bytes are deeply equal.
// Equals returns true if the other's type is the same and their bytes are deeply equal.
func (pubKey PubKey) Equals(other crypto.PubKey) bool {
return pubKey.Type() == other.Type() && bytes.Equal(pubKey.Bytes(), other.Bytes())
}
Loading
0