mirror of
https://github.com/arnaucube/hermez-node.git
synced 2026-02-07 03:16:45 +01:00
Merge pull request #591 from hermeznetwork/feature/accCreationAuth-EIP712
Update AccCreationAuth signature hash to EIP-712
This commit is contained in:
@@ -1,21 +1,25 @@
|
|||||||
package common
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
ethCommon "github.com/ethereum/go-ethereum/common"
|
ethCommon "github.com/ethereum/go-ethereum/common"
|
||||||
|
ethMath "github.com/ethereum/go-ethereum/common/math"
|
||||||
ethCrypto "github.com/ethereum/go-ethereum/crypto"
|
ethCrypto "github.com/ethereum/go-ethereum/crypto"
|
||||||
|
ethSigner "github.com/ethereum/go-ethereum/signer/core"
|
||||||
|
"github.com/hermeznetwork/tracerr"
|
||||||
"github.com/iden3/go-iden3-crypto/babyjub"
|
"github.com/iden3/go-iden3-crypto/babyjub"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AccountCreationAuthMsg is the message that is signed to authorize a Hermez
|
// AccountCreationAuthMsg is the message that is signed to authorize a Hermez
|
||||||
// account creation
|
// account creation
|
||||||
const AccountCreationAuthMsg = "I authorize this babyjubjub key for hermez rollup account creation"
|
const AccountCreationAuthMsg = "Account creation"
|
||||||
|
|
||||||
// EthMsgPrefix is the prefix for message signing at the Ethereum ecosystem
|
// EIP712Version is the used version of the EIP-712
|
||||||
const EthMsgPrefix = "\x19Ethereum Signed Message:\n"
|
const EIP712Version = "1"
|
||||||
|
|
||||||
|
// EIP712Provider defines the Provider for the EIP-712
|
||||||
|
const EIP712Provider = "Hermez Network"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// EmptyEthSignature is an ethereum signature of all zeroes
|
// EmptyEthSignature is an ethereum signature of all zeroes
|
||||||
@@ -31,27 +35,64 @@ type AccountCreationAuth struct {
|
|||||||
Timestamp time.Time `meddler:"timestamp,utctime"`
|
Timestamp time.Time `meddler:"timestamp,utctime"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// toHash returns a byte array to be hashed from the AccountCreationAuth, which
|
||||||
|
// follows the EIP-712 encoding
|
||||||
func (a *AccountCreationAuth) toHash(chainID uint16,
|
func (a *AccountCreationAuth) toHash(chainID uint16,
|
||||||
hermezContractAddr ethCommon.Address) []byte {
|
hermezContractAddr ethCommon.Address) ([]byte, error) {
|
||||||
var chainIDBytes [2]byte
|
chainIDFormatted := ethMath.NewHexOrDecimal256(int64(chainID))
|
||||||
binary.BigEndian.PutUint16(chainIDBytes[:], chainID)
|
|
||||||
// [EthPrefix | AccountCreationAuthMsg | compressedBJJ | chainID | hermezContractAddr]
|
|
||||||
var b []byte
|
|
||||||
b = append(b, []byte(AccountCreationAuthMsg)...)
|
|
||||||
b = append(b, SwapEndianness(a.BJJ[:])...) // for js implementation compatibility
|
|
||||||
b = append(b, chainIDBytes[:]...)
|
|
||||||
b = append(b, hermezContractAddr[:]...)
|
|
||||||
|
|
||||||
ethPrefix := EthMsgPrefix + strconv.Itoa(len(b))
|
signerData := ethSigner.TypedData{
|
||||||
return append([]byte(ethPrefix), b...)
|
Types: ethSigner.Types{
|
||||||
|
"EIP712Domain": []ethSigner.Type{
|
||||||
|
{Name: "name", Type: "string"},
|
||||||
|
{Name: "version", Type: "string"},
|
||||||
|
{Name: "chainId", Type: "uint256"},
|
||||||
|
{Name: "verifyingContract", Type: "address"},
|
||||||
|
},
|
||||||
|
"Authorise": []ethSigner.Type{
|
||||||
|
{Name: "Provider", Type: "string"},
|
||||||
|
{Name: "Authorisation", Type: "string"},
|
||||||
|
{Name: "BJJKey", Type: "bytes32"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PrimaryType: "Authorise",
|
||||||
|
Domain: ethSigner.TypedDataDomain{
|
||||||
|
Name: EIP712Provider,
|
||||||
|
Version: EIP712Version,
|
||||||
|
ChainId: chainIDFormatted,
|
||||||
|
VerifyingContract: hermezContractAddr.Hex(),
|
||||||
|
},
|
||||||
|
Message: ethSigner.TypedDataMessage{
|
||||||
|
"Provider": EIP712Provider,
|
||||||
|
"Authorisation": AccountCreationAuthMsg,
|
||||||
|
"BJJKey": SwapEndianness(a.BJJ[:]),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
domainSeparator, err := signerData.HashStruct("EIP712Domain", signerData.Domain.Map())
|
||||||
|
if err != nil {
|
||||||
|
return nil, tracerr.Wrap(err)
|
||||||
|
}
|
||||||
|
typedDataHash, err := signerData.HashStruct(signerData.PrimaryType, signerData.Message)
|
||||||
|
if err != nil {
|
||||||
|
return nil, tracerr.Wrap(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rawData := []byte{0x19, 0x01} // "\x19\x01"
|
||||||
|
rawData = append(rawData, domainSeparator...)
|
||||||
|
rawData = append(rawData, typedDataHash...)
|
||||||
|
return rawData, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// HashToSign returns the hash to be signed by the Etherum address to authorize
|
// HashToSign returns the hash to be signed by the Etherum address to authorize
|
||||||
// the account creation
|
// the account creation, which follows the EIP-712 encoding
|
||||||
func (a *AccountCreationAuth) HashToSign(chainID uint16,
|
func (a *AccountCreationAuth) HashToSign(chainID uint16,
|
||||||
hermezContractAddr ethCommon.Address) ([]byte, error) {
|
hermezContractAddr ethCommon.Address) ([]byte, error) {
|
||||||
b := a.toHash(chainID, hermezContractAddr)
|
b, err := a.toHash(chainID, hermezContractAddr)
|
||||||
return ethCrypto.Keccak256Hash(b).Bytes(), nil
|
if err != nil {
|
||||||
|
return nil, tracerr.Wrap(err)
|
||||||
|
}
|
||||||
|
return ethCrypto.Keccak256(b), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sign signs the account creation authorization message using the provided
|
// Sign signs the account creation authorization message using the provided
|
||||||
@@ -59,16 +100,17 @@ func (a *AccountCreationAuth) HashToSign(chainID uint16,
|
|||||||
// should do an ethereum signature using the account corresponding to
|
// should do an ethereum signature using the account corresponding to
|
||||||
// `a.EthAddr`. The `signHash` function is used to make signig flexible: in
|
// `a.EthAddr`. The `signHash` function is used to make signig flexible: in
|
||||||
// tests we sign directly using the private key, outside tests we sign using
|
// tests we sign directly using the private key, outside tests we sign using
|
||||||
// the keystore (which never exposes the private key).
|
// the keystore (which never exposes the private key). Sign follows the EIP-712
|
||||||
|
// encoding.
|
||||||
func (a *AccountCreationAuth) Sign(signHash func(hash []byte) ([]byte, error),
|
func (a *AccountCreationAuth) Sign(signHash func(hash []byte) ([]byte, error),
|
||||||
chainID uint16, hermezContractAddr ethCommon.Address) error {
|
chainID uint16, hermezContractAddr ethCommon.Address) error {
|
||||||
hash, err := a.HashToSign(chainID, hermezContractAddr)
|
hash, err := a.HashToSign(chainID, hermezContractAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return tracerr.Wrap(err)
|
||||||
}
|
}
|
||||||
sig, err := signHash(hash)
|
sig, err := signHash(hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return tracerr.Wrap(err)
|
||||||
}
|
}
|
||||||
sig[64] += 27
|
sig[64] += 27
|
||||||
a.Signature = sig
|
a.Signature = sig
|
||||||
@@ -77,7 +119,8 @@ func (a *AccountCreationAuth) Sign(signHash func(hash []byte) ([]byte, error),
|
|||||||
}
|
}
|
||||||
|
|
||||||
// VerifySignature ensures that the Signature is done with the EthAddr, for the
|
// VerifySignature ensures that the Signature is done with the EthAddr, for the
|
||||||
// chainID and hermezContractAddress passed by parameter
|
// chainID and hermezContractAddress passed by parameter. VerifySignature
|
||||||
|
// follows the EIP-712 encoding.
|
||||||
func (a *AccountCreationAuth) VerifySignature(chainID uint16,
|
func (a *AccountCreationAuth) VerifySignature(chainID uint16,
|
||||||
hermezContractAddr ethCommon.Address) bool {
|
hermezContractAddr ethCommon.Address) bool {
|
||||||
// Calculate hash to be signed
|
// Calculate hash to be signed
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ func TestAccountCreationAuthSignVerify(t *testing.T) {
|
|||||||
// Hash and sign manually and compare the generated signature
|
// Hash and sign manually and compare the generated signature
|
||||||
hash, err := a.HashToSign(chainID, hermezContractAddr)
|
hash, err := a.HashToSign(chainID, hermezContractAddr)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, "4f8df75e96fdce1ac90bb2f8d81c42047600f85bfcef80ce3b91c2a2afc58c1e",
|
assert.Equal(t, "9414667457e658dd31949b82996b75c65a055512244c3bbfd22ff56add02ba65",
|
||||||
hex.EncodeToString(hash))
|
hex.EncodeToString(hash))
|
||||||
sig, err := ethCrypto.Sign(hash, ethSk)
|
sig, err := ethCrypto.Sign(hash, ethSk)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -75,9 +75,9 @@ func TestAccountCreationAuthJSComp(t *testing.T) {
|
|||||||
pkCompStr: "21b0a1688b37f77b1d1d5539ec3b826db5ac78b2513f574a04c50a7d4f8246d7",
|
pkCompStr: "21b0a1688b37f77b1d1d5539ec3b826db5ac78b2513f574a04c50a7d4f8246d7",
|
||||||
chainID: uint16(4),
|
chainID: uint16(4),
|
||||||
hermezContractAddr: "0x7e5f4552091a69125d5dfcb7b8c2659029395bdf",
|
hermezContractAddr: "0x7e5f4552091a69125d5dfcb7b8c2659029395bdf",
|
||||||
toHashExpected: "19457468657265756d205369676e6564204d6573736167653a0a3132304920617574686f72697a65207468697320626162796a75626a7562206b657920666f72206865726d657a20726f6c6c7570206163636f756e74206372656174696f6e21b0a1688b37f77b1d1d5539ec3b826db5ac78b2513f574a04c50a7d4f8246d700047e5f4552091a69125d5dfcb7b8c2659029395bdf",
|
toHashExpected: "190189658bba487e11c7da602676ee32bc90b77d3f32a305b147e4f3c3b35f19672e5d84ccc38d0ab245c469b719549d837113465c2abf9972c49403ca6fd10ed3dc",
|
||||||
hashExpected: "39afea52d843a4de905b6b5ebb0ee8c678141f711d96d9b429c4aec10ef9911f",
|
hashExpected: "c56eba41e511df100c804c5c09288f35887efea4f033be956481af335df3bea2",
|
||||||
sigExpected: "73d10d6ecf06ee8a5f60ac90f06b78bef9c650f414ba3ac73e176dc32e896159147457e9c86f0b4bd60fdaf2c0b2aec890a7df993d69a4805e242a6b845ebf231c",
|
sigExpected: "dbedcc5ce02db8f48afbdb2feba9a3a31848eaa8fca5f312ce37b01db45d2199208335330d4445bd2f51d1db68dbc0d0bf3585c4a07504b4efbe46a69eaae5a21b",
|
||||||
}
|
}
|
||||||
tv1 := testVector{
|
tv1 := testVector{
|
||||||
ethSk: "0000000000000000000000000000000000000000000000000000000000000002",
|
ethSk: "0000000000000000000000000000000000000000000000000000000000000002",
|
||||||
@@ -85,9 +85,9 @@ func TestAccountCreationAuthJSComp(t *testing.T) {
|
|||||||
pkCompStr: "093985b1993d9f743f9d7d943ed56f38601cb8b196db025f79650c4007c3054d",
|
pkCompStr: "093985b1993d9f743f9d7d943ed56f38601cb8b196db025f79650c4007c3054d",
|
||||||
chainID: uint16(0),
|
chainID: uint16(0),
|
||||||
hermezContractAddr: "0x2b5ad5c4795c026514f8317c7a215e218dccd6cf",
|
hermezContractAddr: "0x2b5ad5c4795c026514f8317c7a215e218dccd6cf",
|
||||||
toHashExpected: "19457468657265756d205369676e6564204d6573736167653a0a3132304920617574686f72697a65207468697320626162796a75626a7562206b657920666f72206865726d657a20726f6c6c7570206163636f756e74206372656174696f6e093985b1993d9f743f9d7d943ed56f38601cb8b196db025f79650c4007c3054d00002b5ad5c4795c026514f8317c7a215e218dccd6cf",
|
toHashExpected: "1901dafbc253dedf90d6421dc6e25d5d9efc6985133cb2a8d363d0a081a0e3eddddc65f603a88de36aaeabd3b4cf586538c7f3fd50c94780530a3707c8c14ad9fd11",
|
||||||
hashExpected: "89a3895993a4736232212e59566294feb3da227af44375daf3307dcad5451d5d",
|
hashExpected: "deb9afa479282cf27b442ce8ba86b19448aa87eacef691521a33db5d0feb9959",
|
||||||
sigExpected: "bb4156156c705494ad5f99030342c64657e51e2994750f92125717c40bf56ad632044aa6bd00979feea92c417b552401e65fe5f531f15010d9d1c278da8be1df1b",
|
sigExpected: "6a0da90ba2d2b1be679a28ebe54ee03082d44b836087391cd7d2607c1e4dafe04476e6e88dccb8707c68312512f16c947524b35c80f26c642d23953e9bb84c701c",
|
||||||
}
|
}
|
||||||
tv2 := testVector{
|
tv2 := testVector{
|
||||||
ethSk: "c5e8f61d1ab959b397eecc0a37a6517b8e67a0e7cf1f4bce5591f3ed80199122",
|
ethSk: "c5e8f61d1ab959b397eecc0a37a6517b8e67a0e7cf1f4bce5591f3ed80199122",
|
||||||
@@ -95,9 +95,9 @@ func TestAccountCreationAuthJSComp(t *testing.T) {
|
|||||||
pkCompStr: "22870c1bcc451396202d62f566026eab8e438c6c91decf8ddf63a6c162619b52",
|
pkCompStr: "22870c1bcc451396202d62f566026eab8e438c6c91decf8ddf63a6c162619b52",
|
||||||
chainID: uint16(31337), // =0x7a69
|
chainID: uint16(31337), // =0x7a69
|
||||||
hermezContractAddr: "0xf4e77E5Da47AC3125140c470c71cBca77B5c638c",
|
hermezContractAddr: "0xf4e77E5Da47AC3125140c470c71cBca77B5c638c",
|
||||||
toHashExpected: "19457468657265756d205369676e6564204d6573736167653a0a3132304920617574686f72697a65207468697320626162796a75626a7562206b657920666f72206865726d657a20726f6c6c7570206163636f756e74206372656174696f6e22870c1bcc451396202d62f566026eab8e438c6c91decf8ddf63a6c162619b527a69f4e77e5da47ac3125140c470c71cbca77b5c638c",
|
toHashExpected: "190167617949b934d7e01add4009cd3d47415a26727b7d6288e5dce33fb3721d5a1a9ce511b19b694c9aaf8183f4987ed752f24884c54c003d11daa2e98c7547a79e",
|
||||||
hashExpected: "4f6ead01278ba4597d4720e37482f585a713497cea994a95209f4c57a963b4a7",
|
hashExpected: "157b570c597e615b8356ce008ac39f43bc9b6d50080bc07d968031b9378acbbb",
|
||||||
sigExpected: "43b5818802a137a72a190c1d8d767ca507f7a4804b1b69b5e055abf31f4f2b476c80bb1ba63260d95610f6f831420d32130e7f22fec5d76e16644ddfcedd0d441c",
|
sigExpected: "a0766181102428b5672e523dc4b905c10ddf025c10dbd0b3534ef864632a14652737610041c670b302fc7dca28edd5d6eac42b72d69ce58da8ce21287b244e381b",
|
||||||
}
|
}
|
||||||
tvs = append(tvs, tv0)
|
tvs = append(tvs, tv0)
|
||||||
tvs = append(tvs, tv1)
|
tvs = append(tvs, tv1)
|
||||||
@@ -122,10 +122,10 @@ func TestAccountCreationAuthJSComp(t *testing.T) {
|
|||||||
BJJ: pkComp,
|
BJJ: pkComp,
|
||||||
}
|
}
|
||||||
|
|
||||||
toHash := a.toHash(chainID, hermezContractAddr)
|
toHash, err := a.toHash(chainID, hermezContractAddr)
|
||||||
|
require.NoError(t, err)
|
||||||
assert.Equal(t, tv.toHashExpected,
|
assert.Equal(t, tv.toHashExpected,
|
||||||
hex.EncodeToString(toHash))
|
hex.EncodeToString(toHash))
|
||||||
assert.Equal(t, 120+len(EthMsgPrefix)+len([]byte("120")), len(toHash))
|
|
||||||
|
|
||||||
msg, err := a.HashToSign(chainID, hermezContractAddr)
|
msg, err := a.HashToSign(chainID, hermezContractAddr)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|||||||
Reference in New Issue
Block a user