arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
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.
arnaucube root@arnaucube.com
Mon, 24 Aug 2020 09:41:43 +0200
commit

7fa658cc84bd0e5b2f401a45584dd5a3767b9554

parent

869ab519a4724b0dc3586d452f267bbc035e34ec

4 files changed, 86 insertions(+), 2 deletions(-)

jump to
M common/pooll2tx.go → common/pooll2tx.go

@@ -9,6 +9,7 @@

eth "github.com/ethereum/go-ethereum/common" "github.com/hermeznetwork/hermez-node/utils" "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).

@@ -46,7 +47,7 @@ Amount *big.Int `meddler:"amount,bigint"` // TODO: change to float16

Fee FeeSelector `meddler:"fee"` Nonce Nonce `meddler:"nonce"` // effective 40 bits used 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 // 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.

@@ -143,6 +144,31 @@ b[24] = toBjjSign

bi := new(big.Int).SetBytes(SwapEndianness(b[:])) 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 {
M common/pooll2tx_test.go → common/pooll2tx_test.go

@@ -5,6 +5,7 @@ "encoding/hex"

"math/big" "testing" + ethCommon "github.com/ethereum/go-ethereum/common" "github.com/iden3/go-iden3-crypto/babyjub" "github.com/stretchr/testify/assert" )

@@ -73,3 +74,49 @@ assert.Equal(t, "6571340879233176732837827812956721483162819083004853354503", txCompressedData.String())

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())) +}
M common/utils.go → common/utils.go

@@ -1,5 +1,11 @@

package common +import ( + "math/big" + + ethCommon "github.com/ethereum/go-ethereum/common" +) + // SwapEndianness swaps the order of the bytes in the slice. func SwapEndianness(b []byte) []byte { o := make([]byte, len(b))

@@ -8,3 +14,8 @@ o[len(b)-1-i] = b[i]

} 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()) +}
M db/l2db/l2db_test.go → db/l2db/l2db_test.go

@@ -149,7 +149,7 @@ Amount: big.NewInt(3487762374627846747),

Fee: 99, Nonce: 28, State: state, - Signature: *privK.SignPoseidon(big.NewInt(674238462)), + Signature: privK.SignPoseidon(big.NewInt(674238462)), Timestamp: time.Now().UTC(), } if i%2 == 0 { // Optional parameters: rq