Skip to content
This repository has been archived by the owner on Jun 9, 2024. It is now read-only.

feat(crypto): Ethereum secp256k1 #20

Merged
merged 8 commits into from
Jan 13, 2023
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
1 change: 0 additions & 1 deletion build/.golangci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,6 @@ linters:
- gomodguard # allow and block lists linter for direct Go module dependencies. This is different from depguard where there are different block types for example version constraints and module recommendations
- goprintffuncname # checks that printf-like functions are named with f at the end
- gosec # inspects source code for security problems
- ireturn # accept interfaces, return concrete types
- lll # reports long lines
- loggercheck # checks key value pairs for common logger libraries (kitlog,klog,logr,zap)
- makezero # finds slice declarations with non-zero initial length
Expand Down
123 changes: 0 additions & 123 deletions build/scripts/run-local-dev.sh

This file was deleted.

11 changes: 5 additions & 6 deletions core/state/types/state.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 10 additions & 2 deletions crypto/crypto.go → crypto/crypto_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@

package crypto

import "github.com/ethereum/go-ethereum/crypto"
import (
"testing"

var Keccak256Hash = crypto.Keccak256Hash
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

func TestCrypto(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "crypto")
}
31 changes: 31 additions & 0 deletions crypto/imported.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (C) 2023, Berachain Foundation. All rights reserved.
// See the file LICENSE for licensing terms.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package crypto

import "github.com/ethereum/go-ethereum/crypto"

var (
CompressPubkey = crypto.CompressPubkey
DecompressPubkey = crypto.DecompressPubkey
DigestLength = crypto.DigestLength
EthSign = crypto.Sign
FromECDSA = crypto.FromECDSA
GenerateEthKey = crypto.GenerateKey
Keccak256Hash = crypto.Keccak256Hash
PubkeyToAddress = crypto.PubkeyToAddress
SignatureLength = crypto.SignatureLength
ToECDSA = crypto.ToECDSA
VerifySignature = crypto.VerifySignature
)
154 changes: 154 additions & 0 deletions crypto/secp256k1.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
// Copyright (C) 2023, Berachain Foundation. All rights reserved.
// See the file LICENSE for licensing terms.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package crypto

import (
"bytes"
"crypto/ecdsa"
"crypto/subtle"

cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
tmcrypto "github.com/tendermint/tendermint/crypto"
)

const (
// `PrivKeyNumBytes` defines the length of the PrivKey byte array.
PrivKeyNumBytes = 32
// `PubKeyNumBytes` defines the length of the PubKey byte array.
PubKeyNumBytes = PrivKeyNumBytes + 1
// `KeyType` is the string constant for the secp256k1 algorithm.
KeyType = "eth_secp256k1"
)

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

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

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

// `Address` returns the address of the ECDSA public key.
// The function will return an empty address if the public key is invalid.
func (pubKey EthSecp256K1PubKey) Address() tmcrypto.Address {
pubk, err := DecompressPubkey(pubKey.Key)
if err != nil {
return nil
}

return tmcrypto.Address(PubkeyToAddress(*pubk).Bytes())
}

// `Bytes` returns the raw bytes of the ECDSA public key.
func (pubKey EthSecp256K1PubKey) Bytes() []byte {
bz := make([]byte, len(pubKey.Key))
copy(bz, pubKey.Key)

return bz
}

// `Type` returns eth_secp256k1.
func (pubKey EthSecp256K1PubKey) Type() string {
return KeyType
}

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

// `VerifySignature` verifies that the ECDSA public key created a given signature over
// the provided message. The signature should be in [R || S] format.
func (pubKey EthSecp256K1PubKey) VerifySignature(msg, sig []byte) bool {
if len(sig) == 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 VerifySignature(pubKey.Key, Keccak256Hash(msg).Bytes(), sig)
}

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

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

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

// `GenerateKey` generates a new random private key. It returns an error upon
// failure.
func GenerateKey() (*EthSecp256K1PrivKey, error) {
priv, err := GenerateEthKey()
if err != nil {
return nil, err
}

return &EthSecp256K1PrivKey{
Key: FromECDSA(priv),
}, nil
}

// `Bytes` returns the byte representation of the ECDSA Private Key.
func (privKey EthSecp256K1PrivKey) 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 EthSecp256K1PrivKey) PubKey() cryptotypes.PubKey {
ecdsaPrivKey, err := privKey.ToECDSA()
if err != nil {
return nil
}

return &EthSecp256K1PubKey{
Key: CompressPubkey(&ecdsaPrivKey.PublicKey),
}
}

// `Equals` returns true if two ECDSA private keys are equal and false otherwise.
func (privKey EthSecp256K1PrivKey) Equals(other cryptotypes.LedgerPrivKey) bool {
return privKey.Type() == other.Type() && subtle.ConstantTimeCompare(privKey.Bytes(), other.Bytes()) == 1
}

// `Type` returns eth_secp256k1.
func (privKey EthSecp256K1PrivKey) Type() string {
return KeyType
}

// `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 EthSecp256K1PrivKey) Sign(digestBz []byte) ([]byte, error) {
key, err := privKey.ToECDSA()
if err != nil {
return nil, err
}

return EthSign(digestBz, key)
}

// `ToECDSA` returns the ECDSA private key as a reference to ecdsa.PrivateKey type.
func (privKey EthSecp256K1PrivKey) ToECDSA() (*ecdsa.PrivateKey, error) {
return ToECDSA(privKey.Bytes())
}
Loading