Browse Source

Add PoolL2Tx verify signature needed methods

Implements the hash to be signed from PoolL2Tx, compatible with javascript version.
Implements the signature verification for a given PoolL2Tx.
feature/sql-semaphore1
arnaucube 4 years ago
parent
commit
7fa658cc84
4 changed files with 86 additions and 2 deletions
  1. +27
    -1
      common/pooll2tx.go
  2. +47
    -0
      common/pooll2tx_test.go
  3. +11
    -0
      common/utils.go
  4. +1
    -1
      db/l2db/l2db_test.go

+ 27
- 1
common/pooll2tx.go

@ -9,6 +9,7 @@ import (
eth "github.com/ethereum/go-ethereum/common" eth "github.com/ethereum/go-ethereum/common"
"github.com/hermeznetwork/hermez-node/utils" "github.com/hermeznetwork/hermez-node/utils"
"github.com/iden3/go-iden3-crypto/babyjub" "github.com/iden3/go-iden3-crypto/babyjub"
"github.com/iden3/go-iden3-crypto/poseidon"
) )
// Nonce represents the nonce value in a uint64, which has the method Bytes that returns a byte array of length 5 (40 bits). // Nonce represents the nonce value in a uint64, which has the method Bytes that returns a byte array of length 5 (40 bits).
@ -46,7 +47,7 @@ type PoolL2Tx struct {
Fee FeeSelector `meddler:"fee"` Fee FeeSelector `meddler:"fee"`
Nonce Nonce `meddler:"nonce"` // effective 40 bits used Nonce Nonce `meddler:"nonce"` // effective 40 bits used
State PoolL2TxState `meddler:"state"` State PoolL2TxState `meddler:"state"`
Signature babyjub.Signature `meddler:"signature"` // tx signature
Signature *babyjub.Signature `meddler:"signature"` // tx signature
Timestamp time.Time `meddler:"timestamp,utctime"` // time when added to the tx pool Timestamp time.Time `meddler:"timestamp,utctime"` // time when added to the tx pool
// Stored in DB: optional fileds, may be uninitialized // Stored in DB: optional fileds, may be uninitialized
BatchNum BatchNum `meddler:"batch_num,zeroisnull"` // batchNum in which this tx was forged. Presence indicates "forged" state. BatchNum BatchNum `meddler:"batch_num,zeroisnull"` // batchNum in which this tx was forged. Presence indicates "forged" state.
@ -145,6 +146,31 @@ func (tx *PoolL2Tx) TxCompressedDataV2() (*big.Int, error) {
return bi, nil return bi, nil
} }
// HashToSign returns the computed Poseidon hash from the *PoolL2Tx that will be signed by the sender.
func (tx *PoolL2Tx) HashToSign() (*big.Int, error) {
toCompressedData, err := tx.TxCompressedData()
if err != nil {
return nil, err
}
toEthAddr := EthAddrToBigInt(tx.ToEthAddr)
toBjjAy := tx.ToBJJ.Y
rqTxCompressedDataV2, err := tx.TxCompressedDataV2()
if err != nil {
return nil, err
}
return poseidon.Hash([]*big.Int{toCompressedData, toEthAddr, toBjjAy, rqTxCompressedDataV2, EthAddrToBigInt(tx.RqToEthAddr), tx.RqToBJJ.Y})
}
// VerifySignature returns true if the signature verification is correct for the given PublicKey
func (tx *PoolL2Tx) VerifySignature(pk *babyjub.PublicKey) bool {
h, err := tx.HashToSign()
if err != nil {
return false
}
return pk.VerifyPoseidon(h, tx.Signature)
}
func (tx *PoolL2Tx) Tx() *Tx { func (tx *PoolL2Tx) Tx() *Tx {
return &Tx{ return &Tx{
TxID: tx.TxID, TxID: tx.TxID,

+ 47
- 0
common/pooll2tx_test.go

@ -5,6 +5,7 @@ import (
"math/big" "math/big"
"testing" "testing"
ethCommon "github.com/ethereum/go-ethereum/common"
"github.com/iden3/go-iden3-crypto/babyjub" "github.com/iden3/go-iden3-crypto/babyjub"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -73,3 +74,49 @@ func TestTxCompressedData(t *testing.T) {
assert.Equal(t, "10c000000000b0000000a0009000000000008000000000007", hex.EncodeToString(txCompressedData.Bytes())[1:]) assert.Equal(t, "10c000000000b0000000a0009000000000008000000000007", hex.EncodeToString(txCompressedData.Bytes())[1:])
} }
func TestHashToSign(t *testing.T) {
var sk babyjub.PrivateKey
_, err := hex.Decode(sk[:], []byte("0001020304050607080900010203040506070809000102030405060708090001"))
assert.Nil(t, err)
ethAddr := ethCommon.HexToAddress("0xc58d29fA6e86E4FAe04DDcEd660d45BCf3Cb2370")
tx := PoolL2Tx{
FromIdx: 2,
ToIdx: 3,
Amount: big.NewInt(4),
TokenID: 5,
Nonce: 6,
ToBJJ: sk.Public(),
RqToEthAddr: ethAddr,
RqToBJJ: sk.Public(),
}
toSign, err := tx.HashToSign()
assert.Nil(t, err)
assert.Equal(t, "14526446928649310956370997581245770629723313742905751117262272426489782809503", toSign.String())
}
func TestVerifyTxSignature(t *testing.T) {
var sk babyjub.PrivateKey
_, err := hex.Decode(sk[:], []byte("0001020304050607080900010203040506070809000102030405060708090001"))
assert.Nil(t, err)
ethAddr := ethCommon.HexToAddress("0xc58d29fA6e86E4FAe04DDcEd660d45BCf3Cb2370")
tx := PoolL2Tx{
FromIdx: 2,
ToIdx: 3,
Amount: big.NewInt(4),
TokenID: 5,
Nonce: 6,
ToBJJ: sk.Public(),
RqToEthAddr: ethAddr,
RqToBJJ: sk.Public(),
}
toSign, err := tx.HashToSign()
assert.Nil(t, err)
assert.Equal(t, "14526446928649310956370997581245770629723313742905751117262272426489782809503", toSign.String())
sig := sk.SignPoseidon(toSign)
tx.Signature = sig
assert.True(t, tx.VerifySignature(sk.Public()))
}

+ 11
- 0
common/utils.go

@ -1,5 +1,11 @@
package common package common
import (
"math/big"
ethCommon "github.com/ethereum/go-ethereum/common"
)
// SwapEndianness swaps the order of the bytes in the slice. // SwapEndianness swaps the order of the bytes in the slice.
func SwapEndianness(b []byte) []byte { func SwapEndianness(b []byte) []byte {
o := make([]byte, len(b)) o := make([]byte, len(b))
@ -8,3 +14,8 @@ func SwapEndianness(b []byte) []byte {
} }
return o return o
} }
// EthAddrToBigInt returns a *big.Int from a given ethereum common.Address.
func EthAddrToBigInt(a ethCommon.Address) *big.Int {
return new(big.Int).SetBytes(a.Bytes())
}

+ 1
- 1
db/l2db/l2db_test.go

@ -149,7 +149,7 @@ func genTxs(n int) []*common.PoolL2Tx {
Fee: 99, Fee: 99,
Nonce: 28, Nonce: 28,
State: state, State: state,
Signature: *privK.SignPoseidon(big.NewInt(674238462)),
Signature: privK.SignPoseidon(big.NewInt(674238462)),
Timestamp: time.Now().UTC(), Timestamp: time.Now().UTC(),
} }
if i%2 == 0 { // Optional parameters: rq if i%2 == 0 { // Optional parameters: rq

Loading…
Cancel
Save