/
secp256k1.go
86 lines (68 loc) · 2.22 KB
/
secp256k1.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
package crypto
import (
"encoding/binary"
"fmt"
"math/big"
secp "github.com/decred/dcrd/dcrec/secp256k1/v4"
)
const (
SECP256K1_PRIVATE_KEY_PREFIX = 0x00
)
var (
SECP256K1_SEED_PREFIX = []byte{0x21}
)
var (
order = secp.S256().N
zero = big.NewInt(0)
one = big.NewInt(1)
)
func GenerateSeedSecp256k1(entropy []byte) (string, error) {
if entropy == nil {
var err error
entropy, err = GenerateEntropy()
if err != nil {
return "", err
}
}
encoded := append(SECP256K1_SEED_PREFIX, entropy...)
return Base58Encode(encoded, ALPHABET), nil
}
func DeriveKeypairSecp256k1(entropy []byte, sequence *uint32) ([]byte, []byte, error) {
if entropy == nil {
return nil, nil, fmt.Errorf("entropy is nil")
}
if len(entropy) != ENTROPY_LENGTH {
return nil, nil, fmt.Errorf("entropy length is not correct")
}
// This private generator represents the `root` private key, and is what's
// used by validators for signing when a keypair is generated from a seed.
privateGen := deriveScalar(entropy)
if sequence == nil {
privateKey := append([]byte{SECP256K1_PRIVATE_KEY_PREFIX}, privateGen.ToECDSA().D.Bytes()...)
publicKey := privateGen.PubKey().SerializeCompressed()
return publicKey, privateKey, nil
}
// A seed can generate many keypairs as a function of the seed and a uint32.
// Almost everyone just uses the first account, `0`.
secpKey := generateKeyForSequence(privateGen.PubKey().SerializeCompressed(), *sequence)
secpKey.Key = *secpKey.Key.Add(&privateGen.Key)
privateKey := append([]byte{SECP256K1_PRIVATE_KEY_PREFIX}, secpKey.ToECDSA().D.Bytes()...)
publicKey := secpKey.PubKey().SerializeCompressed()
return publicKey, privateKey, nil
}
func deriveScalar(entropy []byte) *secp.PrivateKey {
inc := big.NewInt(0).SetBytes(entropy)
inc.Lsh(inc, 32)
for key := big.NewInt(0); ; inc.Add(inc, one) {
key.SetBytes(Sha512Half(inc.Bytes()))
if key.Cmp(zero) > 0 && key.Cmp(order) < 0 {
return secp.PrivKeyFromBytes(key.Bytes())
}
}
}
func generateKeyForSequence(pubKey []byte, sequence uint32) *secp.PrivateKey {
entropy := make([]byte, secp.PubKeyBytesLenCompressed+4)
copy(entropy, pubKey)
binary.BigEndian.PutUint32(entropy[secp.PubKeyBytesLenCompressed:], sequence)
return deriveScalar(entropy)
}