This repository has been archived by the owner on May 13, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 346
/
private_key.go
144 lines (132 loc) · 4.76 KB
/
private_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
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
package crypto
import (
"bytes"
"crypto/ecdsa"
cryptoRand "crypto/rand"
"crypto/sha256"
"fmt"
"io"
"github.com/btcsuite/btcd/btcec"
"golang.org/x/crypto/ed25519"
)
// Currently this is a stub that reads the raw bytes returned by key_client and returns
// an ed25519 public key.
func PublicKeyFromBytes(bs []byte, curveType CurveType) (*PublicKey, error) {
switch curveType {
case CurveTypeEd25519:
if len(bs) != ed25519.PublicKeySize {
return nil, fmt.Errorf("bytes passed have length %v but ed25519 public keys have %v bytes",
len(bs), ed25519.PublicKeySize)
}
case CurveTypeSecp256k1:
if len(bs) != btcec.PubKeyBytesLenUncompressed {
return nil, fmt.Errorf("bytes passed have length %v but secp256k1 public keys have %v bytes",
len(bs), btcec.PubKeyBytesLenUncompressed)
}
case CurveTypeUnset:
if len(bs) > 0 {
return nil, fmt.Errorf("attempting to create an 'unset' PublicKey but passed non-empty key bytes: %X", bs)
}
return nil, nil
default:
return nil, ErrInvalidCurve(curveType)
}
return &PublicKey{PublicKey: bs, CurveType: curveType}, nil
}
func (p PrivateKey) RawBytes() []byte {
return p.PrivateKey
}
func (p PrivateKey) Sign(msg []byte) (*Signature, error) {
switch p.CurveType {
case CurveTypeEd25519:
privKey := ed25519.PrivateKey(p.PrivateKey)
return &Signature{CurveType: CurveTypeEd25519, Signature: ed25519.Sign(privKey, msg)}, nil
case CurveTypeSecp256k1:
privKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), p.PrivateKey)
sig, err := btcec.SignCompact(btcec.S256(), privKey, Keccak256(msg), false)
if err != nil {
return nil, err
}
return &Signature{CurveType: CurveTypeSecp256k1, Signature: sig}, nil
default:
return nil, ErrInvalidCurve(p.CurveType)
}
}
func (p PrivateKey) GetPublicKey() *PublicKey {
return &PublicKey{CurveType: p.CurveType, PublicKey: p.PublicKey}
}
func (p PrivateKey) String() string {
return fmt.Sprintf("PrivateKey<PublicKey:%X>", p.PublicKey)
}
func GeneratePrivateKey(random io.Reader, curveType CurveType) (PrivateKey, error) {
if random == nil {
random = cryptoRand.Reader
}
switch curveType {
case CurveTypeEd25519:
_, privateKey, err := ed25519.GenerateKey(random)
if err != nil {
return PrivateKey{}, err
}
return PrivateKeyFromRawBytes(privateKey, CurveTypeEd25519)
case CurveTypeSecp256k1:
privateKey, err := ecdsa.GenerateKey(btcec.S256(), random)
if err != nil {
return PrivateKey{}, err
}
return PrivateKeyFromRawBytes(((*btcec.PrivateKey)(privateKey)).Serialize(), CurveTypeSecp256k1)
default:
return PrivateKey{}, ErrInvalidCurve(curveType)
}
}
func PrivateKeyFromRawBytes(privateKeyBytes []byte, curveType CurveType) (PrivateKey, error) {
const ed25519PublicKeyOffset = ed25519.PrivateKeySize - ed25519.PublicKeySize
switch curveType {
case CurveTypeEd25519:
if len(privateKeyBytes) != ed25519.PrivateKeySize {
return PrivateKey{}, fmt.Errorf("bytes passed have length %v but ed25519 private keys have %v bytes",
len(privateKeyBytes), ed25519.PrivateKeySize)
}
return PrivateKey{PrivateKey: privateKeyBytes, PublicKey: privateKeyBytes[ed25519PublicKeyOffset:], CurveType: CurveTypeEd25519}, nil
case CurveTypeSecp256k1:
if len(privateKeyBytes) != btcec.PrivKeyBytesLen {
return PrivateKey{}, fmt.Errorf("bytes passed have length %v but secp256k1 private keys have %v bytes",
len(privateKeyBytes), btcec.PrivKeyBytesLen)
}
_, publicKey := btcec.PrivKeyFromBytes(btcec.S256(), privateKeyBytes)
return PrivateKey{PrivateKey: privateKeyBytes, PublicKey: publicKey.SerializeUncompressed(), CurveType: CurveTypeSecp256k1}, nil
default:
return PrivateKey{}, ErrInvalidCurve(curveType)
}
}
func PrivateKeyFromSecret(secret string, curveType CurveType) PrivateKey {
hasher := sha256.New()
hasher.Write(([]byte)(secret))
// No error from a buffer
sum := hasher.Sum(nil)
const exp = 4
for i := 0; i < exp; i++ {
sum = append(sum, sum...)
}
privateKey, err := GeneratePrivateKey(bytes.NewBuffer(sum), curveType)
if err != nil {
panic(fmt.Errorf("PrivateKeyFromScret: unexpected error: %w", err))
}
return privateKey
}
// Ensures the last 32 bytes of the ed25519 private key is the public key derived from the first 32 private bytes
func EnsureEd25519PrivateKeyCorrect(candidatePrivateKey ed25519.PrivateKey) error {
if len(candidatePrivateKey) != ed25519.PrivateKeySize {
return fmt.Errorf("ed25519 key has size %v but %v bytes passed as key", ed25519.PrivateKeySize,
len(candidatePrivateKey))
}
_, derivedPrivateKey, err := ed25519.GenerateKey(bytes.NewBuffer(candidatePrivateKey))
if err != nil {
return err
}
if !bytes.Equal(derivedPrivateKey, candidatePrivateKey) {
return fmt.Errorf("ed25519 key generated from prefix of %X should equal %X, but is %X",
candidatePrivateKey, candidatePrivateKey, derivedPrivateKey)
}
return nil
}