-
Notifications
You must be signed in to change notification settings - Fork 8
/
privatekey.go
132 lines (108 loc) · 3.17 KB
/
privatekey.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
package go_eccrypto
import (
"bytes"
"crypto/elliptic"
"crypto/rand"
"crypto/subtle"
"encoding/hex"
"fmt"
"github.com/fomichev/secp256k1"
"github.com/pkg/errors"
"math/big"
)
// PrivateKey is an instance of secp256k1 private key with nested public key
type PrivateKey struct {
*PublicKey
D *big.Int
}
// GenerateKey generates secp256k1 key pair
func GenerateKey() (*PrivateKey, error) {
curve := secp256k1.SECP256K1()
p, x, y, err := elliptic.GenerateKey(curve, rand.Reader)
if err != nil {
return nil, errors.Wrap(err, "cannot generate key pair")
}
return &PrivateKey{
PublicKey: &PublicKey{
Curve: curve,
X: x,
Y: y,
},
D: new(big.Int).SetBytes(p),
}, nil
}
// NewPrivateKeyFromHex decodes hex form of private key raw bytes, computes public key and returns PrivateKey instance
func NewPrivateKeyFromHex(s string) (*PrivateKey, error) {
b, err := hex.DecodeString(s)
if err != nil {
return nil, errors.Wrap(err, "cannot decode hex string")
}
return NewPrivateKeyFromBytes(b), nil
}
// NewPrivateKeyFromBytes decodes private key raw bytes, computes public key and returns PrivateKey instance
func NewPrivateKeyFromBytes(priv []byte) *PrivateKey {
curve := secp256k1.SECP256K1()
x, y := curve.ScalarBaseMult(priv)
return &PrivateKey{
PublicKey: &PublicKey{
Curve: curve,
X: x,
Y: y,
},
D: new(big.Int).SetBytes(priv),
}
}
// Bytes returns private key raw bytes
func (k *PrivateKey) Bytes() []byte {
return k.D.Bytes()
}
// Hex returns private key bytes in hex form
func (k *PrivateKey) Hex() string {
return hex.EncodeToString(k.Bytes())
}
// Encapsulate encapsulates key by using Key Encapsulation Mechanism and returns symmetric key;
// can be safely used as crypto key
func (k *PrivateKey) Encapsulate(pub *PublicKey) ([]byte, error) {
fmt.Println(k.Hex())
fmt.Println(pub.Hex(false))
if pub == nil {
return nil, errors.New("public key is empty")
}
var secret bytes.Buffer
secret.Write(k.PublicKey.Bytes(false))
sx, sy := pub.Curve.ScalarMult(pub.X, pub.Y, k.D.Bytes())
secret.Write([]byte{0x04})
// Sometimes shared secret coordinates are less than 32 bytes; Big Endian
l := len(pub.Curve.Params().P.Bytes())
secret.Write(zeroPad(sx.Bytes(), l))
secret.Write(zeroPad(sy.Bytes(), l))
return kdf(secret.Bytes())
}
// ECDH derives shared secret;
// Must not be used as crypto key, it increases chances to perform successful key restoration attack
func (k *PrivateKey) ECDH(pub *PublicKey) ([]byte, error) {
if pub == nil {
return nil, errors.New("public key is empty")
}
// Shared secret generation
sx, sy := pub.Curve.ScalarMult(pub.X, pub.Y, k.D.Bytes())
var ss []byte
if sy.Bit(0) != 0 { // If odd
ss = append(ss, 0x03)
} else { // If even
ss = append(ss, 0x02)
}
// Sometimes shared secret is less than 32 bytes; Big Endian
l := len(pub.Curve.Params().P.Bytes())
for i := 0; i < l-len(sx.Bytes()); i++ {
ss = append(ss, 0x00)
}
return append(ss, sx.Bytes()...), nil
}
// Equals compares two private keys with constant time (to resist timing attacks)
func (k *PrivateKey) Equals(priv *PrivateKey) bool {
if subtle.ConstantTimeCompare(k.D.Bytes(), priv.D.Bytes()) == 1 {
return true
}
return false
}