-
Notifications
You must be signed in to change notification settings - Fork 3.6k
/
privkey.go
127 lines (106 loc) · 3.41 KB
/
privkey.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
package ecdsa
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
"fmt"
"math/big"
)
// p256Order returns the curve order for the secp256r1 curve
// NOTE: this is specific to the secp256r1/P256 curve,
// and not taken from the domain params for the key itself
// (which would be a more generic approach for all EC).
var p256Order = elliptic.P256().Params().N
// p256HalfOrder returns half the curve order
// a bit shift of 1 to the right (Rsh) is equivalent
// to division by 2, only faster.
var p256HalfOrder = new(big.Int).Rsh(p256Order, 1)
// IsSNormalized returns true for the integer sigS if sigS falls in
// lower half of the curve order
func IsSNormalized(sigS *big.Int) bool {
return sigS.Cmp(p256HalfOrder) != 1
}
// NormalizeS will invert the s value if not already in the lower half
// of curve order value
func NormalizeS(sigS *big.Int) *big.Int {
if IsSNormalized(sigS) {
return sigS
}
return new(big.Int).Sub(p256Order, sigS)
}
// signatureRaw will serialize signature to R || S.
// R, S are padded to 32 bytes respectively.
// code roughly copied from secp256k1_nocgo.go
func signatureRaw(r *big.Int, s *big.Int) []byte {
rBytes := r.Bytes()
sBytes := s.Bytes()
sigBytes := make([]byte, 64)
// 0 pad the byte arrays from the left if they aren't big enough.
copy(sigBytes[32-len(rBytes):32], rBytes)
copy(sigBytes[64-len(sBytes):64], sBytes)
return sigBytes
}
// GenPrivKey generates a new secp256r1 private key. It uses operating
// system randomness.
func GenPrivKey(curve elliptic.Curve) (PrivKey, error) {
key, err := ecdsa.GenerateKey(curve, rand.Reader)
if err != nil {
return PrivKey{}, err
}
return PrivKey{*key}, nil
}
type PrivKey struct {
ecdsa.PrivateKey
}
// PubKey returns ECDSA public key associated with this private key.
func (sk *PrivKey) PubKey() PubKey {
return PubKey{sk.PublicKey, nil}
}
// Bytes serialize the private key using big-endian.
func (sk *PrivKey) Bytes() []byte {
if sk == nil {
return nil
}
fieldSize := (sk.Curve.Params().BitSize + 7) / 8
bz := make([]byte, fieldSize)
sk.D.FillBytes(bz)
return bz
}
// Sign hashes and signs the message using ECDSA. Implements SDK
// PrivKey interface.
// NOTE: this now calls the ecdsa Sign function
// (not method!) directly as the s value of the signature is needed to
// low-s normalize the signature value
// See issue: https://github.com/cosmos/cosmos-sdk/issues/9723
// It then raw encodes the signature as two fixed width 32-byte values
// concatenated, reusing the code copied from secp256k1_nocgo.go
func (sk *PrivKey) Sign(msg []byte) ([]byte, error) {
digest := sha256.Sum256(msg)
r, s, err := ecdsa.Sign(rand.Reader, &sk.PrivateKey, digest[:])
if err != nil {
return nil, err
}
normS := NormalizeS(s)
return signatureRaw(r, normS), nil
}
// String returns a string representation of the public key based on the curveName.
func (sk *PrivKey) String(name string) string {
return name + "{-}"
}
// MarshalTo implements proto.Marshaler interface.
func (sk *PrivKey) MarshalTo(dAtA []byte) (int, error) {
bz := sk.Bytes()
copy(dAtA, bz)
return len(bz), nil
}
// Unmarshal implements proto.Marshaler interface.
func (sk *PrivKey) Unmarshal(bz []byte, curve elliptic.Curve, expectedSize int) error {
if len(bz) != expectedSize {
return fmt.Errorf("wrong ECDSA SK bytes, expecting %d bytes", expectedSize)
}
sk.Curve = curve
sk.D = new(big.Int).SetBytes(bz)
sk.X, sk.Y = curve.ScalarBaseMult(bz)
return nil
}