-
Notifications
You must be signed in to change notification settings - Fork 12
/
ecdsa_privkey.go
149 lines (133 loc) · 5.06 KB
/
ecdsa_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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
package secp256k1
// #include "./depend/secp256k1/include/secp256k1.h"
import "C"
import (
"crypto/rand"
"github.com/pkg/errors"
"unsafe"
)
// ECDSAPrivateKey is a type representing a Secp256k1 ECDSA private key.
type ECDSAPrivateKey struct {
privateKey [SerializedPrivateKeySize]byte
init bool
}
// ECDSAPublicKey generates a PublicKey for the corresponding private key.
func (key *ECDSAPrivateKey) ECDSAPublicKey() (*ECDSAPublicKey, error) {
if !key.init {
return nil, errors.WithStack(errNonInitializedKey)
}
pubkey := ECDSAPublicKey{init: true}
cPtrPrivateKey := (*C.uchar)(&key.privateKey[0])
ret := C.secp256k1_ec_pubkey_create(context, &pubkey.pubkey, cPtrPrivateKey)
if ret != 1 {
return nil, errors.New("failed Generating an ECDSAPublicKey. You should call `DeserializeECDSAPrivateKey` before calling this")
}
return &pubkey, nil
}
// ECDSASign creates an ECDSA signature using the private key and the input hashed message.
// Notice: the [32] byte array *MUST* be a hash of a message.
func (key *ECDSAPrivateKey) ECDSASign(hash *Hash) (*ECDSASignature, error) {
var auxilaryRand [32]byte
n, err := rand.Read(auxilaryRand[:])
if err != nil || n != len(auxilaryRand) {
return nil, err
}
return key.ecdsaSignInternal(hash, &auxilaryRand)
}
func (key *ECDSAPrivateKey) ecdsaSignInternal(hash *Hash, auxiliaryRand *[32]byte) (*ECDSASignature, error) {
if !key.init {
return nil, errNonInitializedKey
}
signature := ECDSASignature{}
cPtrHash := (*C.uchar)(&hash[0])
cPtrPrivKey := (*C.uchar)(&key.privateKey[0])
cPtrAux := unsafe.Pointer(auxiliaryRand)
ret := C.secp256k1_ecdsa_sign(context, &signature.signature, cPtrHash, cPtrPrivKey, C.secp256k1_nonce_function_rfc6979, cPtrAux)
if ret != 1 {
return nil, errors.New("failed Signing. You should call `DeserializeECDSAPrivateKey` before calling this")
}
return &signature, nil
}
// String returns the ECDSAPrivateKey as the hexadecimal string
func (key ECDSAPrivateKey) String() string {
return key.Serialize().String()
}
// DeserializeECDSAPrivateKey returns a ECDSAPrivateKey type from a 32 byte private key.
// will verify it's a valid private key(Group Order > key > 0)
func DeserializeECDSAPrivateKey(data *SerializedPrivateKey) (key *ECDSAPrivateKey, err error) {
cPtr := (*C.uchar)(&data[0])
ret := C.secp256k1_ec_seckey_verify(C.secp256k1_context_no_precomp, cPtr)
if ret != 1 {
return nil, errors.New("invalid ECDSAPrivateKey (zero or bigger than the group order)")
}
return &ECDSAPrivateKey{privateKey: *data, init: true}, nil
}
// DeserializeECDSAPrivateKeyFromSlice returns a ECDSAPrivateKey type from a serialized private key slice.
// will verify that it's 32 byte and it's a valid private key(Group Order > key > 0)
func DeserializeECDSAPrivateKeyFromSlice(data []byte) (key *ECDSAPrivateKey, err error) {
if len(data) != SerializedPrivateKeySize {
return nil, errors.Errorf("invalid ECDSA private key length got %d, expected %d", len(data),
SerializedPrivateKeySize)
}
serializedKey := &SerializedPrivateKey{}
copy(serializedKey[:], data)
return DeserializeECDSAPrivateKey(serializedKey)
}
// GenerateECDSAPrivateKey generates a random valid private key from `crypto/rand`
func GenerateECDSAPrivateKey() (key *ECDSAPrivateKey, err error) {
key = &ECDSAPrivateKey{init: true}
cPtr := (*C.uchar)(&key.privateKey[0])
for {
n, tmpErr := rand.Read(key.privateKey[:])
if tmpErr != nil {
return nil, tmpErr
}
if n != len(key.privateKey) {
panic("The standard library promises that this should never happen")
}
ret := C.secp256k1_ec_seckey_verify(C.secp256k1_context_no_precomp, cPtr)
if ret == 1 {
return key, nil
}
}
}
// Serialize a private key
func (key *ECDSAPrivateKey) Serialize() *SerializedPrivateKey {
ret := SerializedPrivateKey(key.privateKey)
return &ret
}
// Negate a private key in place.
func (key *ECDSAPrivateKey) Negate() error {
if !key.init {
return errNonInitializedKey
}
cPtr := (*C.uchar)(&key.privateKey[0])
ret := C.secp256k1_ec_privkey_negate(C.secp256k1_context_no_precomp, cPtr)
if ret != 1 {
panic("Failed Negating the private key. Should never happen")
}
return nil
}
// Add a tweak to the private key by doing `key + tweak % Group Order`. this adds it in place.
// This is meant for creating BIP-32(HD) wallets
func (key *ECDSAPrivateKey) Add(tweak [32]byte) error {
if !key.init {
return errNonInitializedKey
}
cPtrKey := (*C.uchar)(&key.privateKey[0])
cPtrTweak := (*C.uchar)(&tweak[0])
ret := C.secp256k1_ec_privkey_tweak_add(C.secp256k1_context_no_precomp, cPtrKey, cPtrTweak)
if ret != 1 {
return errors.New("failed Adding to private key. Tweak is bigger than the order or the complement of the private key")
}
return nil
}
// ToSchnorr converts an ECDSA private key to a schnorr keypair
// Note: You shouldn't sign using the same key in both ECDSA and Schnorr signatures.
// this function is for convenience when using BIP-32
func (key *ECDSAPrivateKey) ToSchnorr() (*SchnorrKeyPair, error) {
if !key.init {
return nil, errors.WithStack(errNonInitializedKey)
}
return DeserializeSchnorrPrivateKey((*SerializedPrivateKey)(&key.privateKey))
}