Browse Source

Update AccountCreationAuth & fix auth.HashToSign

- Fix AccountCreationAuth.HashToSign (was using `[]byte("0x...")`, which
uses the bytes of the string. Now uses the bytearray of the compressed
BJJ public key (compatible with js implementation))
- Update AccountCreationAuth to last specification (add to hash
parameters ChainID & HermezAddress)
- Add missing test to AccountCreationAuth
feature/sql-semaphore1
arnaucube 3 years ago
parent
commit
8615a462ab
11 changed files with 95 additions and 36 deletions
  1. +1
    -1
      api/accountcreationauths.go
  2. +13
    -11
      api/api.go
  3. +2
    -3
      api/api_test.go
  4. +3
    -0
      api/config.go
  5. +4
    -1
      api/config_test.go
  6. +17
    -12
      common/accountcreationauths.go
  7. +41
    -0
      common/accountcreationauths_test.go
  8. +3
    -1
      db/l2db/l2db_test.go
  9. +2
    -3
      node/node.go
  10. +3
    -2
      test/l2db.go
  11. +6
    -2
      test/l2db_test.go

+ 1
- 1
api/accountcreationauths.go

@ -21,7 +21,7 @@ func (a *API) postAccountCreationAuth(c *gin.Context) {
} }
// API to common + verify signature // API to common + verify signature
commonAuth := accountCreationAuthAPIToCommon(&apiAuth) commonAuth := accountCreationAuthAPIToCommon(&apiAuth)
if !commonAuth.VerifySignature() {
if !commonAuth.VerifySignature(a.chainID, a.hermezAddress) {
retBadReq(errors.New("invalid signature"), c) retBadReq(errors.New("invalid signature"), c)
return return
} }

+ 13
- 11
api/api.go

@ -4,6 +4,7 @@ import (
"errors" "errors"
"sync" "sync"
ethCommon "github.com/ethereum/go-ethereum/common"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/hermeznetwork/hermez-node/common" "github.com/hermeznetwork/hermez-node/common"
"github.com/hermeznetwork/hermez-node/db/historydb" "github.com/hermeznetwork/hermez-node/db/historydb"
@ -31,12 +32,13 @@ type Status struct {
// API serves HTTP requests to allow external interaction with the Hermez node // API serves HTTP requests to allow external interaction with the Hermez node
type API struct { type API struct {
h *historydb.HistoryDB
cg *configAPI
s *statedb.StateDB
l2 *l2db.L2DB
status Status
chainID uint16
h *historydb.HistoryDB
cg *configAPI
s *statedb.StateDB
l2 *l2db.L2DB
status Status
chainID uint16
hermezAddress ethCommon.Address
} }
// NewAPI sets the endpoints and the appropriate handlers, but doesn't start the server // NewAPI sets the endpoints and the appropriate handlers, but doesn't start the server
@ -47,7 +49,6 @@ func NewAPI(
sdb *statedb.StateDB, sdb *statedb.StateDB,
l2db *l2db.L2DB, l2db *l2db.L2DB,
config *Config, config *Config,
chainID uint16,
) (*API, error) { ) (*API, error) {
// Check input // Check input
// TODO: is stateDB only needed for explorer endpoints or for both? // TODO: is stateDB only needed for explorer endpoints or for both?
@ -65,10 +66,11 @@ func NewAPI(
AuctionConstants: config.AuctionConstants, AuctionConstants: config.AuctionConstants,
WDelayerConstants: config.WDelayerConstants, WDelayerConstants: config.WDelayerConstants,
}, },
s: sdb,
l2: l2db,
status: Status{},
chainID: chainID,
s: sdb,
l2: l2db,
status: Status{},
chainID: config.ChainID,
hermezAddress: config.HermezAddress,
} }
// Add coordinator endpoints // Add coordinator endpoints

+ 2
- 3
api/api_test.go

@ -221,7 +221,7 @@ func TestMain(m *testing.M) {
test.WipeDB(l2DB.DB()) // this will clean HistoryDB and L2DB test.WipeDB(l2DB.DB()) // this will clean HistoryDB and L2DB
// Config (smart contract constants) // Config (smart contract constants)
_config := getConfigTest()
_config := getConfigTest(chainID)
config = configAPI{ config = configAPI{
RollupConstants: *newRollupConstants(_config.RollupConstants), RollupConstants: *newRollupConstants(_config.RollupConstants),
AuctionConstants: _config.AuctionConstants, AuctionConstants: _config.AuctionConstants,
@ -238,7 +238,6 @@ func TestMain(m *testing.M) {
sdb, sdb,
l2DB, l2DB,
&_config, &_config,
chainID,
) )
if err != nil { if err != nil {
panic(err) panic(err)
@ -423,7 +422,7 @@ func TestMain(m *testing.M) {
exits: testExits, exits: testExits,
poolTxsToSend: poolTxsToSend, poolTxsToSend: poolTxsToSend,
poolTxsToReceive: poolTxsToReceive, poolTxsToReceive: poolTxsToReceive,
auths: genTestAuths(test.GenAuths(5)),
auths: genTestAuths(test.GenAuths(5, _config.ChainID, _config.HermezAddress)),
router: router, router: router,
bids: testBids, bids: testBids,
slots: api.genTestSlots( slots: api.genTestSlots(

+ 3
- 0
api/config.go

@ -4,6 +4,7 @@ import (
"math/big" "math/big"
"net/http" "net/http"
ethCommon "github.com/ethereum/go-ethereum/common"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/hermeznetwork/hermez-node/common" "github.com/hermeznetwork/hermez-node/common"
) )
@ -51,6 +52,8 @@ type Config struct {
RollupConstants common.RollupConstants RollupConstants common.RollupConstants
AuctionConstants common.AuctionConstants AuctionConstants common.AuctionConstants
WDelayerConstants common.WDelayerConstants WDelayerConstants common.WDelayerConstants
ChainID uint16
HermezAddress ethCommon.Address
} }
type configAPI struct { type configAPI struct {

+ 4
- 1
api/config_test.go

@ -9,7 +9,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func getConfigTest() Config {
func getConfigTest(chainID uint16) Config {
var config Config var config Config
var rollupPublicConstants common.RollupConstants var rollupPublicConstants common.RollupConstants
@ -40,6 +40,9 @@ func getConfigTest() Config {
config.AuctionConstants = auctionConstants config.AuctionConstants = auctionConstants
config.WDelayerConstants = wdelayerConstants config.WDelayerConstants = wdelayerConstants
config.ChainID = chainID
config.HermezAddress = ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6")
return config return config
} }

+ 17
- 12
common/accountcreationauths.go

@ -1,15 +1,20 @@
package common package common
import ( import (
"encoding/binary"
"time" "time"
ethCommon "github.com/ethereum/go-ethereum/common" ethCommon "github.com/ethereum/go-ethereum/common"
ethCrypto "github.com/ethereum/go-ethereum/crypto" ethCrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/hermeznetwork/tracerr"
"github.com/iden3/go-iden3-crypto/babyjub" "github.com/iden3/go-iden3-crypto/babyjub"
) )
// AccountCreationAuth authorizations sent by users to the L2DB, to be used for account creations when necessary
// AccountCreationAuthMsg is the message that is signed to authorize an account
// creation
const AccountCreationAuthMsg = "I authorize this babyjubjub key for hermez rollup account creation"
// AccountCreationAuth authorizations sent by users to the L2DB, to be used for
// account creations when necessary
type AccountCreationAuth struct { type AccountCreationAuth struct {
EthAddr ethCommon.Address `meddler:"eth_addr"` EthAddr ethCommon.Address `meddler:"eth_addr"`
BJJ babyjub.PublicKeyComp `meddler:"bjj"` BJJ babyjub.PublicKeyComp `meddler:"bjj"`
@ -18,21 +23,21 @@ type AccountCreationAuth struct {
} }
// HashToSign builds the hash to be signed using BJJ pub key and the constant message // HashToSign builds the hash to be signed using BJJ pub key and the constant message
func (a *AccountCreationAuth) HashToSign() ([]byte, error) {
func (a *AccountCreationAuth) HashToSign(chainID uint16,
hermezContractAddr ethCommon.Address) ([]byte, error) {
// Calculate message to be signed // Calculate message to be signed
const msg = "I authorize this babyjubjub key for hermez rollup account creation"
comp, err := a.BJJ.MarshalText()
if err != nil {
return nil, tracerr.Wrap(err)
}
// Hash message (msg || compressed-bjj)
return ethCrypto.Keccak256Hash([]byte(msg), comp).Bytes(), nil
var chainIDBytes [2]byte
binary.BigEndian.PutUint16(chainIDBytes[:], chainID)
// to hash: [AccountCreationAuthMsg | compressedBJJ | chainID | hermezContractAddr]
return ethCrypto.Keccak256Hash([]byte(AccountCreationAuthMsg), a.BJJ[:], chainIDBytes[:],
hermezContractAddr[:]).Bytes(), nil
} }
// VerifySignature ensures that the Signature is done with the specified EthAddr // VerifySignature ensures that the Signature is done with the specified EthAddr
func (a *AccountCreationAuth) VerifySignature() bool {
func (a *AccountCreationAuth) VerifySignature(chainID uint16,
hermezContractAddr ethCommon.Address) bool {
// Calculate hash to be signed // Calculate hash to be signed
msg, err := a.HashToSign()
msg, err := a.HashToSign(chainID, hermezContractAddr)
if err != nil { if err != nil {
return false return false
} }

+ 41
- 0
common/accountcreationauths_test.go

@ -0,0 +1,41 @@
package common
import (
"encoding/hex"
"testing"
ethCommon "github.com/ethereum/go-ethereum/common"
ethCrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/iden3/go-iden3-crypto/babyjub"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestAccountCreationAuth(t *testing.T) {
// Ethereum key
ethSk, err := ethCrypto.HexToECDSA("fad9c8855b740a0b7ed4c221dbad0f33a83a49cad6b3fe8d5817ac83d38b6a19")
require.NoError(t, err)
ethAddr := ethCrypto.PubkeyToAddress(ethSk.PublicKey)
// BabyJubJub key
var sk babyjub.PrivateKey
_, err = hex.Decode(sk[:], []byte("0001020304050607080900010203040506070809000102030405060708090001"))
assert.NoError(t, err)
chainID := uint16(0)
hermezContractAddr := ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6")
a := AccountCreationAuth{
EthAddr: ethAddr,
BJJ: sk.Public().Compress(),
}
msg, err := a.HashToSign(chainID, hermezContractAddr)
assert.NoError(t, err)
assert.Equal(t, "cb5a7e44329ff430c81fec49fb2ac6741f02d5ec96cbcb618a6991f0a9c80ffd", hex.EncodeToString(msg))
// sign AccountCreationAuth with eth key
sig, err := ethCrypto.Sign(msg, ethSk)
assert.NoError(t, err)
a.Signature = sig
assert.True(t, a.VerifySignature(chainID, hermezContractAddr))
}

+ 3
- 1
db/l2db/l2db_test.go

@ -611,8 +611,10 @@ func TestPurge(t *testing.T) {
func TestAuth(t *testing.T) { func TestAuth(t *testing.T) {
test.WipeDB(l2DB.DB()) test.WipeDB(l2DB.DB())
const nAuths = 5 const nAuths = 5
chainID := uint16(0)
hermezContractAddr := ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6")
// Generate authorizations // Generate authorizations
auths := test.GenAuths(nAuths)
auths := test.GenAuths(nAuths, chainID, hermezContractAddr)
for i := 0; i < len(auths); i++ { for i := 0; i < len(auths); i++ {
// Add to the DB // Add to the DB
err := l2DB.AddAccountCreationAuth(auths[i]) err := l2DB.AddAccountCreationAuth(auths[i])

+ 2
- 3
node/node.go

@ -245,8 +245,9 @@ func NewNode(mode Mode, cfg *config.Node) (*Node, error) {
RollupConstants: scConsts.Rollup, RollupConstants: scConsts.Rollup,
AuctionConstants: scConsts.Auction, AuctionConstants: scConsts.Auction,
WDelayerConstants: scConsts.WDelayer, WDelayerConstants: scConsts.WDelayer,
ChainID: chainIDU16,
HermezAddress: cfg.SmartContracts.Rollup,
}, },
chainIDU16,
) )
if err != nil { if err != nil {
return nil, tracerr.Wrap(err) return nil, tracerr.Wrap(err)
@ -301,7 +302,6 @@ func NewNodeAPI(
sdb *statedb.StateDB, sdb *statedb.StateDB,
l2db *l2db.L2DB, l2db *l2db.L2DB,
config *api.Config, config *api.Config,
chainID uint16,
) (*NodeAPI, error) { ) (*NodeAPI, error) {
engine := gin.Default() engine := gin.Default()
engine.NoRoute(handleNoRoute) engine.NoRoute(handleNoRoute)
@ -313,7 +313,6 @@ func NewNodeAPI(
sdb, sdb,
l2db, l2db,
config, config,
chainID,
) )
if err != nil { if err != nil {
return nil, tracerr.Wrap(err) return nil, tracerr.Wrap(err)

+ 3
- 2
test/l2db.go

@ -1,6 +1,7 @@
package test package test
import ( import (
ethCommon "github.com/ethereum/go-ethereum/common"
ethCrypto "github.com/ethereum/go-ethereum/crypto" ethCrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/hermeznetwork/hermez-node/common" "github.com/hermeznetwork/hermez-node/common"
"github.com/iden3/go-iden3-crypto/babyjub" "github.com/iden3/go-iden3-crypto/babyjub"
@ -66,7 +67,7 @@ func GenPoolTxs(n int, tokens []common.Token) []*common.PoolL2Tx {
} }
// GenAuths generates account creation authorizations // GenAuths generates account creation authorizations
func GenAuths(nAuths int) []*common.AccountCreationAuth {
func GenAuths(nAuths int, chainID uint16, hermezContractAddr ethCommon.Address) []*common.AccountCreationAuth {
auths := []*common.AccountCreationAuth{} auths := []*common.AccountCreationAuth{}
for i := 0; i < nAuths; i++ { for i := 0; i < nAuths; i++ {
// Generate keys // Generate keys
@ -81,7 +82,7 @@ func GenAuths(nAuths int) []*common.AccountCreationAuth {
BJJ: bjjPrivK.Public().Compress(), BJJ: bjjPrivK.Public().Compress(),
} }
// Sign // Sign
h, err := auth.HashToSign()
h, err := auth.HashToSign(chainID, hermezContractAddr)
if err != nil { if err != nil {
panic(err) panic(err)
} }

+ 6
- 2
test/l2db_test.go

@ -3,13 +3,17 @@ package test
import ( import (
"testing" "testing"
ethCommon "github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestGenAuths(t *testing.T) { func TestGenAuths(t *testing.T) {
chainID := uint16(0)
hermezContractAddr := ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6")
const nAuths = 5 const nAuths = 5
auths := GenAuths(nAuths)
auths := GenAuths(nAuths, chainID, hermezContractAddr)
for _, auth := range auths { for _, auth := range auths {
assert.True(t, auth.VerifySignature())
assert.True(t, auth.VerifySignature(chainID, hermezContractAddr))
} }
} }

Loading…
Cancel
Save