forked from 33cn/plugin
/
util.go
229 lines (211 loc) · 7.05 KB
/
util.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
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package wallet
import (
"encoding/hex"
"unsafe"
"github.com/33cn/chain33/common"
"github.com/33cn/chain33/types"
privacy "github.com/33cn/plugin/plugin/dapp/privacy/crypto"
privacytypes "github.com/33cn/plugin/plugin/dapp/privacy/types"
)
func checkAmountValid(amount int64) bool {
if amount <= 0 {
return false
}
// 隐私交易中,交易金额必须是types.Coin的整数倍
// 后续调整了隐私交易中手续费计算以后需要修改
if (int64(float64(amount)/float64(types.Coin)) * types.Coin) != amount {
return false
}
return true
}
func makeViewSpendPubKeyPairToString(viewPubKey, spendPubKey []byte) string {
pair := viewPubKey
pair = append(pair, spendPubKey...)
return hex.EncodeToString(pair)
}
//将amount切分为1,2,5的组合,这样在进行amount混淆的时候就能够方便获取相同额度的utxo
func decomAmount2Nature(amount int64, order int64) []int64 {
res := make([]int64, 0)
if order == 0 {
return res
}
mul := amount / order
switch mul {
case 3:
res = append(res, order)
res = append(res, 2*order)
case 4:
res = append(res, 2*order)
res = append(res, 2*order)
case 6:
res = append(res, 5*order)
res = append(res, order)
case 7:
res = append(res, 5*order)
res = append(res, 2*order)
case 8:
res = append(res, 5*order)
res = append(res, 2*order)
res = append(res, 1*order)
case 9:
res = append(res, 5*order)
res = append(res, 2*order)
res = append(res, 2*order)
default:
res = append(res, mul*order)
return res
}
return res
}
// 62387455827 -> 455827 + 7000000 + 80000000 + 300000000 + 2000000000 + 60000000000, where 455827 <= dustThreshold
//res:[455827, 7000000, 80000000, 300000000, 2000000000, 60000000000]
func decomposeAmount2digits(amount, dustThreshold int64) []int64 {
res := make([]int64, 0)
if 0 >= amount {
return res
}
isDustHandled := false
var dust int64
var order int64 = 1
var chunk int64
for 0 != amount {
chunk = (amount % 10) * order
amount /= 10
order *= 10
if dust+chunk < dustThreshold {
dust += chunk //累加小数,直到超过dust_threshold为止
} else {
if !isDustHandled && 0 != dust {
//1st 正常情况下,先把dust保存下来
res = append(res, dust)
isDustHandled = true
}
if 0 != chunk {
//2nd 然后依次将大的整数额度进行保存
goodAmount := decomAmount2Nature(chunk, order/10)
res = append(res, goodAmount...)
}
}
}
//如果需要被拆分的额度 < dustThreshold,则直接将其进行保存
if !isDustHandled && 0 != dust {
res = append(res, dust)
}
return res
}
func parseViewSpendPubKeyPair(in string) (viewPubKey, spendPubKey []byte, err error) {
src, err := common.FromHex(in)
if err != nil {
return nil, nil, err
}
if 64 != len(src) {
bizlog.Error("parseViewSpendPubKeyPair", "pair with len", len(src))
return nil, nil, types.ErrPubKeyLen
}
viewPubKey = src[:32]
spendPubKey = src[32:]
return
}
// genCustomOuts 构建一个交易的输出
// 构建方式是,P=Hs(rA)G+B
//func genCustomOuts(viewpubTo, spendpubto *[32]byte, transAmount int64, count int32) (*privacytypes.PrivacyOutput, error) {
// decomDigit := make([]int64, count)
// for i := range decomDigit {
// decomDigit[i] = transAmount
// }
//
// pk := &privacy.PubKeyPrivacy{}
// sk := &privacy.PrivKeyPrivacy{}
// privacy.GenerateKeyPair(sk, pk)
// RtxPublicKey := pk.Bytes()
//
// sktx := (*[32]byte)(unsafe.Pointer(&sk[0]))
// var privacyOutput privacytypes.PrivacyOutput
// privacyOutput.RpubKeytx = RtxPublicKey
// privacyOutput.Keyoutput = make([]*privacytypes.KeyOutput, len(decomDigit))
//
// //添加本次转账的目的接收信息(UTXO),包括一次性公钥和额度
// for index, digit := range decomDigit {
// pubkeyOnetime, err := privacy.GenerateOneTimeAddr(viewpubTo, spendpubto, sktx, int64(index))
// if err != nil {
// bizlog.Error("genCustomOuts", "Fail to GenerateOneTimeAddr due to cause", err)
// return nil, err
// }
// keyOutput := &privacytypes.KeyOutput{
// Amount: digit,
// Onetimepubkey: pubkeyOnetime[:],
// }
// privacyOutput.Keyoutput[index] = keyOutput
// }
//
// return &privacyOutput, nil
//}
//最后构造完成的utxo依次是2种类型,不构造交易费utxo,使其直接燃烧消失
//1.进行实际转账utxo
//2.进行找零转账utxo
func generateOuts(viewpubTo, spendpubto, viewpubChangeto, spendpubChangeto *[32]byte, transAmount, selectedAmount, fee int64) (*privacytypes.PrivacyOutput, error) {
decomDigit := decomposeAmount2digits(transAmount, types.BTYDustThreshold)
//计算找零
changeAmount := selectedAmount - transAmount - fee
var decomChange []int64
if 0 < changeAmount {
decomChange = decomposeAmount2digits(changeAmount, types.BTYDustThreshold)
}
bizlog.Info("generateOuts", "decompose digit for amount", selectedAmount-fee, "decomDigit", decomDigit)
pk := &privacy.PubKeyPrivacy{}
sk := &privacy.PrivKeyPrivacy{}
privacy.GenerateKeyPair(sk, pk)
RtxPublicKey := pk.Bytes()
sktx := (*[32]byte)(unsafe.Pointer(&sk[0]))
var privacyOutput privacytypes.PrivacyOutput
privacyOutput.RpubKeytx = RtxPublicKey
privacyOutput.Keyoutput = make([]*privacytypes.KeyOutput, len(decomDigit)+len(decomChange))
//添加本次转账的目的接收信息(UTXO),包括一次性公钥和额度
for index, digit := range decomDigit {
pubkeyOnetime, err := privacy.GenerateOneTimeAddr(viewpubTo, spendpubto, sktx, int64(index))
if err != nil {
bizlog.Error("generateOuts", "Fail to GenerateOneTimeAddr due to cause", err)
return nil, err
}
keyOutput := &privacytypes.KeyOutput{
Amount: digit,
Onetimepubkey: pubkeyOnetime[:],
}
privacyOutput.Keyoutput[index] = keyOutput
}
//添加本次转账选择的UTXO后的找零后的UTXO
for index, digit := range decomChange {
pubkeyOnetime, err := privacy.GenerateOneTimeAddr(viewpubChangeto, spendpubChangeto, sktx, int64(index+len(decomDigit)))
if err != nil {
bizlog.Error("generateOuts", "Fail to GenerateOneTimeAddr for change due to cause", err)
return nil, err
}
keyOutput := &privacytypes.KeyOutput{
Amount: digit,
Onetimepubkey: pubkeyOnetime[:],
}
privacyOutput.Keyoutput[index+len(decomDigit)] = keyOutput
}
//交易费不产生额外的utxo,方便执行器执行的时候直接燃烧殆尽
if 0 != fee {
//viewPub, _ := common.Hex2Bytes(types.ViewPubFee)
//spendPub, _ := common.Hex2Bytes(types.SpendPubFee)
//viewPublic := (*[32]byte)(unsafe.Pointer(&viewPub[0]))
//spendPublic := (*[32]byte)(unsafe.Pointer(&spendPub[0]))
//
//pubkeyOnetime, err := privacy.GenerateOneTimeAddr(viewPublic, spendPublic, sktx, int64(len(privacyOutput.Keyoutput)))
//if err != nil {
// bizlog.Error("transPub2PriV2", "Fail to GenerateOneTimeAddr for fee due to cause", err)
// return nil, nil, err
//}
//keyOutput := &types.KeyOutput{
// Amount: fee,
// Ometimepubkey: pubkeyOnetime[:],
//}
//privacyOutput.Keyoutput = append(privacyOutput.Keyoutput, keyOutput)
}
return &privacyOutput, nil
}