/
ethsecp256k1.go
135 lines (109 loc) · 3.99 KB
/
ethsecp256k1.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package ethsecp256k1
import (
"bytes"
"crypto/ecdsa"
ethcrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/secp256k1"
tmcrypto "github.com/tendermint/tendermint/crypto"
)
const (
// PrivKeySize defines the size of the PrivKey bytes
PrivKeySize = 32
// KeyType is the string constant for the EthSecp256k1 algorithm
KeyType = "eth_secp256k1"
)
// Amino encoding names
const (
// PrivKeyName defines the amino encoding name for the EthSecp256k1 private key
PrivKeyName = "dogschain/PrivKeyEthSecp256k1"
// PubKeyName defines the amino encoding name for the EthSecp256k1 public key
PubKeyName = "dogschain/PubKeyEthSecp256k1"
)
// ----------------------------------------------------------------------------
// secp256k1 Private Key
var _ tmcrypto.PrivKey = PrivKey{}
// PrivKey defines a type alias for an ecdsa.PrivateKey that implements
// Tendermint's PrivateKey interface.
type PrivKey []byte
// GenerateKey generates a new random private key. It returns an error upon
// failure.
func GenerateKey() (PrivKey, error) {
priv, err := ethcrypto.GenerateKey()
if err != nil {
return PrivKey{}, err
}
return PrivKey(ethcrypto.FromECDSA(priv)), nil
}
// PubKey returns the ECDSA private key's public key.
func (privkey PrivKey) PubKey() tmcrypto.PubKey {
ecdsaPKey := privkey.ToECDSA()
return PubKey(ethcrypto.CompressPubkey(&ecdsaPKey.PublicKey))
}
// Bytes returns the raw ECDSA private key bytes.
func (privkey PrivKey) Bytes() []byte {
return CryptoCodec.MustMarshalBinaryBare(privkey)
}
// Sign creates a recoverable ECDSA signature on the secp256k1 curve over the
// Keccak256 hash of the provided message. The produced signature is 65 bytes
// where the last byte contains the recovery ID.
func (privkey PrivKey) Sign(msg []byte) ([]byte, error) {
return ethcrypto.Sign(ethcrypto.Keccak256Hash(msg).Bytes(), privkey.ToECDSA())
}
// Equals returns true if two ECDSA private keys are equal and false otherwise.
func (privkey PrivKey) Equals(other tmcrypto.PrivKey) bool {
if other, ok := other.(PrivKey); ok {
return bytes.Equal(privkey.Bytes(), other.Bytes())
}
return false
}
// ToECDSA returns the ECDSA private key as a reference to ecdsa.PrivateKey type.
// The function will panic if the private key is invalid.
func (privkey PrivKey) ToECDSA() *ecdsa.PrivateKey {
key, err := ethcrypto.ToECDSA(privkey)
if err != nil {
panic(err)
}
return key
}
// ----------------------------------------------------------------------------
// secp256k1 Public Key
var _ tmcrypto.PubKey = (*PubKey)(nil)
// PubKey defines a type alias for an ecdsa.PublicKey that implements Tendermint's PubKey
// interface. It represents the 33-byte compressed public key format.
type PubKey []byte
// Address returns the address of the ECDSA public key.
// The function will panic if the public key is invalid.
func (key PubKey) Address() tmcrypto.Address {
pubk, err := ethcrypto.DecompressPubkey(key)
if err != nil {
panic(err)
}
return tmcrypto.Address(ethcrypto.PubkeyToAddress(*pubk).Bytes())
}
// Bytes returns the raw bytes of the ECDSA public key.
// The function panics if the key cannot be marshaled to bytes.
func (key PubKey) Bytes() []byte {
bz, err := CryptoCodec.MarshalBinaryBare(key)
if err != nil {
panic(err)
}
return bz
}
// VerifyBytes 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.
func (key PubKey) VerifyBytes(msg []byte, sig []byte) bool {
if len(sig) == 65 {
// remove recovery ID if contained in the signature
sig = sig[:len(sig)-1]
}
// the signature needs to be in [R || S] format when provided to VerifySignature
return secp256k1.VerifySignature(key, ethcrypto.Keccak256Hash(msg).Bytes(), sig)
}
// Equals returns true if two ECDSA public keys are equal and false otherwise.
func (key PubKey) Equals(other tmcrypto.PubKey) bool {
if other, ok := other.(PubKey); ok {
return bytes.Equal(key.Bytes(), other.Bytes())
}
return false
}