/
public_key.go
119 lines (102 loc) · 3.3 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
package vrfkey
import (
"fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"go.dedis.ch/kyber/v3"
"github.com/smartcontractkit/chainlink/core/services/signatures/secp256k1"
"github.com/smartcontractkit/chainlink/core/utils"
)
// PublicKey is a secp256k1 point in compressed format
type PublicKey [CompressedPublicKeyLength]byte
// CompressedPublicKeyLength is the length of a secp256k1 public key's x
// ordinate as a uint256, concatenated with 00 if y is even, 01 if odd.
const CompressedPublicKeyLength = 33
func init() {
if CompressedPublicKeyLength != (&secp256k1.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.Secp256k1{}).Point()
return p, p.UnmarshalBinary(k[:])
}
// NewPublicKey returns the PublicKey corresponding to rawKey
func NewPublicKey(rawKey [CompressedPublicKeyLength]byte) *PublicKey {
rv := PublicKey(rawKey)
return &rv
}
// 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
}
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, err
}
// 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(secp256k1.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(secp256k1.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{}
}