Skip to content
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

feat(crypto): add blst #20296

Merged
merged 13 commits into from
Jun 11, 2024
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ ifeq (boltdb,$(findstring boltdb,$(COSMOS_BUILD_OPTIONS)))
build_tags += boltdb
endif

# handle blst
ifeq (boltdb,$(findstring blst,$(COSMOS_BUILD_OPTIONS)))
tac0turtle marked this conversation as resolved.
Show resolved Hide resolved
CGO_ENABLED=1
build_tags += blst
endif

whitespace :=
whitespace += $(whitespace)
comma := ,
Expand Down
3 changes: 3 additions & 0 deletions crypto/codec/amino.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"github.com/cometbft/cometbft/crypto/sr25519"

"github.com/cosmos/cosmos-sdk/codec"
bls12_381 "github.com/cosmos/cosmos-sdk/crypto/keys/bls12_381"
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
kmultisig "github.com/cosmos/cosmos-sdk/crypto/keys/multisig"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
Expand All @@ -20,6 +21,7 @@ func RegisterCrypto(cdc *codec.LegacyAmino) {
ed25519.PubKeyName, nil)
cdc.RegisterConcrete(&secp256k1.PubKey{},
secp256k1.PubKeyName, nil)
cdc.RegisterConcrete(&bls12_381.PubKey{}, bls12_381.PubKeyName, nil)
cdc.RegisterConcrete(&kmultisig.LegacyAminoPubKey{},
kmultisig.PubKeyAminoRoute, nil)

Expand All @@ -30,4 +32,5 @@ func RegisterCrypto(cdc *codec.LegacyAmino) {
ed25519.PrivKeyName, nil)
cdc.RegisterConcrete(&secp256k1.PrivKey{},
secp256k1.PrivKeyName, nil)
cdc.RegisterConcrete(&bls12_381.PrivKey{}, bls12_381.PrivKeyName, nil)
}
12 changes: 11 additions & 1 deletion crypto/codec/cmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"github.com/cometbft/cometbft/crypto/encoding"

"cosmossdk.io/errors"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reorder imports according to the Golang style guide.

import (
	cmtprotocrypto "github.com/cometbft/cometbft/api/cometbft/crypto/v1"
	cmtcrypto "github.com/cometbft/cometbft/crypto"
	"github.com/cometbft/cometbft/crypto/encoding"
	"cosmossdk.io/errors"
	bls12_381 "github.com/cosmos/cosmos-sdk/crypto/keys/bls12_381"
	"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
	"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
	cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
	sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
"cosmossdk.io/errors"
import (
cmtprotocrypto "github.com/cometbft/cometbft/api/cometbft/crypto/v1"
cmtcrypto "github.com/cometbft/cometbft/crypto"
"github.com/cometbft/cometbft/crypto/encoding"
"cosmossdk.io/errors"
bls12_381 "github.com/cosmos/cosmos-sdk/crypto/keys/bls12_381"
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
Tools
golangci-lint

8-8: File is not gci-ed with --skip-generated -s standard -s default -s prefix(cosmossdk.io) -s prefix(github.com/cosmos/cosmos-sdk) --custom-order (gci)


bls12_381 "github.com/cosmos/cosmos-sdk/crypto/keys/bls12_381"
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
Expand All @@ -24,6 +24,10 @@ func FromCmtProtoPublicKey(protoPk cmtprotocrypto.PublicKey) (cryptotypes.PubKey
return &secp256k1.PubKey{
Key: protoPk.Secp256K1,
}, nil
case *cmtprotocrypto.PublicKey_Bls12381:
return &bls12_381.PubKey{
Key: protoPk.Bls12381,
}, nil
default:
return nil, errors.Wrapf(sdkerrors.ErrInvalidType, "cannot convert %v from Tendermint public key", protoPk)
}
Expand All @@ -44,6 +48,12 @@ func ToCmtProtoPublicKey(pk cryptotypes.PubKey) (cmtprotocrypto.PublicKey, error
Secp256K1: pk.Key,
},
}, nil
case *bls12_381.PubKey:
return cmtprotocrypto.PublicKey{
Sum: &cmtprotocrypto.PublicKey_Bls12381{
Bls12381: pk.Key,
},
}, nil
default:
return cmtprotocrypto.PublicKey{}, errors.Wrapf(sdkerrors.ErrInvalidType, "cannot convert %v to Tendermint public key", pk)
}
Expand Down
3 changes: 3 additions & 0 deletions crypto/codec/proto.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package codec

import (
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
bls12_381 "github.com/cosmos/cosmos-sdk/crypto/keys/bls12_381"
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
"github.com/cosmos/cosmos-sdk/crypto/keys/multisig"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
Expand All @@ -15,11 +16,13 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) {
registry.RegisterInterface("cosmos.crypto.PubKey", pk)
registry.RegisterImplementations(pk, &ed25519.PubKey{})
registry.RegisterImplementations(pk, &secp256k1.PubKey{})
registry.RegisterImplementations(pk, &bls12_381.PubKey{})
registry.RegisterImplementations(pk, &multisig.LegacyAminoPubKey{})

var priv *cryptotypes.PrivKey
registry.RegisterInterface("cosmos.crypto.PrivKey", priv)
registry.RegisterImplementations(priv, &secp256k1.PrivKey{})
registry.RegisterImplementations(priv, &ed25519.PrivKey{})
registry.RegisterImplementations(priv, &bls12_381.PrivKey{})
secp256r1.RegisterInterfaces(registry)
}
3 changes: 3 additions & 0 deletions crypto/hd/algo.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ const (
// Ed25519Type represents the Ed25519Type signature system.
// It is currently not supported for end-user keys (wallets/ledgers).
Ed25519Type = PubKeyType("ed25519")
// Ed25519Type represents the Ed25519Type signature system.
// It is currently not supported for end-user keys (wallets/ledgers).
Bls12_381Type = PubKeyType("bls12_381")
// Sr25519Type represents the Sr25519Type signature system.
Sr25519Type = PubKeyType("sr25519")
)
Expand Down
240 changes: 240 additions & 0 deletions crypto/keys/bls12_381/keys.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
// SPDX-License-Identifier: MIT
//
// Copyright (c) 2023 Berachain Foundation
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.

package bls12_381

import (
"bytes"
fmt "fmt"

"github.com/minio/sha256-simd"

errorsmod "cosmossdk.io/errors"

"github.com/cometbft/cometbft/crypto"
"github.com/cometbft/cometbft/crypto/tmhash"
"github.com/cosmos/cosmos-sdk/codec"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/types/errors"

"github.com/itsdevbear/comet-bls12-381/bls/blst"

Check failure on line 42 in crypto/keys/bls12_381/keys.go

View workflow job for this annotation

GitHub Actions / split-test-files

no required module provides package github.com/itsdevbear/comet-bls12-381/bls/blst; to add it:

Check failure on line 42 in crypto/keys/bls12_381/keys.go

View workflow job for this annotation

GitHub Actions / dependency-review

no required module provides package github.com/itsdevbear/comet-bls12-381/bls/blst; to add it:

Check failure on line 42 in crypto/keys/bls12_381/keys.go

View workflow job for this annotation

GitHub Actions / dependency-review

no required module provides package github.com/itsdevbear/comet-bls12-381/bls/blst; to add it:

Check failure on line 42 in crypto/keys/bls12_381/keys.go

View workflow job for this annotation

GitHub Actions / dependency-review

no required module provides package github.com/itsdevbear/comet-bls12-381/bls/blst; to add it:

Check failure on line 42 in crypto/keys/bls12_381/keys.go

View workflow job for this annotation

GitHub Actions / dependency-review

no required module provides package github.com/itsdevbear/comet-bls12-381/bls/blst; to add it:

Check failure on line 42 in crypto/keys/bls12_381/keys.go

View workflow job for this annotation

GitHub Actions / dependency-review

no required module provides package github.com/itsdevbear/comet-bls12-381/bls/blst; to add it:

Check failure on line 42 in crypto/keys/bls12_381/keys.go

View workflow job for this annotation

GitHub Actions / dependency-review

no required module provides package github.com/itsdevbear/comet-bls12-381/bls/blst; to add it:

Check failure on line 42 in crypto/keys/bls12_381/keys.go

View workflow job for this annotation

GitHub Actions / dependency-review

no required module provides package github.com/itsdevbear/comet-bls12-381/bls/blst; to add it:

Check failure on line 42 in crypto/keys/bls12_381/keys.go

View workflow job for this annotation

GitHub Actions / dependency-review

no required module provides package github.com/itsdevbear/comet-bls12-381/bls/blst; to add it:

Check failure on line 42 in crypto/keys/bls12_381/keys.go

View workflow job for this annotation

GitHub Actions / dependency-review

no required module provides package github.com/itsdevbear/comet-bls12-381/bls/blst; to add it:

Check failure on line 42 in crypto/keys/bls12_381/keys.go

View workflow job for this annotation

GitHub Actions / dependency-review

no required module provides package github.com/itsdevbear/comet-bls12-381/bls/blst; to add it:

Check failure on line 42 in crypto/keys/bls12_381/keys.go

View workflow job for this annotation

GitHub Actions / dependency-review

no required module provides package github.com/itsdevbear/comet-bls12-381/bls/blst; to add it:

Check failure on line 42 in crypto/keys/bls12_381/keys.go

View workflow job for this annotation

GitHub Actions / dependency-review

could not import github.com/itsdevbear/comet-bls12-381/bls/blst (invalid package name: "")
"github.com/itsdevbear/comet-bls12-381/bls/params"

Check failure on line 43 in crypto/keys/bls12_381/keys.go

View workflow job for this annotation

GitHub Actions / split-test-files

no required module provides package github.com/itsdevbear/comet-bls12-381/bls/params; to add it:

Check failure on line 43 in crypto/keys/bls12_381/keys.go

View workflow job for this annotation

GitHub Actions / dependency-review

no required module provides package github.com/itsdevbear/comet-bls12-381/bls/params; to add it:

Check failure on line 43 in crypto/keys/bls12_381/keys.go

View workflow job for this annotation

GitHub Actions / dependency-review

could not import github.com/itsdevbear/comet-bls12-381/bls/params (invalid package name: "")
)

const (
// PrivKeySize defines the length of the PrivKey byte array.
PrivKeySize = 32
// PubKeySize defines the length of the PubKey byte array.
PubKeySize = 48
// KeyType is the string constant for the bls12_381 algorithm.
KeyType = "bls12_381"
)

var (
_ cryptotypes.PrivKey = &PrivKey{}
_ codec.AminoMarshaler = &PrivKey{}
)

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

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

// PrivKey is a wrapper around the Ethereum bls12_381 private key type. This wrapper conforms to
// crypotypes.Pubkey to allow for the use of the Ethereum bls12_381 private key type within the
// Cosmos SDK.

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

func NewPrivateKeyFromBytes(bz []byte) (*PrivKey, error) {
secretKey, err := blst.SecretKeyFromBytes(bz)
if err != nil {
return nil, err
}
return &PrivKey{secretKey.Marshal()}, nil
}

func GenPrivKey() (PrivKey, error) {
secretKey, err := blst.RandKey()
return PrivKey{secretKey.Marshal()}, err
}

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

// PubKey returns the ECDSA private key's public key. If the privkey is not valid
// it returns a nil value.
func (privKey PrivKey) PubKey() cryptotypes.PubKey {
secretKey, _ := blst.SecretKeyFromBytes(privKey.Key)
key := PubKey{secretKey.PublicKey().Marshal()}
return &key
}

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

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

func (privKey PrivKey) Sign(digestBz []byte) ([]byte, error) {
secretKey, err := blst.SecretKeyFromBytes(privKey.Key)
if err != nil {
return nil, err
}

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

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

// MarshalAmino overrides Amino binary marshaling.
func (privKey PrivKey) MarshalAmino() ([]byte, error) {
return privKey.Key, nil
}

// UnmarshalAmino overrides Amino binary marshaling.
func (privKey *PrivKey) UnmarshalAmino(bz []byte) error {
if len(bz) != PrivKeySize {
return fmt.Errorf("invalid privkey size")
}
privKey.Key = bz

return nil
}

// MarshalAminoJSON overrides Amino JSON marshaling.
func (privKey PrivKey) MarshalAminoJSON() ([]byte, error) {
// When we marshal to Amino JSON, we don't marshal the "key" field itself,
// just its contents (i.e. the key bytes).
return privKey.MarshalAmino()
}

// UnmarshalAminoJSON overrides Amino JSON marshaling.
func (privKey *PrivKey) UnmarshalAminoJSON(bz []byte) error {
return privKey.UnmarshalAmino(bz)
}

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

// Pubkey is a wrapper around the Ethereum bls12_381 public key type. This wrapper conforms to
// crypotypes.Pubkey to allow for the use of the Ethereum bls12_381 public key type within the
// Cosmos SDK.

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

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

func (pubKey *PubKey) VerifySignature(msg, sig []byte) bool {
if len(sig) != params.BLSSignatureLength {
return false
}
bz := msg
if len(msg) > 32 {
hash := sha256.Sum256(msg)
bz = hash[:]
}

pubK, _ := blst.PublicKeyFromBytes(pubKey.Key)
ok, err := blst.VerifySignature(sig, [32]byte(bz[:32]), pubK)
if err != nil {
return false
}
return ok
}

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

func (pubKey *PubKey) String() string {
return fmt.Sprintf("PubKeyBLS12_381{%X}", pubKey.Key)
}

// Type returns eth_bls12_381.
func (pubKey *PubKey) Type() string {
return KeyType
}

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

// MarshalAmino overrides Amino binary marshaling.
func (pubKey *PubKey) MarshalAmino() ([]byte, error) {
return pubKey.Key, nil
}

// UnmarshalAmino overrides Amino binary marshaling.
func (pubKey *PubKey) UnmarshalAmino(bz []byte) error {
if len(bz) != PubKeySize {
return errorsmod.Wrap(errors.ErrInvalidPubKey, "invalid pubkey size")
}
pubKey.Key = bz

return nil
}

// MarshalAminoJSON overrides Amino JSON marshaling.
func (pubKey *PubKey) MarshalAminoJSON() ([]byte, error) {
// When we marshal to Amino JSON, we don't marshal the "key" field itself,
// just its contents (i.e. the key bytes).
return pubKey.MarshalAmino()
}

// UnmarshalAminoJSON overrides Amino JSON marshaling.
func (pubKey *PubKey) UnmarshalAminoJSON(bz []byte) error {
return pubKey.UnmarshalAmino(bz)
}
Loading
Loading