Skip to content

Commit 1a46a9b

Browse files
epic(eth): protos, go-ethereum, eth types, and evm module types (#1837)
* feat(eth): protos, eth types, and evm module types * chore: changelog * feat(eth): unit tests for types, crypto, encoding (#1838) * feat(eth): unit tests for types, crypto, encoding ## Impl `go-ethereum` Adds `go-ethereum` fork with an `Interpreter` interface for running smart contracts in integration tests. ```go type Interpreter interface { // Run loops and evaluates the contract's code with the given input data and returns // the return byte-slice and an error if one occurred. Run(contract *Contract, input []byte, static bool) ([]byte, error) } ``` An `Interpreter` is used to run Ethereum based contracts and will utilize the passed environment to query external sources for state information. The Interpreter will run the byte code VM based on the passed configuration. Changes from go-ethereum v1.11: * Set `callcode` to use `readOnly` mode for precompiled calls. * Remove `IsStateful` function from the `PrecompiledContract` interface, as this remains unused. * Support stateful precompiled contracts. * Add `Address` function to `PrecompiledContract` interface. * Implement custom active precompiles for the EVM. * Define `Interpreter` interface for the EVM. * Move the `JumpTable` defaults to a separate function. * Refactor `Stack` implementation * chore: linter * docs(sample.go): PrivKeyEth * refactor: fix copyright lines and LICENSE entity * feat(eth): Collections encoders for bytes, Ethereum addresses, and Ethereum hashes (#1841)
1 parent 92662eb commit 1a46a9b

File tree

1,894 files changed

+695438
-27
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,894 files changed

+695438
-27
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
5858
- [#1823](https://github.com/NibiruChain/nibiru/pull/1823) - feat(inflation): add burn method
5959
- [#1832](https://github.com/NibiruChain/nibiru/pull/1832) - feat(tokenfactory): add burn method for native tokens
6060

61+
#### Nibiru EVM
62+
63+
- [#1837](https://github.com/NibiruChain/nibiru/pull/1837) - feat(eth): protos, eth types, and evm module types
64+
- [#1838](https://github.com/NibiruChain/nibiru/pull/1838) - feat(eth): Go-ethereum, crypto, encoding, and unit tests for evm/types
65+
- [#1841](https://github.com/NibiruChain/nibiru/pull/1841) - feat(eth): Collections encoders for bytes, Ethereum addresses, and Ethereum hashes
66+
6167
#### Dapp modules: perp, spot, etc
6268

6369
- [#1573](https://github.com/NibiruChain/nibiru/pull/1573) - feat(perp): Close markets and compute settlement price

LICENSE.md

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@
186186
same "printed page" as the copyright notice for easier
187187
identification within third-party archives.
188188

189-
Copyright 2020 Nibiru Labs, Inc.
189+
Copyright 2024 MTRX Services Ltd.
190190

191191
Licensed under the Apache License, Version 2.0 (the "License");
192192
you may not use this file except in compliance with the License.
@@ -199,9 +199,3 @@
199199
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200200
See the License for the specific language governing permissions and
201201
limitations under the License.
202-
$10-worth New Year Gift for You
203-
Make your 2022 productive
204-
with LINER Premium
205-
206-
Dismiss
207-
Open the gift

cmd/ethclient/const.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package ethclient
2+
3+
const Bech32Prefix = "nibi"

eth/crypto/codec/amino.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright (c) 2023-2024 Nibi, Inc.
2+
package codec
3+
4+
import (
5+
"github.com/cosmos/cosmos-sdk/codec"
6+
"github.com/cosmos/cosmos-sdk/codec/legacy"
7+
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
8+
"github.com/cosmos/cosmos-sdk/crypto/keyring"
9+
10+
"github.com/NibiruChain/nibiru/eth/crypto/ethsecp256k1"
11+
)
12+
13+
// RegisterCrypto registers all crypto dependency types with the provided Amino
14+
// codec.
15+
func RegisterCrypto(cdc *codec.LegacyAmino) {
16+
cdc.RegisterConcrete(&ethsecp256k1.PubKey{},
17+
ethsecp256k1.PubKeyName, nil)
18+
cdc.RegisterConcrete(&ethsecp256k1.PrivKey{},
19+
ethsecp256k1.PrivKeyName, nil)
20+
21+
keyring.RegisterLegacyAminoCodec(cdc)
22+
cryptocodec.RegisterCrypto(cdc)
23+
24+
// NOTE: update SDK's amino codec to include the ethsecp256k1 keys.
25+
// DO NOT REMOVE unless deprecated on the SDK.
26+
legacy.Cdc = cdc
27+
}

eth/crypto/codec/codec.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright (c) 2023-2024 Nibi, Inc.
2+
package codec
3+
4+
import (
5+
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
6+
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
7+
8+
"github.com/NibiruChain/nibiru/eth/crypto/ethsecp256k1"
9+
)
10+
11+
// RegisterInterfaces register the cryptographic key concrete types.
12+
func RegisterInterfaces(registry codectypes.InterfaceRegistry) {
13+
registry.RegisterImplementations((*cryptotypes.PubKey)(nil), &ethsecp256k1.PubKey{})
14+
registry.RegisterImplementations((*cryptotypes.PrivKey)(nil), &ethsecp256k1.PrivKey{})
15+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package ethsecp256k1
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
)
7+
8+
func BenchmarkGenerateKey(b *testing.B) {
9+
b.ReportAllocs()
10+
for i := 0; i < b.N; i++ {
11+
if _, err := GenerateKey(); err != nil {
12+
b.Fatal(err)
13+
}
14+
}
15+
}
16+
17+
func BenchmarkPubKey_VerifySignature(b *testing.B) {
18+
privKey, err := GenerateKey()
19+
if err != nil {
20+
b.Fatal(err)
21+
}
22+
pubKey := privKey.PubKey()
23+
24+
b.ResetTimer()
25+
b.ReportAllocs()
26+
for i := 0; i < b.N; i++ {
27+
msg := []byte(fmt.Sprintf("%10d", i))
28+
sig, err := privKey.Sign(msg)
29+
if err != nil {
30+
b.Fatal(err)
31+
}
32+
pubKey.VerifySignature(msg, sig)
33+
}
34+
}
Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
// Copyright (c) 2023-2024 Nibi, Inc.
2+
3+
package ethsecp256k1
4+
5+
import (
6+
"bytes"
7+
"crypto/ecdsa"
8+
"crypto/subtle"
9+
"fmt"
10+
11+
errorsmod "cosmossdk.io/errors"
12+
tmcrypto "github.com/cometbft/cometbft/crypto"
13+
"github.com/cosmos/cosmos-sdk/codec"
14+
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
15+
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
16+
"github.com/ethereum/go-ethereum/crypto"
17+
18+
"github.com/NibiruChain/nibiru/eth/ethereum/eip712"
19+
)
20+
21+
const (
22+
// PrivKeySize defines the size of the PrivKey bytes
23+
PrivKeySize = 32
24+
// PubKeySize defines the size of the PubKey bytes
25+
PubKeySize = 33
26+
// KeyType is the string constant for the Secp256k1 algorithm
27+
KeyType = "eth_secp256k1"
28+
)
29+
30+
// Amino encoding names
31+
const (
32+
// PrivKeyName defines the amino encoding name for the EthSecp256k1 private key
33+
PrivKeyName = "ethermint/PrivKeyEthSecp256k1"
34+
// PubKeyName defines the amino encoding name for the EthSecp256k1 public key
35+
PubKeyName = "ethermint/PubKeyEthSecp256k1"
36+
)
37+
38+
// ----------------------------------------------------------------------------
39+
// secp256k1 Private Key
40+
41+
var (
42+
_ cryptotypes.PrivKey = &PrivKey{}
43+
_ codec.AminoMarshaler = &PrivKey{}
44+
)
45+
46+
// GenerateKey generates a new random private key. It returns an error upon
47+
// failure.
48+
func GenerateKey() (*PrivKey, error) {
49+
priv, err := crypto.GenerateKey()
50+
if err != nil {
51+
return nil, err
52+
}
53+
54+
return &PrivKey{
55+
Key: crypto.FromECDSA(priv),
56+
}, nil
57+
}
58+
59+
// Bytes returns the byte representation of the ECDSA Private Key.
60+
func (privKey PrivKey) Bytes() []byte {
61+
bz := make([]byte, len(privKey.Key))
62+
copy(bz, privKey.Key)
63+
64+
return bz
65+
}
66+
67+
// PubKey returns the ECDSA private key's public key. If the privkey is not valid
68+
// it returns a nil value.
69+
func (privKey PrivKey) PubKey() cryptotypes.PubKey {
70+
ecdsaPrivKey, err := privKey.ToECDSA()
71+
if err != nil {
72+
return nil
73+
}
74+
75+
return &PubKey{
76+
Key: crypto.CompressPubkey(&ecdsaPrivKey.PublicKey),
77+
}
78+
}
79+
80+
// Equals returns true if two ECDSA private keys are equal and false otherwise.
81+
func (privKey PrivKey) Equals(other cryptotypes.LedgerPrivKey) bool {
82+
return privKey.Type() == other.Type() && subtle.ConstantTimeCompare(privKey.Bytes(), other.Bytes()) == 1
83+
}
84+
85+
// Type returns eth_secp256k1
86+
func (privKey PrivKey) Type() string {
87+
return KeyType
88+
}
89+
90+
// MarshalAmino overrides Amino binary marshaling.
91+
func (privKey PrivKey) MarshalAmino() ([]byte, error) {
92+
return privKey.Key, nil
93+
}
94+
95+
// UnmarshalAmino overrides Amino binary marshaling.
96+
func (privKey *PrivKey) UnmarshalAmino(bz []byte) error {
97+
if len(bz) != PrivKeySize {
98+
return fmt.Errorf("invalid privkey size, expected %d got %d", PrivKeySize, len(bz))
99+
}
100+
privKey.Key = bz
101+
102+
return nil
103+
}
104+
105+
// MarshalAminoJSON overrides Amino JSON marshaling.
106+
func (privKey PrivKey) MarshalAminoJSON() ([]byte, error) {
107+
// When we marshal to Amino JSON, we don't marshal the "key" field itself,
108+
// just its contents (i.e. the key bytes).
109+
return privKey.MarshalAmino()
110+
}
111+
112+
// UnmarshalAminoJSON overrides Amino JSON marshaling.
113+
func (privKey *PrivKey) UnmarshalAminoJSON(bz []byte) error {
114+
return privKey.UnmarshalAmino(bz)
115+
}
116+
117+
// Sign creates a recoverable ECDSA signature on the secp256k1 curve over the
118+
// provided hash of the message. The produced signature is 65 bytes
119+
// where the last byte contains the recovery ID.
120+
func (privKey PrivKey) Sign(digestBz []byte) ([]byte, error) {
121+
// TODO: remove
122+
if len(digestBz) != crypto.DigestLength {
123+
digestBz = crypto.Keccak256Hash(digestBz).Bytes()
124+
}
125+
126+
key, err := privKey.ToECDSA()
127+
if err != nil {
128+
return nil, err
129+
}
130+
131+
return crypto.Sign(digestBz, key)
132+
}
133+
134+
// ToECDSA returns the ECDSA private key as a reference to ecdsa.PrivateKey type.
135+
func (privKey PrivKey) ToECDSA() (*ecdsa.PrivateKey, error) {
136+
return crypto.ToECDSA(privKey.Bytes())
137+
}
138+
139+
// ----------------------------------------------------------------------------
140+
// secp256k1 Public Key
141+
142+
var (
143+
_ cryptotypes.PubKey = &PubKey{}
144+
_ codec.AminoMarshaler = &PubKey{}
145+
)
146+
147+
// Address returns the address of the ECDSA public key.
148+
// The function will return an empty address if the public key is invalid.
149+
func (pubKey PubKey) Address() tmcrypto.Address {
150+
pubk, err := crypto.DecompressPubkey(pubKey.Key)
151+
if err != nil {
152+
return nil
153+
}
154+
155+
return tmcrypto.Address(crypto.PubkeyToAddress(*pubk).Bytes())
156+
}
157+
158+
// Bytes returns the raw bytes of the ECDSA public key.
159+
func (pubKey PubKey) Bytes() []byte {
160+
bz := make([]byte, len(pubKey.Key))
161+
copy(bz, pubKey.Key)
162+
163+
return bz
164+
}
165+
166+
// String implements the fmt.Stringer interface.
167+
func (pubKey PubKey) String() string {
168+
return fmt.Sprintf("EthPubKeySecp256k1{%X}", pubKey.Key)
169+
}
170+
171+
// Type returns eth_secp256k1
172+
func (pubKey PubKey) Type() string {
173+
return KeyType
174+
}
175+
176+
// Equals returns true if the pubkey type is the same and their bytes are deeply equal.
177+
func (pubKey PubKey) Equals(other cryptotypes.PubKey) bool {
178+
return pubKey.Type() == other.Type() && bytes.Equal(pubKey.Bytes(), other.Bytes())
179+
}
180+
181+
// MarshalAmino overrides Amino binary marshaling.
182+
func (pubKey PubKey) MarshalAmino() ([]byte, error) {
183+
return pubKey.Key, nil
184+
}
185+
186+
// UnmarshalAmino overrides Amino binary marshaling.
187+
func (pubKey *PubKey) UnmarshalAmino(bz []byte) error {
188+
if len(bz) != PubKeySize {
189+
return errorsmod.Wrapf(errortypes.ErrInvalidPubKey, "invalid pubkey size, expected %d, got %d", PubKeySize, len(bz))
190+
}
191+
pubKey.Key = bz
192+
193+
return nil
194+
}
195+
196+
// MarshalAminoJSON overrides Amino JSON marshaling.
197+
func (pubKey PubKey) MarshalAminoJSON() ([]byte, error) {
198+
// When we marshal to Amino JSON, we don't marshal the "key" field itself,
199+
// just its contents (i.e. the key bytes).
200+
return pubKey.MarshalAmino()
201+
}
202+
203+
// UnmarshalAminoJSON overrides Amino JSON marshaling.
204+
func (pubKey *PubKey) UnmarshalAminoJSON(bz []byte) error {
205+
return pubKey.UnmarshalAmino(bz)
206+
}
207+
208+
// VerifySignature verifies that the ECDSA public key created a given signature over
209+
// the provided message. It will calculate the Keccak256 hash of the message
210+
// prior to verification and approve verification if the signature can be verified
211+
// from either the original message or its EIP-712 representation.
212+
//
213+
// CONTRACT: The signature should be in [R || S] format.
214+
func (pubKey PubKey) VerifySignature(msg, sig []byte) bool {
215+
return pubKey.verifySignatureECDSA(msg, sig) || pubKey.verifySignatureAsEIP712(msg, sig)
216+
}
217+
218+
// Verifies the signature as an EIP-712 signature by first converting the message payload
219+
// to EIP-712 object bytes, then performing ECDSA verification on the hash. This is to support
220+
// signing a Cosmos payload using EIP-712.
221+
func (pubKey PubKey) verifySignatureAsEIP712(msg, sig []byte) bool {
222+
eip712Bytes, err := eip712.GetEIP712BytesForMsg(msg)
223+
if err != nil {
224+
return false
225+
}
226+
227+
if pubKey.verifySignatureECDSA(eip712Bytes, sig) {
228+
return true
229+
}
230+
231+
// Try verifying the signature using the legacy EIP-712 encoding
232+
legacyEIP712Bytes, err := eip712.LegacyGetEIP712BytesForMsg(msg)
233+
if err != nil {
234+
return false
235+
}
236+
237+
return pubKey.verifySignatureECDSA(legacyEIP712Bytes, sig)
238+
}
239+
240+
// Perform standard ECDSA signature verification for the given raw bytes and signature.
241+
func (pubKey PubKey) verifySignatureECDSA(msg, sig []byte) bool {
242+
if len(sig) == crypto.SignatureLength {
243+
// remove recovery ID (V) if contained in the signature
244+
sig = sig[:len(sig)-1]
245+
}
246+
247+
// the signature needs to be in [R || S] format when provided to VerifySignature
248+
return crypto.VerifySignature(pubKey.Key, crypto.Keccak256Hash(msg).Bytes(), sig)
249+
}

0 commit comments

Comments
 (0)