hermez-node/common/account_test.go
common/account_test.goRaw
1package common
2
3import (
4 "encoding/hex"
5 "fmt"
6 "math"
7 "math/big"
8 "strings"
9 "testing"
10
11 ethCommon "github.com/ethereum/go-ethereum/common"
12 ethCrypto "github.com/ethereum/go-ethereum/crypto"
13 "github.com/hermeznetwork/tracerr"
14 "github.com/iden3/go-iden3-crypto/babyjub"
15 cryptoConstants "github.com/iden3/go-iden3-crypto/constants"
16 "github.com/iden3/go-iden3-crypto/poseidon"
17 cryptoUtils "github.com/iden3/go-iden3-crypto/utils"
18 "github.com/stretchr/testify/assert"
19 "github.com/stretchr/testify/require"
20)
21
22func TestIdxParser(t *testing.T) {
23 i := Idx(1)
24 iBytes, err := i.Bytes()
25 assert.NoError(t, err)
26 assert.Equal(t, 6, len(iBytes))
27 assert.Equal(t, "000000000001", hex.EncodeToString(iBytes[:]))
28 i2, err := IdxFromBytes(iBytes[:])
29 assert.NoError(t, err)
30 assert.Equal(t, i, i2)
31
32 i = Idx(100)
33 assert.Equal(t, big.NewInt(100), i.BigInt())
34
35 // value before overflow
36 i = Idx(281474976710655)
37 iBytes, err = i.Bytes()
38 assert.NoError(t, err)
39 assert.Equal(t, 6, len(iBytes))
40 assert.Equal(t, "ffffffffffff", hex.EncodeToString(iBytes[:]))
41 i2, err = IdxFromBytes(iBytes[:])
42 assert.NoError(t, err)
43 assert.Equal(t, i, i2)
44
45 // expect value overflow
46 i = Idx(281474976710656)
47 iBytes, err = i.Bytes()
48 assert.NotNil(t, err)
49 assert.Equal(t, ErrIdxOverflow, tracerr.Unwrap(err))
50}
51
52func TestNonceParser(t *testing.T) {
53 n := Nonce(1)
54 nBytes, err := n.Bytes()
55 assert.NoError(t, err)
56 assert.Equal(t, 5, len(nBytes))
57 assert.Equal(t, "0000000001", hex.EncodeToString(nBytes[:]))
58 n2 := NonceFromBytes(nBytes)
59 assert.Equal(t, n, n2)
60
61 // value before overflow
62 n = Nonce(1099511627775)
63 nBytes, err = n.Bytes()
64 assert.NoError(t, err)
65 assert.Equal(t, 5, len(nBytes))
66 assert.Equal(t, "ffffffffff", hex.EncodeToString(nBytes[:]))
67 n2 = NonceFromBytes(nBytes)
68 assert.Equal(t, n, n2)
69
70 // expect value overflow
71 n = Nonce(1099511627776)
72 nBytes, err = n.Bytes()
73 assert.NotNil(t, err)
74 assert.Equal(t, ErrNonceOverflow, tracerr.Unwrap(err))
75}
76
77func TestAccount(t *testing.T) {
78 var sk babyjub.PrivateKey
79 _, err := hex.Decode(sk[:],
80 []byte("0001020304050607080900010203040506070809000102030405060708090001"))
81 assert.NoError(t, err)
82 pk := sk.Public()
83
84 account := &Account{
85 TokenID: TokenID(1),
86 Nonce: Nonce(1234),
87 Balance: big.NewInt(1000),
88 BJJ: pk.Compress(),
89 EthAddr: ethCommon.HexToAddress("0xc58d29fA6e86E4FAe04DDcEd660d45BCf3Cb2370"),
90 }
91 b, err := account.Bytes()
92 assert.NoError(t, err)
93 assert.Equal(t, byte(1), b[22])
94 a1, err := AccountFromBytes(b)
95 assert.NoError(t, err)
96 assert.Equal(t, account, a1)
97
98 e, err := account.BigInts()
99 assert.NoError(t, err)
100 assert.True(t, cryptoUtils.CheckBigIntInField(e[0]))
101 assert.True(t, cryptoUtils.CheckBigIntInField(e[1]))
102 assert.True(t, cryptoUtils.CheckBigIntInField(e[2]))
103 assert.True(t, cryptoUtils.CheckBigIntInField(e[3]))
104
105 assert.Equal(t, "1000", e[1].String())
106 assert.Equal(t, pk.Y.String(), e[2].String())
107 assert.Equal(t, new(big.Int).SetBytes(account.EthAddr.Bytes()).String(), e[3].String())
108
109 a2, err := AccountFromBigInts(e)
110 assert.NoError(t, err)
111 assert.Equal(t, account, a2)
112 assert.Equal(t, a1, a2)
113}
114
115func TestAccountLoop(t *testing.T) {
116 // check that for different deterministic BabyJubJub keys & random Address there is no problem
117 for i := 0; i < 256; i++ {
118 var sk babyjub.PrivateKey
119 _, err := hex.Decode(sk[:],
120 []byte("0001020304050607080900010203040506070809000102030405060708090001"))
121 assert.NoError(t, err)
122 pk := sk.Public()
123
124 key, err := ethCrypto.GenerateKey()
125 assert.NoError(t, err)
126 address := ethCrypto.PubkeyToAddress(key.PublicKey)
127
128 account := &Account{
129 TokenID: TokenID(i),
130 Nonce: Nonce(i),
131 Balance: big.NewInt(1000),
132 BJJ: pk.Compress(),
133 EthAddr: address,
134 }
135 b, err := account.Bytes()
136 assert.NoError(t, err)
137 a1, err := AccountFromBytes(b)
138 assert.NoError(t, err)
139 assert.Equal(t, account, a1)
140
141 e, err := account.BigInts()
142 assert.NoError(t, err)
143 assert.True(t, cryptoUtils.CheckBigIntInField(e[0]))
144 assert.True(t, cryptoUtils.CheckBigIntInField(e[1]))
145 assert.True(t, cryptoUtils.CheckBigIntInField(e[2]))
146 assert.True(t, cryptoUtils.CheckBigIntInField(e[3]))
147
148 a2, err := AccountFromBigInts(e)
149 assert.NoError(t, err)
150 assert.Equal(t, account, a2)
151 }
152}
153
154func TestAccountLoopRandom(t *testing.T) {
155 // check that for different random Address & BabyJubJub keys there is
156 // no problem
157 for i := 0; i < 256; i++ {
158 sk := babyjub.NewRandPrivKey()
159 pk := sk.Public()
160
161 key, err := ethCrypto.GenerateKey()
162 assert.NoError(t, err)
163 address := ethCrypto.PubkeyToAddress(key.PublicKey)
164
165 account := &Account{
166 TokenID: TokenID(i),
167 Nonce: Nonce(i),
168 Balance: big.NewInt(1000),
169 BJJ: pk.Compress(),
170 EthAddr: address,
171 }
172 b, err := account.Bytes()
173 assert.NoError(t, err)
174 a1, err := AccountFromBytes(b)
175 assert.NoError(t, err)
176 assert.Equal(t, account, a1)
177
178 e, err := account.BigInts()
179 assert.NoError(t, err)
180 assert.True(t, cryptoUtils.CheckBigIntInField(e[0]))
181 assert.True(t, cryptoUtils.CheckBigIntInField(e[1]))
182 assert.True(t, cryptoUtils.CheckBigIntInField(e[2]))
183 assert.True(t, cryptoUtils.CheckBigIntInField(e[3]))
184
185 a2, err := AccountFromBigInts(e)
186 assert.NoError(t, err)
187 assert.Equal(t, account, a2)
188 }
189}
190
191func bigFromStr(h string, u int) *big.Int {
192 if u == 16 {
193 h = strings.TrimPrefix(h, "0x")
194 }
195 b, ok := new(big.Int).SetString(h, u)
196 if !ok {
197 panic("bigFromStr err")
198 }
199 return b
200}
201
202func TestAccountHashValue(t *testing.T) {
203 var sk babyjub.PrivateKey
204 _, err := hex.Decode(sk[:],
205 []byte("0001020304050607080900010203040506070809000102030405060708090001"))
206 assert.NoError(t, err)
207 pk := sk.Public()
208
209 account := &Account{
210 TokenID: TokenID(1),
211 Nonce: Nonce(1234),
212 Balance: big.NewInt(1000),
213 BJJ: pk.Compress(),
214 EthAddr: ethCommon.HexToAddress("0xc58d29fA6e86E4FAe04DDcEd660d45BCf3Cb2370"),
215 }
216 v, err := account.HashValue()
217 assert.NoError(t, err)
218 assert.Equal(t,
219 "16297758255249203915951182296472515138555043617458222397753168518282206850764",
220 v.String())
221}
222
223func TestAccountHashValueTestVectors(t *testing.T) {
224 // values from js test vectors
225 ay := new(big.Int).Sub(new(big.Int).Exp(big.NewInt(2), big.NewInt(253), nil), big.NewInt(1))
226 assert.Equal(t, "1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
227 (hex.EncodeToString(ay.Bytes())))
228 bjjPoint, err := babyjub.PointFromSignAndY(true, ay)
229 require.NoError(t, err)
230 bjj := babyjub.PublicKey(*bjjPoint)
231
232 account := &Account{
233 Idx: 1,
234 TokenID: 0xFFFFFFFF,
235 BJJ: bjj.Compress(),
236 EthAddr: ethCommon.HexToAddress("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"),
237 Nonce: Nonce(0xFFFFFFFFFF),
238 Balance: bigFromStr("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16),
239 }
240
241 e, err := account.BigInts()
242 assert.NoError(t, err)
243 assert.Equal(t, "9444732965739290427391", e[0].String())
244 assert.Equal(t, "6277101735386680763835789423207666416102355444464034512895", e[1].String())
245 assert.Equal(t,
246 "14474011154664524427946373126085988481658748083205070504932198000989141204991",
247 e[2].String())
248 assert.Equal(t, "1461501637330902918203684832716283019655932542975", e[3].String())
249
250 h, err := poseidon.Hash(e[:])
251 assert.NoError(t, err)
252 assert.Equal(t,
253 "4550823210217540218403400309533329186487982452461145263910122718498735057257",
254 h.String())
255
256 v, err := account.HashValue()
257 assert.NoError(t, err)
258 assert.Equal(t,
259 "4550823210217540218403400309533329186487982452461145263910122718498735057257",
260 v.String())
261
262 // second account
263 ay = big.NewInt(0)
264 bjjPoint, err = babyjub.PointFromSignAndY(false, ay)
265 require.NoError(t, err)
266 bjj = babyjub.PublicKey(*bjjPoint)
267 account = &Account{
268 TokenID: 0,
269 BJJ: bjj.Compress(),
270 EthAddr: ethCommon.HexToAddress("0x00"),
271 Nonce: Nonce(0),
272 Balance: big.NewInt(0),
273 }
274 v, err = account.HashValue()
275 assert.NoError(t, err)
276 assert.Equal(t,
277 "7750253361301235345986002241352365187241910378619330147114280396816709365657",
278 v.String())
279
280 // third account
281 ay = bigFromStr("21b0a1688b37f77b1d1d5539ec3b826db5ac78b2513f574a04c50a7d4f8246d7", 16)
282 bjjPoint, err = babyjub.PointFromSignAndY(false, ay)
283 require.NoError(t, err)
284 bjj = babyjub.PublicKey(*bjjPoint)
285 account = &Account{
286 TokenID: 3,
287 BJJ: bjj.Compress(),
288 EthAddr: ethCommon.HexToAddress("0xA3C88ac39A76789437AED31B9608da72e1bbfBF9"),
289 Nonce: Nonce(129),
290 Balance: bigFromStr("42000000000000000000", 10),
291 }
292 e, err = account.BigInts()
293 assert.NoError(t, err)
294 assert.Equal(t, "554050781187", e[0].String())
295 assert.Equal(t, "42000000000000000000", e[1].String())
296 assert.Equal(t,
297 "15238403086306505038849621710779816852318505119327426213168494964113886299863",
298 e[2].String())
299 assert.Equal(t, "935037732739828347587684875151694054123613453305", e[3].String())
300 v, err = account.HashValue()
301 assert.NoError(t, err)
302 assert.Equal(t,
303 "10565754214047872850889045989683221123564392137456000481397520902594455245517",
304 v.String())
305}
306
307func TestAccountErrNotInFF(t *testing.T) {
308 z := big.NewInt(0)
309
310 // Q-1 should not give error
311 r := new(big.Int).Sub(cryptoConstants.Q, big.NewInt(1))
312 e := [NLeafElems]*big.Int{z, z, r, r}
313 _, err := AccountFromBigInts(e)
314 assert.NoError(t, err)
315
316 // Q should give error
317 r = cryptoConstants.Q
318 e = [NLeafElems]*big.Int{z, z, r, r}
319 _, err = AccountFromBigInts(e)
320 assert.NotNil(t, err)
321 assert.Equal(t, ErrNotInFF, tracerr.Unwrap(err))
322
323 // Q+1 should give error
324 r = new(big.Int).Add(cryptoConstants.Q, big.NewInt(1))
325 e = [NLeafElems]*big.Int{z, z, r, r}
326 _, err = AccountFromBigInts(e)
327 assert.NotNil(t, err)
328 assert.Equal(t, ErrNotInFF, tracerr.Unwrap(err))
329}
330
331func TestAccountErrNumOverflowNonce(t *testing.T) {
332 var sk babyjub.PrivateKey
333 _, err := hex.Decode(sk[:],
334 []byte("0001020304050607080900010203040506070809000102030405060708090001"))
335 assert.NoError(t, err)
336 pk := sk.Public()
337
338 // check limit
339 account := &Account{
340 TokenID: TokenID(1),
341 Nonce: Nonce(math.Pow(2, 40) - 1),
342 Balance: big.NewInt(1000),
343 BJJ: pk.Compress(),
344 EthAddr: ethCommon.HexToAddress("0xc58d29fA6e86E4FAe04DDcEd660d45BCf3Cb2370"),
345 }
346 _, err = account.Bytes()
347 assert.NoError(t, err)
348
349 // force value overflow
350 account.Nonce = Nonce(math.Pow(2, 40))
351 b, err := account.Bytes()
352 assert.NotNil(t, err)
353 assert.Equal(t, fmt.Errorf("%s Nonce", ErrNumOverflow), tracerr.Unwrap(err))
354
355 _, err = AccountFromBytes(b)
356 assert.NoError(t, err)
357}
358
359func TestAccountErrNumOverflowBalance(t *testing.T) {
360 var sk babyjub.PrivateKey
361 _, err := hex.Decode(sk[:],
362 []byte("0001020304050607080900010203040506070809000102030405060708090001"))
363 assert.NoError(t, err)
364 pk := sk.Public()
365
366 // check limit
367 account := &Account{
368 TokenID: TokenID(1),
369 Nonce: Nonce(math.Pow(2, 40) - 1),
370 Balance: new(big.Int).Sub(new(big.Int).Exp(big.NewInt(2), big.NewInt(192), nil), big.NewInt(1)),
371 BJJ: pk.Compress(),
372 EthAddr: ethCommon.HexToAddress("0xc58d29fA6e86E4FAe04DDcEd660d45BCf3Cb2370"),
373 }
374 assert.Equal(t, "6277101735386680763835789423207666416102355444464034512895",
375 account.Balance.String())
376
377 _, err = account.Bytes()
378 assert.NoError(t, err)
379
380 // force value overflow
381 account.Balance = new(big.Int).Exp(big.NewInt(2), big.NewInt(192), nil)
382 assert.Equal(t, "6277101735386680763835789423207666416102355444464034512896",
383 account.Balance.String())
384 b, err := account.Bytes()
385 assert.NotNil(t, err)
386 assert.Equal(t, fmt.Errorf("%s Balance", ErrNumOverflow), tracerr.Unwrap(err))
387
388 _, err = AccountFromBytes(b)
389 assert.NoError(t, err)
390
391 b[39] = 1
392 _, err = AccountFromBytes(b)
393 assert.NotNil(t, err)
394 assert.Equal(t, fmt.Errorf("%s Balance", ErrNumOverflow), tracerr.Unwrap(err))
395}