/
key.go
233 lines (199 loc) · 7.73 KB
/
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
package key
import (
"encoding/hex"
"errors"
"github.com/incognitochain/go-incognito-sdk-v2/crypto"
)
// PrivateKey is a 32-byte long slice which is used to manage an account.
// A PrivateKey can be used to spend UTXOs, sign transaction, etc.
type PrivateKey []byte
// PublicKey is the public key corresponding to a PrivateKey, generated by the following formula:
// PublicKey = PrivateKey * G[0], where G[0] is the base point for key-related operations. See crypto.PedCom.
type PublicKey []byte
// ReceivingKey (a.k.a ReadonlyKey) is used to decrypt UTXOs.
type ReceivingKey []byte
// TransmissionKey is the public key for a ReceivingKey. It is used to encrypt the amount of UTXOs in transactions.
type TransmissionKey []byte
// PrivateOTAKey is used to check if an UTXO belong to a user (in Privacy V2).
type PrivateOTAKey []byte
// PublicOTAKey is the public key for a PrivateOTAKey. It is used to "encrypt" the owner of UTXOs as well as blind
// the real asset of UTXOs.
type PublicOTAKey []byte
// ViewingKey is a wrapped version of a ReceivingKey.
type ViewingKey struct {
Pk PublicKey // 33 bytes, use to receive coin
Rk ReceivingKey // 32 bytes, use to decrypt pointByte
}
// GetPublicSpend returns the PublicKey of a ViewingKey.
func (viewKey ViewingKey) GetPublicSpend() *crypto.Point {
pubSpend, _ := new(crypto.Point).FromBytesS(viewKey.Pk)
return pubSpend
}
// GetPrivateView returns the ReceivingKey of a ViewingKey.
func (viewKey ViewingKey) GetPrivateView() *crypto.Scalar {
return new(crypto.Scalar).FromBytesS(viewKey.Rk)
}
// OTAKey is a wrapped version of a PrivateOTAKey.
type OTAKey struct {
pk PublicKey //32 bytes: used to
otaSecret PrivateOTAKey
}
// GetPublicSpend returns the PublicKey of an OTAKey.
func (otaKey OTAKey) GetPublicSpend() *crypto.Point {
pubSpend, err := new(crypto.Point).FromBytesS(otaKey.pk)
if err != nil {
return nil
}
if pubSpend.PointValid() {
return pubSpend
}
return nil
}
// GetOTASecretKey returns the PrivateOTAKey of an OTAKey.
func (otaKey OTAKey) GetOTASecretKey() *crypto.Scalar {
otaSecret := new(crypto.Scalar).FromBytesS(otaKey.otaSecret)
if otaSecret.ScalarValid() {
return otaSecret
}
return nil
}
// SetOTASecretKey sets v as the PrivateOTAKey of an OTAKey.
func (otaKey *OTAKey) SetOTASecretKey(v []byte) {
if len(otaKey.otaSecret) == 0 {
otaKey.otaSecret = append([]byte{}, v...)
}
}
// SetPublicSpend sets v as the PublicKey of an OTAKey.
func (otaKey *OTAKey) SetPublicSpend(v []byte) {
if len(otaKey.pk) == 0 {
otaKey.pk = append([]byte{}, v...)
}
}
// PaymentAddress represents the address of a user. It consists of
// - PublicKey: the ID of a user on the blockchain. It is also used to receive UTXOs in a non-private manner (V1).
// In Privacy V1, the public key of an UTXO is also the public key of its owner.
// - TransmissionKey: to encrypt UTXOs.
// - PublicOTAKey: to hide the owner of UTXOs. Only the sender and receiver will be able to know the ownership of
// the transferred UTXO.
type PaymentAddress struct {
Pk PublicKey // 32 bytes, use to receive coin (CoinV1)
Tk TransmissionKey // 32 bytes, use to encrypt pointByte
OTAPublic PublicOTAKey //32 bytes, used to receive coin (CoinV2)
}
// Bytes converts payment address to bytes array
func (addr *PaymentAddress) Bytes() []byte {
res := append(addr.Pk[:], addr.Tk[:]...)
if addr.OTAPublic != nil {
return append(res, addr.OTAPublic[:]...)
}
return res
}
// SetBytes reverts bytes array to payment address
func (addr *PaymentAddress) SetBytes(bytes []byte) error {
if len(bytes) != 2*crypto.Ed25519KeySize && len(bytes) != 3*crypto.Ed25519KeySize {
return errors.New("length of payment address not valid")
}
// the first 33 bytes are public key
addr.Pk = bytes[:crypto.Ed25519KeySize]
// the last 33 bytes are transmission key
addr.Tk = bytes[crypto.Ed25519KeySize : 2*crypto.Ed25519KeySize]
if len(bytes) == 3*crypto.Ed25519KeySize {
addr.OTAPublic = bytes[2*crypto.Ed25519KeySize:]
} else {
addr.OTAPublic = nil
}
return nil
}
// GetPublicSpend returns the PublicKey of a PaymentAddress.
func (addr PaymentAddress) GetPublicSpend() *crypto.Point {
pubSpend, _ := new(crypto.Point).FromBytesS(addr.Pk)
return pubSpend
}
// GetPublicView returns the TransmissionKey of a PaymentAddress.
func (addr PaymentAddress) GetPublicView() *crypto.Point {
pubView, _ := new(crypto.Point).FromBytesS(addr.Tk)
return pubView
}
// String returns a string representation of a PaymentAddress.
func (addr PaymentAddress) String() string {
byteArrays := addr.Bytes()
return hex.EncodeToString(byteArrays[:])
}
// GetOTAPublicKey returns the PublicOTAKey of a PaymentAddress.
func (addr PaymentAddress) GetOTAPublicKey() *crypto.Point {
if len(addr.OTAPublic) == 0 {
return nil
}
encryptionKey, _ := new(crypto.Point).FromBytesS(addr.OTAPublic)
return encryptionKey
}
// PaymentInfo represents the information of a receiver when creating a transaction.
type PaymentInfo struct {
PaymentAddress PaymentAddress
Amount uint64
Message []byte // at most 512 bytes
}
// InitPaymentInfo creates a new PaymentInfo given a PaymentAddress, an amount and a message.
func InitPaymentInfo(addr PaymentAddress, amount uint64, message []byte) *PaymentInfo {
return &PaymentInfo{
PaymentAddress: addr,
Amount: amount,
Message: message,
}
}
// GeneratePrivateKey generates a random 32-byte PrivateKey.
func GeneratePrivateKey(seed []byte) PrivateKey {
bip32PrivateKey := crypto.HashToScalar(seed)
privateKey := bip32PrivateKey.ToBytesS()
return privateKey
}
// GeneratePublicKey returns the PublicKey given a PrivateKey.
func GeneratePublicKey(privateKey []byte) PublicKey {
privateScalar := new(crypto.Scalar).FromBytesS(privateKey)
publicKey := new(crypto.Point).ScalarMultBase(privateScalar)
return publicKey.ToBytesS()
}
// GenerateReceivingKey returns the ReceivingKey given a PrivateKey.
func GenerateReceivingKey(privateKey []byte) ReceivingKey {
receivingKey := crypto.HashToScalar(privateKey[:])
return receivingKey.ToBytesS()
}
// GenerateTransmissionKey returns the TransmissionKey given a PrivateKey.
func GenerateTransmissionKey(receivingKey []byte) TransmissionKey {
receiveScalar := new(crypto.Scalar).FromBytesS(receivingKey)
transmissionKey := new(crypto.Point).ScalarMultBase(receiveScalar)
return transmissionKey.ToBytesS()
}
// GenerateViewingKey returns the ViewingKey given a PrivateKey.
func GenerateViewingKey(privateKey []byte) ViewingKey {
var viewingKey ViewingKey
viewingKey.Pk = GeneratePublicKey(privateKey)
viewingKey.Rk = GenerateReceivingKey(privateKey)
return viewingKey
}
// GeneratePrivateOTAKey returns the PrivateOTAKey given a PrivateKey.
func GeneratePrivateOTAKey(privateKey []byte) PrivateOTAKey {
privateOTAKey := append(privateKey, []byte(crypto.CStringOTA)...)
privateOTAKey = crypto.HashToScalar(privateOTAKey).ToBytesS()
return privateOTAKey
}
// GeneratePublicOTAKey returns the PublicOTAKey given a PrivateOTAKey.
func GeneratePublicOTAKey(privateOTAKey PrivateOTAKey) PublicOTAKey {
privateOTAScalar := new(crypto.Scalar).FromBytesS(privateOTAKey)
return new(crypto.Point).ScalarMultBase(privateOTAScalar).ToBytesS()
}
// GenerateOTAKey returns the OTAKey given a PrivateKey.
func GenerateOTAKey(privateKey []byte) OTAKey {
var otaKey OTAKey
otaKey.pk = GeneratePublicKey(privateKey)
otaKey.otaSecret = GeneratePrivateOTAKey(privateKey)
return otaKey
}
// GeneratePaymentAddress returns the PaymentAddress given a PrivateKey.
func GeneratePaymentAddress(privateKey []byte) PaymentAddress {
var paymentAddress PaymentAddress
paymentAddress.Pk = GeneratePublicKey(privateKey)
paymentAddress.Tk = GenerateTransmissionKey(GenerateReceivingKey(privateKey))
paymentAddress.OTAPublic = GeneratePublicOTAKey(GeneratePrivateOTAKey(privateKey))
return paymentAddress
}