|
|
@ -1,21 +1,25 @@ |
|
|
|
package common |
|
|
|
|
|
|
|
import ( |
|
|
|
"encoding/binary" |
|
|
|
"strconv" |
|
|
|
"time" |
|
|
|
|
|
|
|
ethCommon "github.com/ethereum/go-ethereum/common" |
|
|
|
ethMath "github.com/ethereum/go-ethereum/common/math" |
|
|
|
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" |
|
|
|
) |
|
|
|
|
|
|
|
// AccountCreationAuthMsg is the message that is signed to authorize a Hermez
|
|
|
|
// 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
|
|
|
|
const EthMsgPrefix = "\x19Ethereum Signed Message:\n" |
|
|
|
// EIP712Version is the used version of the EIP-712
|
|
|
|
const EIP712Version = "1" |
|
|
|
|
|
|
|
// EIP712Provider defines the Provider for the EIP-712
|
|
|
|
const EIP712Provider = "Hermez Network" |
|
|
|
|
|
|
|
var ( |
|
|
|
// EmptyEthSignature is an ethereum signature of all zeroes
|
|
|
@ -31,27 +35,64 @@ type AccountCreationAuth struct { |
|
|
|
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, |
|
|
|
hermezContractAddr ethCommon.Address) []byte { |
|
|
|
var chainIDBytes [2]byte |
|
|
|
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)) |
|
|
|
return append([]byte(ethPrefix), b...) |
|
|
|
hermezContractAddr ethCommon.Address) ([]byte, error) { |
|
|
|
chainIDFormatted := ethMath.NewHexOrDecimal256(int64(chainID)) |
|
|
|
|
|
|
|
signerData := ethSigner.TypedData{ |
|
|
|
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
|
|
|
|
// the account creation
|
|
|
|
// the account creation, which follows the EIP-712 encoding
|
|
|
|
func (a *AccountCreationAuth) HashToSign(chainID uint16, |
|
|
|
hermezContractAddr ethCommon.Address) ([]byte, error) { |
|
|
|
b := a.toHash(chainID, hermezContractAddr) |
|
|
|
return ethCrypto.Keccak256Hash(b).Bytes(), nil |
|
|
|
b, err := a.toHash(chainID, hermezContractAddr) |
|
|
|
if err != nil { |
|
|
|
return nil, tracerr.Wrap(err) |
|
|
|
} |
|
|
|
return ethCrypto.Keccak256(b), nil |
|
|
|
} |
|
|
|
|
|
|
|
// 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
|
|
|
|
// `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
|
|
|
|
// 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), |
|
|
|
chainID uint16, hermezContractAddr ethCommon.Address) error { |
|
|
|
hash, err := a.HashToSign(chainID, hermezContractAddr) |
|
|
|
if err != nil { |
|
|
|
return err |
|
|
|
return tracerr.Wrap(err) |
|
|
|
} |
|
|
|
sig, err := signHash(hash) |
|
|
|
if err != nil { |
|
|
|
return err |
|
|
|
return tracerr.Wrap(err) |
|
|
|
} |
|
|
|
sig[64] += 27 |
|
|
|
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
|
|
|
|
// chainID and hermezContractAddress passed by parameter
|
|
|
|
// chainID and hermezContractAddress passed by parameter. VerifySignature
|
|
|
|
// follows the EIP-712 encoding.
|
|
|
|
func (a *AccountCreationAuth) VerifySignature(chainID uint16, |
|
|
|
hermezContractAddr ethCommon.Address) bool { |
|
|
|
// Calculate hash to be signed
|
|
|
|