...
1 package x25519
2
3 import (
4 "bytes"
5 "crypto"
6 cryptorand "crypto/rand"
7 "io"
8
9 "golang.org/x/crypto/curve25519"
10
11 "github.com/pkg/errors"
12 )
13
14
15
16
17
18
19
20
21
22
23
24
25 const (
26
27 PublicKeySize = 32
28
29 PrivateKeySize = 64
30
31 SeedSize = 32
32 )
33
34
35 type PublicKey []byte
36
37
38
39
40
41 func (pub PublicKey) Equal(x crypto.PublicKey) bool {
42 xx, ok := x.(PublicKey)
43 if !ok {
44 return false
45 }
46 return bytes.Equal(pub, xx)
47 }
48
49
50 type PrivateKey []byte
51
52
53 func (priv PrivateKey) Public() crypto.PublicKey {
54 publicKey := make([]byte, PublicKeySize)
55 copy(publicKey, priv[SeedSize:])
56 return PublicKey(publicKey)
57 }
58
59
60 func (priv PrivateKey) Equal(x crypto.PrivateKey) bool {
61 xx, ok := x.(PrivateKey)
62 if !ok {
63 return false
64 }
65 return bytes.Equal(priv, xx)
66 }
67
68
69
70
71 func (priv PrivateKey) Seed() []byte {
72 seed := make([]byte, SeedSize)
73 copy(seed, priv[:SeedSize])
74 return seed
75 }
76
77
78
79
80
81 func NewKeyFromSeed(seed []byte) (PrivateKey, error) {
82 privateKey := make([]byte, PrivateKeySize)
83 if len(seed) != SeedSize {
84 return nil, errors.Errorf("unexpected seed size: %d", len(seed))
85 }
86 copy(privateKey, seed)
87 public, err := curve25519.X25519(seed, curve25519.Basepoint)
88 if err != nil {
89 return nil, errors.Wrap(err, "failed to compute public key")
90 }
91 copy(privateKey[SeedSize:], public)
92
93 return privateKey, nil
94 }
95
96
97
98 func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) {
99 if rand == nil {
100 rand = cryptorand.Reader
101 }
102
103 seed := make([]byte, SeedSize)
104 if _, err := io.ReadFull(rand, seed); err != nil {
105 return nil, nil, err
106 }
107
108 privateKey, err := NewKeyFromSeed(seed)
109 if err != nil {
110 return nil, nil, err
111 }
112 publicKey := make([]byte, PublicKeySize)
113 copy(publicKey, privateKey[SeedSize:])
114
115 return publicKey, privateKey, nil
116 }
117
View as plain text