You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

78 lines
2.5 KiB

  1. package common
  2. import (
  3. "encoding/binary"
  4. "strconv"
  5. "time"
  6. ethCommon "github.com/ethereum/go-ethereum/common"
  7. ethCrypto "github.com/ethereum/go-ethereum/crypto"
  8. "github.com/iden3/go-iden3-crypto/babyjub"
  9. )
  10. // AccountCreationAuthMsg is the message that is signed to authorize a Hermez
  11. // account creation
  12. const AccountCreationAuthMsg = "I authorize this babyjubjub key for hermez rollup account creation"
  13. // EthMsgPrefix is the prefix for message signing at the Ethereum ecosystem
  14. const EthMsgPrefix = "\x19Ethereum Signed Message:\n"
  15. // AccountCreationAuth authorizations sent by users to the L2DB, to be used for
  16. // account creations when necessary
  17. type AccountCreationAuth struct {
  18. EthAddr ethCommon.Address `meddler:"eth_addr"`
  19. BJJ babyjub.PublicKeyComp `meddler:"bjj"`
  20. Signature []byte `meddler:"signature"`
  21. Timestamp time.Time `meddler:"timestamp,utctime"`
  22. }
  23. func (a *AccountCreationAuth) toHash(chainID uint16,
  24. hermezContractAddr ethCommon.Address) []byte {
  25. var chainIDBytes [2]byte
  26. binary.BigEndian.PutUint16(chainIDBytes[:], chainID)
  27. // [EthPrefix | AccountCreationAuthMsg | compressedBJJ | chainID | hermezContractAddr]
  28. var b []byte
  29. b = append(b, []byte(AccountCreationAuthMsg)...)
  30. b = append(b, SwapEndianness(a.BJJ[:])...) // for js implementation compatibility
  31. b = append(b, chainIDBytes[:]...)
  32. b = append(b, hermezContractAddr[:]...)
  33. ethPrefix := EthMsgPrefix + strconv.Itoa(len(b))
  34. return append([]byte(ethPrefix), b...)
  35. }
  36. // HashToSign returns the hash to be signed by the Etherum address to authorize
  37. // the account creation
  38. func (a *AccountCreationAuth) HashToSign(chainID uint16,
  39. hermezContractAddr ethCommon.Address) ([]byte, error) {
  40. b := a.toHash(chainID, hermezContractAddr)
  41. return ethCrypto.Keccak256Hash(b).Bytes(), nil
  42. }
  43. // VerifySignature ensures that the Signature is done with the EthAddr, for the
  44. // chainID and hermezContractAddress passed by parameter
  45. func (a *AccountCreationAuth) VerifySignature(chainID uint16,
  46. hermezContractAddr ethCommon.Address) bool {
  47. // Calculate hash to be signed
  48. msg, err := a.HashToSign(chainID, hermezContractAddr)
  49. if err != nil {
  50. return false
  51. }
  52. var sig [65]byte
  53. copy(sig[:], a.Signature[:])
  54. sig[64] -= 27
  55. // Get public key from Signature
  56. pubKBytes, err := ethCrypto.Ecrecover(msg, sig[:])
  57. if err != nil {
  58. return false
  59. }
  60. pubK, err := ethCrypto.UnmarshalPubkey(pubKBytes)
  61. if err != nil {
  62. return false
  63. }
  64. // Get addr from pubK
  65. addr := ethCrypto.PubkeyToAddress(*pubK)
  66. return addr == a.EthAddr
  67. }