Skip to content

Commit fecd038

Browse files
simonzg1Alex | Interchain Labscoderabbitai[bot]
authored
feat: port bls12381 from v0.52.rc2 (#24872)
Co-authored-by: Alex | Interchain Labs <[email protected]> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
1 parent c9d9b2a commit fecd038

File tree

15 files changed

+1037
-6
lines changed

15 files changed

+1037
-6
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ Ref: https://keepachangelog.com/en/1.0.0/
3838

3939
## [Unreleased]
4040

41+
### Features
42+
43+
* [#24872](https://github.com/cosmos/cosmos-sdk/pull/24872) Support BLS 12-381 for cli `init`, `gentx`, `collect-gentx`
44+
4145
### Breaking Changes
4246

4347
* [#24837](https://github.com/cosmos/cosmos-sdk/pull/24837) Update to using CometBFT v2.

crypto/codec/amino.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package codec
22

33
import (
4+
"github.com/cometbft/cometbft/v2/crypto/bls12381"
5+
46
"github.com/cosmos/cosmos-sdk/codec"
7+
bls12_381 "github.com/cosmos/cosmos-sdk/crypto/keys/bls12_381"
58
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
69
kmultisig "github.com/cosmos/cosmos-sdk/crypto/keys/multisig"
710
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
@@ -24,4 +27,6 @@ func RegisterCrypto(cdc *codec.LegacyAmino) {
2427
ed25519.PrivKeyName, nil)
2528
cdc.RegisterConcrete(&secp256k1.PrivKey{},
2629
secp256k1.PrivKeyName, nil)
30+
cdc.RegisterConcrete(&bls12_381.PubKey{}, bls12381.PubKeyName, nil)
31+
cdc.RegisterConcrete(&bls12_381.PrivKey{}, bls12381.PrivKeyName, nil)
2732
}

crypto/codec/cmt.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77

88
"cosmossdk.io/errors"
99

10+
bls12_381 "github.com/cosmos/cosmos-sdk/crypto/keys/bls12_381"
1011
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
1112
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
1213
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
@@ -24,6 +25,10 @@ func FromCmtProtoPublicKey(protoPk cmtprotocrypto.PublicKey) (cryptotypes.PubKey
2425
return &secp256k1.PubKey{
2526
Key: protoPk.Secp256K1,
2627
}, nil
28+
case *cmtprotocrypto.PublicKey_Bls12381:
29+
return &bls12_381.PubKey{
30+
Key: protoPk.Bls12381,
31+
}, nil
2732
default:
2833
return nil, errors.Wrapf(sdkerrors.ErrInvalidType, "cannot convert %v from Tendermint public key", protoPk)
2934
}
@@ -44,6 +49,12 @@ func ToCmtProtoPublicKey(pk cryptotypes.PubKey) (cmtprotocrypto.PublicKey, error
4449
Secp256K1: pk.Key,
4550
},
4651
}, nil
52+
case *bls12_381.PubKey:
53+
return cmtprotocrypto.PublicKey{
54+
Sum: &cmtprotocrypto.PublicKey_Bls12381{
55+
Bls12381: pk.Key,
56+
},
57+
}, nil
4758
default:
4859
return cmtprotocrypto.PublicKey{}, errors.Wrapf(sdkerrors.ErrInvalidType, "cannot convert %v to Tendermint public key", pk)
4960
}

crypto/codec/proto.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package codec
22

33
import (
44
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
5+
bls12_381 "github.com/cosmos/cosmos-sdk/crypto/keys/bls12_381"
56
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
67
"github.com/cosmos/cosmos-sdk/crypto/keys/multisig"
78
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
@@ -15,11 +16,13 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) {
1516
registry.RegisterInterface("cosmos.crypto.PubKey", pk)
1617
registry.RegisterImplementations(pk, &ed25519.PubKey{})
1718
registry.RegisterImplementations(pk, &secp256k1.PubKey{})
19+
registry.RegisterImplementations(pk, &bls12_381.PubKey{})
1820
registry.RegisterImplementations(pk, &multisig.LegacyAminoPubKey{})
1921

2022
var priv *cryptotypes.PrivKey
2123
registry.RegisterInterface("cosmos.crypto.PrivKey", priv)
2224
registry.RegisterImplementations(priv, &secp256k1.PrivKey{})
2325
registry.RegisterImplementations(priv, &ed25519.PrivKey{})
26+
registry.RegisterImplementations(priv, &bls12_381.PrivKey{})
2427
secp256r1.RegisterInterfaces(registry)
2528
}

crypto/hd/algo.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ const (
1818
// Ed25519Type represents the Ed25519Type signature system.
1919
// It is currently not supported for end-user keys (wallets/ledgers).
2020
Ed25519Type = PubKeyType("ed25519")
21+
// Bls12_381Type represents the Bls12_381Type signature system.
22+
// It is currently not supported for end-user keys (wallets/ledgers).
23+
Bls12_381Type = PubKeyType("bls12_381")
2124
)
2225

2326
// Secp256k1 uses the Bitcoin secp256k1 ECDSA parameters.

crypto/keys/bls12_381/key.go

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
//go:build !bls12381
2+
3+
package bls12_381
4+
5+
import (
6+
"bytes"
7+
"errors"
8+
"fmt"
9+
10+
"github.com/cometbft/cometbft/v2/crypto"
11+
bls "github.com/cometbft/cometbft/v2/crypto/bls12381"
12+
13+
"github.com/cosmos/cosmos-sdk/codec"
14+
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
15+
)
16+
17+
// ===============================================================================================
18+
// Private Key
19+
// ===============================================================================================
20+
21+
// PrivKey is a wrapper around the Ethereum BLS12-381 private key type. This
22+
// wrapper conforms to crypto.Pubkey to allow for the use of the Ethereum
23+
// BLS12-381 private key type.
24+
25+
var (
26+
_ cryptotypes.PrivKey = &PrivKey{}
27+
_ codec.AminoMarshaler = &PrivKey{}
28+
)
29+
30+
// NewPrivateKeyFromBytes build a new key from the given bytes.
31+
func NewPrivateKeyFromBytes(bz []byte) (PrivKey, error) {
32+
panic("not implemented, build flags are required to use bls12_381 keys")
33+
}
34+
35+
// GenPrivKey generates a new key.
36+
func GenPrivKey() (PrivKey, error) {
37+
panic("not implemented, build flags are required to use bls12_381 keys")
38+
}
39+
40+
// Bytes returns the byte representation of the Key.
41+
func (privKey PrivKey) Bytes() []byte {
42+
panic("not implemented, build flags are required to use bls12_381 keys")
43+
}
44+
45+
// PubKey returns the private key's public key. If the privkey is not valid
46+
// it returns a nil value.
47+
func (privKey PrivKey) PubKey() cryptotypes.PubKey {
48+
panic("not implemented, build flags are required to use bls12_381 keys")
49+
}
50+
51+
// Equals returns true if two keys are equal and false otherwise.
52+
func (privKey PrivKey) Equals(other cryptotypes.LedgerPrivKey) bool {
53+
panic("not implemented, build flags are required to use bls12_381 keys")
54+
}
55+
56+
// Type returns the type.
57+
func (PrivKey) Type() string {
58+
return bls.KeyType
59+
}
60+
61+
// Sign signs the given byte array. If msg is larger than
62+
// MaxMsgLen, SHA256 sum will be signed instead of the raw bytes.
63+
func (privKey PrivKey) Sign(msg []byte) ([]byte, error) {
64+
panic("not implemented, build flags are required to use bls12_381 keys")
65+
}
66+
67+
// MarshalAmino overrides Amino binary marshaling.
68+
func (privKey PrivKey) MarshalAmino() ([]byte, error) {
69+
return privKey.Key, nil
70+
}
71+
72+
// UnmarshalAmino overrides Amino binary marshaling.
73+
func (privKey *PrivKey) UnmarshalAmino(bz []byte) error {
74+
if len(bz) != bls.PrivKeySize {
75+
return errors.New("invalid privkey size")
76+
}
77+
privKey.Key = bz
78+
79+
return nil
80+
}
81+
82+
// MarshalAminoJSON overrides Amino JSON marshaling.
83+
func (privKey PrivKey) MarshalAminoJSON() ([]byte, error) {
84+
// When we marshal to Amino JSON, we don't marshal the "key" field itself,
85+
// just its contents (i.e. the key bytes).
86+
return privKey.MarshalAmino()
87+
}
88+
89+
// UnmarshalAminoJSON overrides Amino JSON marshaling.
90+
func (privKey *PrivKey) UnmarshalAminoJSON(bz []byte) error {
91+
return privKey.UnmarshalAmino(bz)
92+
}
93+
94+
// ===============================================================================================
95+
// Public Key
96+
// ===============================================================================================
97+
98+
// Pubkey is a wrapper around the Ethereum BLS12-381 public key type. This
99+
// wrapper conforms to crypto.Pubkey to allow for the use of the Ethereum
100+
// BLS12-381 public key type.
101+
102+
var _ cryptotypes.PubKey = &PubKey{}
103+
104+
// Address returns the address of the key.
105+
//
106+
// The function will panic if the public key is invalid.
107+
func (pubKey PubKey) Address() crypto.Address {
108+
panic("not implemented, build flags are required to use bls12_381 keys")
109+
}
110+
111+
// VerifySignature verifies the given signature.
112+
func (pubKey PubKey) VerifySignature(msg, sig []byte) bool {
113+
panic("not implemented, build flags are required to use bls12_381 keys")
114+
}
115+
116+
// Bytes returns the byte format.
117+
func (pubKey PubKey) Bytes() []byte {
118+
return pubKey.Key
119+
}
120+
121+
// Type returns the key's type.
122+
func (PubKey) Type() string {
123+
return bls.KeyType
124+
}
125+
126+
// Equals returns true if the other's type is the same and their bytes are deeply equal.
127+
func (pubKey PubKey) Equals(other cryptotypes.PubKey) bool {
128+
return pubKey.Type() == other.Type() && bytes.Equal(pubKey.Bytes(), other.Bytes())
129+
}
130+
131+
// String returns Hex representation of a pubkey with it's type
132+
func (pubKey PubKey) String() string {
133+
return fmt.Sprintf("PubKeyBLS12_381{%X}", pubKey.Key)
134+
}

crypto/keys/bls12_381/key_cgo.go

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
//go:build ((linux && amd64) || (linux && arm64) || (darwin && amd64) || (darwin && arm64) || (windows && amd64)) && bls12381
2+
3+
package bls12_381
4+
5+
import (
6+
"bytes"
7+
"errors"
8+
"fmt"
9+
10+
"github.com/cometbft/cometbft/v2/crypto"
11+
"github.com/cometbft/cometbft/v2/crypto/bls12381"
12+
"github.com/cometbft/cometbft/v2/crypto/tmhash"
13+
14+
"github.com/cosmos/cosmos-sdk/codec"
15+
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
16+
)
17+
18+
// ===============================================================================================
19+
// Private Key
20+
// ===============================================================================================
21+
22+
// PrivKey is a wrapper around the Ethereum BLS12-381 private key type. This
23+
// wrapper conforms to crypto.Pubkey to allow for the use of the Ethereum
24+
// BLS12-381 private key type.
25+
26+
var (
27+
_ cryptotypes.PrivKey = &PrivKey{}
28+
_ codec.AminoMarshaler = &PrivKey{}
29+
)
30+
31+
// NewPrivateKeyFromBytes build a new key from the given bytes.
32+
func NewPrivateKeyFromBytes(bz []byte) (PrivKey, error) {
33+
secretKey, err := bls12381.NewPrivateKeyFromBytes(bz)
34+
if err != nil {
35+
return PrivKey{}, err
36+
}
37+
return PrivKey{
38+
Key: secretKey.Bytes(),
39+
}, nil
40+
}
41+
42+
// GenPrivKey generates a new key.
43+
func GenPrivKey() (PrivKey, error) {
44+
secretKey, err := bls12381.GenPrivKey()
45+
return PrivKey{
46+
Key: secretKey.Bytes(),
47+
}, err
48+
}
49+
50+
// Bytes returns the byte representation of the Key.
51+
func (privKey PrivKey) Bytes() []byte {
52+
return privKey.Key
53+
}
54+
55+
// PubKey returns the private key's public key. If the privkey is not valid
56+
// it returns a nil value.
57+
func (privKey PrivKey) PubKey() cryptotypes.PubKey {
58+
secretKey, err := bls12381.NewPrivateKeyFromBytes(privKey.Key)
59+
if err != nil {
60+
return nil
61+
}
62+
63+
return &PubKey{
64+
Key: secretKey.PubKey().Bytes(),
65+
}
66+
}
67+
68+
// Equals returns true if two keys are equal and false otherwise.
69+
func (privKey PrivKey) Equals(other cryptotypes.LedgerPrivKey) bool {
70+
return privKey.Type() == other.Type() && bytes.Equal(privKey.Bytes(), other.Bytes())
71+
}
72+
73+
// Type returns the type.
74+
func (PrivKey) Type() string {
75+
return bls12381.KeyType
76+
}
77+
78+
// Sign signs the given byte array. If msg is larger than
79+
// MaxMsgLen, SHA256 sum will be signed instead of the raw bytes.
80+
func (privKey PrivKey) Sign(msg []byte) ([]byte, error) {
81+
secretKey, err := bls12381.NewPrivateKeyFromBytes(privKey.Key)
82+
if err != nil {
83+
return nil, err
84+
}
85+
86+
return secretKey.Sign(msg)
87+
}
88+
89+
// MarshalAmino overrides Amino binary marshaling.
90+
func (privKey PrivKey) MarshalAmino() ([]byte, error) {
91+
return privKey.Key, nil
92+
}
93+
94+
// UnmarshalAmino overrides Amino binary marshaling.
95+
func (privKey *PrivKey) UnmarshalAmino(bz []byte) error {
96+
if len(bz) != bls12381.PrivKeySize {
97+
return errors.New("invalid privkey size")
98+
}
99+
privKey.Key = bz
100+
101+
return nil
102+
}
103+
104+
// MarshalAminoJSON overrides Amino JSON marshaling.
105+
func (privKey PrivKey) MarshalAminoJSON() ([]byte, error) {
106+
// When we marshal to Amino JSON, we don't marshal the "key" field itself,
107+
// just its contents (i.e. the key bytes).
108+
return privKey.MarshalAmino()
109+
}
110+
111+
// UnmarshalAminoJSON overrides Amino JSON marshaling.
112+
func (privKey *PrivKey) UnmarshalAminoJSON(bz []byte) error {
113+
return privKey.UnmarshalAmino(bz)
114+
}
115+
116+
// ===============================================================================================
117+
// Public Key
118+
// ===============================================================================================
119+
120+
// Pubkey is a wrapper around the Ethereum BLS12-381 public key type. This
121+
// wrapper conforms to crypto.Pubkey to allow for the use of the Ethereum
122+
// BLS12-381 public key type.
123+
124+
var _ cryptotypes.PubKey = &PubKey{}
125+
126+
// Address returns the address of the key.
127+
//
128+
// The function will panic if the public key is invalid.
129+
func (pubKey PubKey) Address() crypto.Address {
130+
pk, _ := bls12381.NewPublicKeyFromBytes(pubKey.Key)
131+
if len(pk.Bytes()) != bls12381.PubKeySize {
132+
panic("pubkey is incorrect size")
133+
}
134+
return crypto.Address(tmhash.SumTruncated(pubKey.Key))
135+
}
136+
137+
// VerifySignature verifies the given signature.
138+
func (pubKey PubKey) VerifySignature(msg, sig []byte) bool {
139+
if len(sig) != bls12381.SignatureLength {
140+
return false
141+
}
142+
143+
pubK, err := bls12381.NewPublicKeyFromBytes(pubKey.Key)
144+
if err != nil { // invalid pubkey
145+
return false
146+
}
147+
148+
return pubK.VerifySignature(msg, sig)
149+
}
150+
151+
// Bytes returns the byte format.
152+
func (pubKey PubKey) Bytes() []byte {
153+
return pubKey.Key
154+
}
155+
156+
// Type returns the key's type.
157+
func (PubKey) Type() string {
158+
return bls12381.KeyType
159+
}
160+
161+
// Equals returns true if the other's type is the same and their bytes are deeply equal.
162+
func (pubKey PubKey) Equals(other cryptotypes.PubKey) bool {
163+
return pubKey.Type() == other.Type() && bytes.Equal(pubKey.Bytes(), other.Bytes())
164+
}
165+
166+
// String returns Hex representation of a pubkey with it's type
167+
func (pubKey PubKey) String() string {
168+
return fmt.Sprintf("PubKeyBLS12_381{%X}", pubKey.Key)
169+
}

0 commit comments

Comments
 (0)