-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
key_v2.go
161 lines (142 loc) · 4.47 KB
/
key_v2.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
151
152
153
154
155
156
157
158
159
160
161
package vrfkey
import (
"crypto/rand"
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/pkg/errors"
"go.dedis.ch/kyber/v3"
"github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1"
"github.com/smartcontractkit/chainlink/v2/core/utils"
bm "github.com/smartcontractkit/chainlink/v2/core/utils/big_math"
)
var suite = secp256k1.NewBlakeKeccackSecp256k1()
type Raw []byte
func (raw Raw) Key() KeyV2 {
rawKeyInt := new(big.Int).SetBytes(raw)
k := secp256k1.IntToScalar(rawKeyInt)
key, err := keyFromScalar(k)
if err != nil {
panic(err)
}
return key
}
func (raw Raw) String() string {
return "<VRF Raw Private Key>"
}
func (raw Raw) GoString() string {
return raw.String()
}
var _ fmt.GoStringer = &KeyV2{}
type KeyV2 struct {
k *kyber.Scalar
PublicKey secp256k1.PublicKey
}
func NewV2() (KeyV2, error) {
k := suite.Scalar().Pick(suite.RandomStream())
return keyFromScalar(k)
}
func MustNewV2XXXTestingOnly(k *big.Int) KeyV2 {
rv, err := keyFromScalar(secp256k1.IntToScalar(k))
if err != nil {
panic(err)
}
return rv
}
func (key KeyV2) ID() string {
return hexutil.Encode(key.PublicKey[:])
}
func (key KeyV2) Raw() Raw {
return secp256k1.ToInt(*key.k).Bytes()
}
// GenerateProofWithNonce allows external nonce generation for testing purposes
//
// As with signatures, using nonces which are in any way predictable to an
// adversary will leak your secret key! Most people should use GenerateProof
// instead.
func (key KeyV2) GenerateProofWithNonce(seed, nonce *big.Int) (Proof, error) {
secretKey := secp256k1.ScalarToHash(*key.k).Big()
if !(secp256k1.RepresentsScalar(secretKey) && seed.BitLen() <= 256) {
return Proof{}, fmt.Errorf("badly-formatted key or seed")
}
skAsScalar := secp256k1.IntToScalar(secretKey)
publicKey := Secp256k1Curve.Point().Mul(skAsScalar, nil)
h, err := HashToCurve(publicKey, seed, func(*big.Int) {})
if err != nil {
return Proof{}, errors.Wrap(err, "vrf.makeProof#HashToCurve")
}
gamma := Secp256k1Curve.Point().Mul(skAsScalar, h)
sm := secp256k1.IntToScalar(nonce)
u := Secp256k1Curve.Point().Mul(sm, Generator)
uWitness := secp256k1.EthereumAddress(u)
v := Secp256k1Curve.Point().Mul(sm, h)
c := ScalarFromCurvePoints(h, publicKey, gamma, uWitness, v)
// (m - c*secretKey) % GroupOrder
s := bm.Mod(bm.Sub(nonce, bm.Mul(c, secretKey)), secp256k1.GroupOrder)
if e := checkCGammaNotEqualToSHash(c, gamma, s, h); e != nil {
return Proof{}, e
}
outputHash := utils.MustHash(string(append(RandomOutputHashPrefix,
secp256k1.LongMarshal(gamma)...)))
rv := Proof{
PublicKey: publicKey,
Gamma: gamma,
C: c,
S: s,
Seed: seed,
Output: outputHash.Big(),
}
valid, err := rv.VerifyVRFProof()
if !valid || err != nil {
panic("constructed invalid proof")
}
return rv, nil
}
// GenerateProof returns gamma, plus proof that gamma was constructed from seed
// as mandated from the given secretKey, with public key secretKey*Generator
//
// secretKey and seed must be less than secp256k1 group order. (Without this
// constraint on the seed, the samples and the possible public keys would
// deviate very slightly from uniform distribution.)
func (key KeyV2) GenerateProof(seed *big.Int) (Proof, error) {
for {
nonce, err := rand.Int(rand.Reader, secp256k1.GroupOrder)
if err != nil {
return Proof{}, err
}
proof, err := key.GenerateProofWithNonce(seed, nonce)
switch {
case errors.Is(err, ErrCGammaEqualsSHash):
// This is cryptographically impossible, but if it were ever to happen, we
// should try again with a different nonce.
continue
case err != nil: // Any other error indicates failure
return Proof{}, err
default:
return proof, err // err should be nil
}
}
}
func (key KeyV2) String() string {
return fmt.Sprintf("VRFKeyV2{PublicKey: %s}", key.PublicKey)
}
func (key KeyV2) GoString() string {
return key.String()
}
func keyFromScalar(k kyber.Scalar) (KeyV2, error) {
rawPublicKey, err := secp256k1.ScalarToPublicPoint(k).MarshalBinary()
if err != nil {
return KeyV2{}, errors.Wrapf(err, "could not marshal public key")
}
if len(rawPublicKey) != secp256k1.CompressedPublicKeyLength {
return KeyV2{}, fmt.Errorf("public key %x has wrong length", rawPublicKey)
}
var publicKey secp256k1.PublicKey
if l := copy(publicKey[:], rawPublicKey); l != secp256k1.CompressedPublicKeyLength {
panic(fmt.Errorf("failed to copy correct length in serialized public key"))
}
return KeyV2{
k: &k,
PublicKey: publicKey,
}, nil
}