-
Notifications
You must be signed in to change notification settings - Fork 202
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(eth): protos, go-ethereum, eth types, and evm module types #1837
Changes from all commits
7871ecc
a7d7e90
f7a9a66
c2a3807
dd6a100
048393b
182ea3a
a1d11cd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
package ethclient | ||
|
||
const Bech32Prefix = "nibi" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// Copyright (c) 2023-2024 Nibi, Inc. | ||
package codec | ||
|
||
import ( | ||
"github.com/cosmos/cosmos-sdk/codec" | ||
"github.com/cosmos/cosmos-sdk/codec/legacy" | ||
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" | ||
"github.com/cosmos/cosmos-sdk/crypto/keyring" | ||
|
||
"github.com/NibiruChain/nibiru/eth/crypto/ethsecp256k1" | ||
) | ||
|
||
// RegisterCrypto registers all crypto dependency types with the provided Amino | ||
// codec. | ||
func RegisterCrypto(cdc *codec.LegacyAmino) { | ||
cdc.RegisterConcrete(ðsecp256k1.PubKey{}, | ||
ethsecp256k1.PubKeyName, nil) | ||
cdc.RegisterConcrete(ðsecp256k1.PrivKey{}, | ||
ethsecp256k1.PrivKeyName, nil) | ||
|
||
keyring.RegisterLegacyAminoCodec(cdc) | ||
cryptocodec.RegisterCrypto(cdc) | ||
|
||
// NOTE: update SDK's amino codec to include the ethsecp256k1 keys. | ||
// DO NOT REMOVE unless deprecated on the SDK. | ||
legacy.Cdc = cdc | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// Copyright (c) 2023-2024 Nibi, Inc. | ||
package codec | ||
|
||
import ( | ||
codectypes "github.com/cosmos/cosmos-sdk/codec/types" | ||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" | ||
|
||
"github.com/NibiruChain/nibiru/eth/crypto/ethsecp256k1" | ||
) | ||
|
||
// RegisterInterfaces register the cryptographic key concrete types. | ||
func RegisterInterfaces(registry codectypes.InterfaceRegistry) { | ||
registry.RegisterImplementations((*cryptotypes.PubKey)(nil), ðsecp256k1.PubKey{}) | ||
registry.RegisterImplementations((*cryptotypes.PrivKey)(nil), ðsecp256k1.PrivKey{}) | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,34 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
package ethsecp256k1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"fmt" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"testing" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
func BenchmarkGenerateKey(b *testing.B) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
b.ReportAllocs() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
for i := 0; i < b.N; i++ { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if _, err := GenerateKey(); err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
b.Fatal(err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
func BenchmarkPubKey_VerifySignature(b *testing.B) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
privKey, err := GenerateKey() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
b.Fatal(err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pubKey := privKey.PubKey() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
b.ResetTimer() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
b.ReportAllocs() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
for i := 0; i < b.N; i++ { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
msg := []byte(fmt.Sprintf("%10d", i)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
sig, err := privKey.Sign(msg) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
b.Fatal(err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pubKey.VerifySignature(msg, sig) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+17
to
+34
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider pre-generating the messages outside of the benchmark loop to reduce overhead not directly related to the signature verification process being benchmarked. + messages := make([][]byte, b.N)
+ for i := range messages {
+ messages[i] = []byte(fmt.Sprintf("%10d", i))
+ }
- msg := []byte(fmt.Sprintf("%10d", i))
+ msg := messages[i] Committable suggestion
Suggested change
|
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,249 @@ | ||||||||||
// Copyright (c) 2023-2024 Nibi, Inc. | ||||||||||
|
||||||||||
package ethsecp256k1 | ||||||||||
|
||||||||||
import ( | ||||||||||
"bytes" | ||||||||||
"crypto/ecdsa" | ||||||||||
"crypto/subtle" | ||||||||||
"fmt" | ||||||||||
|
||||||||||
errorsmod "cosmossdk.io/errors" | ||||||||||
tmcrypto "github.com/cometbft/cometbft/crypto" | ||||||||||
"github.com/cosmos/cosmos-sdk/codec" | ||||||||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" | ||||||||||
errortypes "github.com/cosmos/cosmos-sdk/types/errors" | ||||||||||
"github.com/ethereum/go-ethereum/crypto" | ||||||||||
|
||||||||||
"github.com/NibiruChain/nibiru/eth/ethereum/eip712" | ||||||||||
) | ||||||||||
|
||||||||||
const ( | ||||||||||
// PrivKeySize defines the size of the PrivKey bytes | ||||||||||
PrivKeySize = 32 | ||||||||||
// PubKeySize defines the size of the PubKey bytes | ||||||||||
PubKeySize = 33 | ||||||||||
// KeyType is the string constant for the Secp256k1 algorithm | ||||||||||
KeyType = "eth_secp256k1" | ||||||||||
) | ||||||||||
|
||||||||||
// Amino encoding names | ||||||||||
const ( | ||||||||||
// PrivKeyName defines the amino encoding name for the EthSecp256k1 private key | ||||||||||
PrivKeyName = "ethermint/PrivKeyEthSecp256k1" | ||||||||||
// PubKeyName defines the amino encoding name for the EthSecp256k1 public key | ||||||||||
PubKeyName = "ethermint/PubKeyEthSecp256k1" | ||||||||||
) | ||||||||||
|
||||||||||
// ---------------------------------------------------------------------------- | ||||||||||
// secp256k1 Private Key | ||||||||||
|
||||||||||
var ( | ||||||||||
_ cryptotypes.PrivKey = &PrivKey{} | ||||||||||
_ codec.AminoMarshaler = &PrivKey{} | ||||||||||
) | ||||||||||
|
||||||||||
// GenerateKey generates a new random private key. It returns an error upon | ||||||||||
// failure. | ||||||||||
func GenerateKey() (*PrivKey, error) { | ||||||||||
priv, err := crypto.GenerateKey() | ||||||||||
if err != nil { | ||||||||||
return nil, err | ||||||||||
} | ||||||||||
|
||||||||||
return &PrivKey{ | ||||||||||
Key: crypto.FromECDSA(priv), | ||||||||||
}, nil | ||||||||||
} | ||||||||||
|
||||||||||
// Bytes returns the byte representation of the ECDSA Private Key. | ||||||||||
func (privKey PrivKey) Bytes() []byte { | ||||||||||
bz := make([]byte, len(privKey.Key)) | ||||||||||
copy(bz, privKey.Key) | ||||||||||
|
||||||||||
return bz | ||||||||||
} | ||||||||||
|
||||||||||
// 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 { | ||||||||||
ecdsaPrivKey, err := privKey.ToECDSA() | ||||||||||
if err != nil { | ||||||||||
return nil | ||||||||||
} | ||||||||||
|
||||||||||
return &PubKey{ | ||||||||||
Key: crypto.CompressPubkey(&ecdsaPrivKey.PublicKey), | ||||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
// 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() && subtle.ConstantTimeCompare(privKey.Bytes(), other.Bytes()) == 1 | ||||||||||
} | ||||||||||
|
||||||||||
// Type returns eth_secp256k1 | ||||||||||
func (privKey PrivKey) Type() string { | ||||||||||
return KeyType | ||||||||||
} | ||||||||||
|
||||||||||
// 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, expected %d got %d", PrivKeySize, len(bz)) | ||||||||||
} | ||||||||||
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) | ||||||||||
} | ||||||||||
|
||||||||||
// Sign creates a recoverable ECDSA signature on the secp256k1 curve over the | ||||||||||
// provided hash of the message. The produced signature is 65 bytes | ||||||||||
// where the last byte contains the recovery ID. | ||||||||||
func (privKey PrivKey) Sign(digestBz []byte) ([]byte, error) { | ||||||||||
// TODO: remove | ||||||||||
if len(digestBz) != crypto.DigestLength { | ||||||||||
digestBz = crypto.Keccak256Hash(digestBz).Bytes() | ||||||||||
} | ||||||||||
Comment on lines
+121
to
+124
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider removing the modification of the digest based on its length to ensure consistent behavior. - // TODO: remove
- if len(digestBz) != crypto.DigestLength {
- digestBz = crypto.Keccak256Hash(digestBz).Bytes()
- } This modification could lead to unexpected behavior and should be avoided unless there's a specific reason for it. Ensure that the input to the Committable suggestion
Suggested change
|
||||||||||
|
||||||||||
key, err := privKey.ToECDSA() | ||||||||||
if err != nil { | ||||||||||
return nil, err | ||||||||||
} | ||||||||||
|
||||||||||
return crypto.Sign(digestBz, key) | ||||||||||
} | ||||||||||
|
||||||||||
// ToECDSA returns the ECDSA private key as a reference to ecdsa.PrivateKey type. | ||||||||||
func (privKey PrivKey) ToECDSA() (*ecdsa.PrivateKey, error) { | ||||||||||
return crypto.ToECDSA(privKey.Bytes()) | ||||||||||
} | ||||||||||
|
||||||||||
// ---------------------------------------------------------------------------- | ||||||||||
// secp256k1 Public Key | ||||||||||
|
||||||||||
var ( | ||||||||||
_ cryptotypes.PubKey = &PubKey{} | ||||||||||
_ codec.AminoMarshaler = &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() tmcrypto.Address { | ||||||||||
pubk, err := crypto.DecompressPubkey(pubKey.Key) | ||||||||||
if err != nil { | ||||||||||
return nil | ||||||||||
} | ||||||||||
|
||||||||||
return tmcrypto.Address(crypto.PubkeyToAddress(*pubk).Bytes()) | ||||||||||
} | ||||||||||
|
||||||||||
// Bytes returns the raw bytes of the ECDSA public key. | ||||||||||
func (pubKey PubKey) Bytes() []byte { | ||||||||||
bz := make([]byte, len(pubKey.Key)) | ||||||||||
copy(bz, pubKey.Key) | ||||||||||
|
||||||||||
return bz | ||||||||||
} | ||||||||||
|
||||||||||
// String implements the fmt.Stringer interface. | ||||||||||
func (pubKey PubKey) String() string { | ||||||||||
return fmt.Sprintf("EthPubKeySecp256k1{%X}", pubKey.Key) | ||||||||||
} | ||||||||||
|
||||||||||
// Type returns eth_secp256k1 | ||||||||||
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.Wrapf(errortypes.ErrInvalidPubKey, "invalid pubkey size, expected %d, got %d", PubKeySize, len(bz)) | ||||||||||
} | ||||||||||
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) | ||||||||||
} | ||||||||||
|
||||||||||
// VerifySignature verifies that the ECDSA public key created a given signature over | ||||||||||
// the provided message. It will calculate the Keccak256 hash of the message | ||||||||||
// prior to verification and approve verification if the signature can be verified | ||||||||||
// from either the original message or its EIP-712 representation. | ||||||||||
// | ||||||||||
// CONTRACT: The signature should be in [R || S] format. | ||||||||||
func (pubKey PubKey) VerifySignature(msg, sig []byte) bool { | ||||||||||
return pubKey.verifySignatureECDSA(msg, sig) || pubKey.verifySignatureAsEIP712(msg, sig) | ||||||||||
} | ||||||||||
|
||||||||||
// Verifies the signature as an EIP-712 signature by first converting the message payload | ||||||||||
// to EIP-712 object bytes, then performing ECDSA verification on the hash. This is to support | ||||||||||
// signing a Cosmos payload using EIP-712. | ||||||||||
func (pubKey PubKey) verifySignatureAsEIP712(msg, sig []byte) bool { | ||||||||||
eip712Bytes, err := eip712.GetEIP712BytesForMsg(msg) | ||||||||||
if err != nil { | ||||||||||
return false | ||||||||||
} | ||||||||||
|
||||||||||
if pubKey.verifySignatureECDSA(eip712Bytes, sig) { | ||||||||||
return true | ||||||||||
} | ||||||||||
|
||||||||||
// Try verifying the signature using the legacy EIP-712 encoding | ||||||||||
legacyEIP712Bytes, err := eip712.LegacyGetEIP712BytesForMsg(msg) | ||||||||||
if err != nil { | ||||||||||
return false | ||||||||||
} | ||||||||||
|
||||||||||
return pubKey.verifySignatureECDSA(legacyEIP712Bytes, sig) | ||||||||||
} | ||||||||||
|
||||||||||
// Perform standard ECDSA signature verification for the given raw bytes and signature. | ||||||||||
func (pubKey PubKey) verifySignatureECDSA(msg, sig []byte) bool { | ||||||||||
if len(sig) == crypto.SignatureLength { | ||||||||||
// remove recovery ID (V) if contained in the signature | ||||||||||
sig = sig[:len(sig)-1] | ||||||||||
} | ||||||||||
|
||||||||||
// the signature needs to be in [R || S] format when provided to VerifySignature | ||||||||||
return crypto.VerifySignature(pubKey.Key, crypto.Keccak256Hash(msg).Bytes(), sig) | ||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ensure consistency in the formatting of changelog entries. Consider adding a period at the end of each entry to maintain uniformity.
Committable suggestion