/
keypairs.go
110 lines (92 loc) · 2.52 KB
/
keypairs.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
package keypairs
import (
"crypto/rand"
"fmt"
addresscodec "github.com/xyield/xrpl-go/address-codec"
)
var r randomizer
const (
VERIFICATIONMESSAGE = "This test message should verify."
)
func init() {
r.Reader = rand.Reader
}
type CryptoImplementation interface {
deriveKeypair(decodedSeed []byte, validator bool) (string, string, error)
sign(msg, privKey string) (string, error)
validate(msg, pubkey, sig string) bool
}
func GenerateSeed(entropy string, alg addresscodec.CryptoAlgorithm) (string, error) {
var pe []byte
if entropy == "" {
b, err := r.generateBytes(addresscodec.FamilySeedLength)
pe = b
if err != nil {
return "", err
}
} else {
pe = []byte(entropy)[:addresscodec.FamilySeedLength]
}
return addresscodec.EncodeSeed(pe, alg)
}
// Derives a keypair from a given seed. Returns a tuple of private key and public key
func DeriveKeypair(seed string, validator bool) (private, public string, err error) {
ds, alg, err := addresscodec.DecodeSeed(seed)
if err != nil {
return
}
ci := getCryptoImplementation(alg)
if ci == nil {
return "", "", &CryptoImplementationError{}
}
private, public, err = ci.deriveKeypair(ds, validator)
if err != nil {
return
}
signature, err := ci.sign(VERIFICATIONMESSAGE, private)
if !ci.validate(VERIFICATIONMESSAGE, public, signature) {
return "", "", &InvalidSignatureError{}
}
return
}
func DeriveClassicAddress(pubkey string) (string, error) {
return addresscodec.EncodeClassicAddressFromPublicKeyHex(pubkey)
}
func Sign(msg, privKey string) (string, error) {
alg := getCryptoImplementationFromKey(privKey)
if alg == nil {
return "", &CryptoImplementationError{}
}
return alg.sign(msg, privKey)
}
func Validate(msg, pubKey, sig string) (bool, error) {
alg := getCryptoImplementationFromKey(pubKey)
if alg == nil {
return false, &CryptoImplementationError{}
}
return alg.validate(msg, pubKey, sig), nil
}
func getCryptoImplementation(alg addresscodec.CryptoAlgorithm) CryptoImplementation {
switch alg {
case addresscodec.ED25519:
return &ed25519Alg{}
default:
return nil
}
}
func getCryptoImplementationFromKey(k string) CryptoImplementation {
switch deformatKey(k)[0] {
case addresscodec.ED25519:
return &ed25519Alg{}
default:
return nil
}
}
type CryptoImplementationError struct{}
func (e *CryptoImplementationError) Error() string {
return fmt.Sprintln("not a valid crypto implementation")
}
type InvalidSignatureError struct{}
func (e *InvalidSignatureError) Error() string {
return "derived keypair did not generate verifiable signature"
}