-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
public_key.go
150 lines (128 loc) · 4.15 KB
/
public_key.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package secp256k1
import (
"database/sql/driver"
"fmt"
"github.com/pkg/errors"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"go.dedis.ch/kyber/v3"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
)
// PublicKey is a secp256k1 point in compressed format
type PublicKey [CompressedPublicKeyLength]byte
// CompressedPublicKeyLength is the length of a secp256k1 public key's x
// coordinate as a uint256, concatenated with 00 if y is even, 01 if odd.
const CompressedPublicKeyLength = 33
func init() {
if CompressedPublicKeyLength != (&Secp256k1{}).Point().MarshalSize() {
panic("disparity in expected public key lengths")
}
}
// Set sets k to the public key represented by l
func (k *PublicKey) Set(l PublicKey) {
if copy(k[:], l[:]) != CompressedPublicKeyLength {
panic(fmt.Errorf("failed to copy entire public key %x to %x", l, k))
}
}
// Point returns the secp256k1 point corresponding to k
func (k *PublicKey) Point() (kyber.Point, error) {
p := (&Secp256k1{}).Point()
return p, p.UnmarshalBinary(k[:])
}
// NewPublicKeyFromHex returns the PublicKey encoded by 0x-hex string hex, or errors
func NewPublicKeyFromHex(hex string) (PublicKey, error) {
rawKey, err := hexutil.Decode(hex)
if err != nil {
return PublicKey{}, err
}
return NewPublicKeyFromBytes(rawKey)
}
// NewPublicKeyFromBytes returns the PublicKey built from the given bytes, or errors
func NewPublicKeyFromBytes(rawKey []byte) (PublicKey, error) {
if l := len(rawKey); l != CompressedPublicKeyLength {
return PublicKey{}, fmt.Errorf(
"wrong length for public key: %s of length %d", rawKey, l)
}
var k PublicKey
if c := copy(k[:], rawKey); c != CompressedPublicKeyLength {
panic(fmt.Errorf("failed to copy entire key to return value"))
}
return k, nil
}
// SetFromHex sets k to the public key represented by hex, which must represent
// the compressed binary format
func (k *PublicKey) SetFromHex(hex string) error {
nk, err := NewPublicKeyFromHex(hex)
if err != nil {
return err
}
k.Set(nk)
return nil
}
// String returns k's binary compressed representation, as 0x-hex
func (k PublicKey) String() string {
return hexutil.Encode(k[:])
}
// StringUncompressed returns k's binary uncompressed representation, as 0x-hex
func (k *PublicKey) StringUncompressed() (string, error) {
p, err := k.Point()
if err != nil {
return "", err
}
return hexutil.Encode(LongMarshal(p)), nil
}
// Hash returns the solidity Keccak256 hash of k. Corresponds to hashOfKey on
// VRFCoordinator.
func (k *PublicKey) Hash() (common.Hash, error) {
p, err := k.Point()
if err != nil {
return common.Hash{}, err
}
return utils.MustHash(string(LongMarshal(p))), nil
}
// MustHash is like Hash, but panics on error. Useful for testing.
func (k *PublicKey) MustHash() common.Hash {
hash, err := k.Hash()
if err != nil {
panic(fmt.Sprintf("Failed to compute hash of public vrf key %v", k))
}
return hash
}
// Address returns the Ethereum address of k or 0 if the key is invalid
func (k *PublicKey) Address() common.Address {
hash, err := k.Hash()
if err != nil {
return common.Address{}
}
return common.BytesToAddress(hash.Bytes()[12:])
}
// IsZero returns true iff k is the zero value for PublicKey
func (k *PublicKey) IsZero() bool {
return *k == PublicKey{}
}
// MarshalText renders k as a text string
func (k PublicKey) MarshalText() ([]byte, error) {
return []byte(k.String()), nil
}
// UnmarshalText reads a PublicKey into k from text, or errors
func (k *PublicKey) UnmarshalText(text []byte) error {
if err := k.SetFromHex(string(text)); err != nil {
return errors.Wrapf(err, "while parsing %s as public key", text)
}
return nil
}
// Value marshals PublicKey to be saved in the DB
func (k PublicKey) Value() (driver.Value, error) {
return k.String(), nil
}
// Scan reconstructs a PublicKey from a DB record of it.
func (k *PublicKey) Scan(value interface{}) error {
rawKey, ok := value.(string)
if !ok {
return errors.Wrap(fmt.Errorf("unable to convert %+v of type %T to PublicKey", value, value), "scan failure")
}
if err := k.SetFromHex(rawKey); err != nil {
return errors.Wrapf(err, "while scanning %s as PublicKey", rawKey)
}
return nil
}