浏览代码

Implement `0x00` version of EIP-191 in ECDSA Library (#4063)

Yamen Merhi 2 年之前
父节点
当前提交
53235263a3
共有 4 个文件被更改,包括 41 次插入1 次删除
  1. 5 0
      .changeset/small-cars-appear.md
  2. 10 0
      contracts/utils/cryptography/ECDSA.sol
  3. 16 0
      test/helpers/sign.js
  4. 10 1
      test/utils/cryptography/ECDSA.test.js

+ 5 - 0
.changeset/small-cars-appear.md

@@ -0,0 +1,5 @@
+---
+'openzeppelin-solidity': patch
+---
+
+`ECDSA`: Add a function `toDataWithIntendedValidatorHash` that encodes data with version 0x00 following EIP-191.

+ 10 - 0
contracts/utils/cryptography/ECDSA.sol

@@ -204,4 +204,14 @@ library ECDSA {
             data := keccak256(ptr, 0x42)
         }
     }
+
+    /**
+     * @dev Returns an Ethereum Signed Data with intended validator, created from a
+     * `validator` and `data` according to the version 0 of EIP-191.
+     *
+     * See {recover}.
+     */
+    function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
+        return keccak256(abi.encodePacked("\x19\x00", validator, data));
+    }
 }

+ 16 - 0
test/helpers/sign.js

@@ -4,6 +4,21 @@ function toEthSignedMessageHash(messageHex) {
   return web3.utils.sha3(Buffer.concat([prefix, messageBuffer]));
 }
 
+/**
+ * Create a signed data with intended validator according to the version 0 of EIP-191
+ * @param validatorAddress The address of the validator
+ * @param dataHex The data to be concatenated with the prefix and signed
+ */
+function toDataWithIntendedValidatorHash(validatorAddress, dataHex) {
+  const validatorBuffer = Buffer.from(web3.utils.hexToBytes(validatorAddress));
+  const dataBuffer = Buffer.from(web3.utils.hexToBytes(dataHex));
+  const preambleBuffer = Buffer.from('\x19');
+  const versionBuffer = Buffer.from('\x00');
+  const ethMessage = Buffer.concat([preambleBuffer, versionBuffer, validatorBuffer, dataBuffer]);
+
+  return web3.utils.sha3(ethMessage);
+}
+
 /**
  * Create a signer between a contract and a signer for a voucher of method, args, and redeemer
  * Note that `method` is the web3 method, not the truffle-contract method
@@ -43,5 +58,6 @@ const getSignFor =
 
 module.exports = {
   toEthSignedMessageHash,
+  toDataWithIntendedValidatorHash,
   getSignFor,
 };

+ 10 - 1
test/utils/cryptography/ECDSA.test.js

@@ -1,5 +1,5 @@
 const { expectRevert } = require('@openzeppelin/test-helpers');
-const { toEthSignedMessageHash } = require('../../helpers/sign');
+const { toEthSignedMessageHash, toDataWithIntendedValidatorHash } = require('../../helpers/sign');
 
 const { expect } = require('chai');
 
@@ -8,6 +8,7 @@ const ECDSA = artifacts.require('$ECDSA');
 const TEST_MESSAGE = web3.utils.sha3('OpenZeppelin');
 const WRONG_MESSAGE = web3.utils.sha3('Nope');
 const NON_HASH_MESSAGE = '0x' + Buffer.from('abcd').toString('hex');
+const RANDOM_ADDRESS = web3.utils.toChecksumAddress(web3.utils.randomHex(20));
 
 function to2098Format(signature) {
   const long = web3.utils.hexToBytes(signature);
@@ -248,4 +249,12 @@ contract('ECDSA', function (accounts) {
       );
     });
   });
+
+  context('toDataWithIntendedValidatorHash', function () {
+    it('returns the hash correctly', async function () {
+      expect(
+        await this.ecdsa.methods['$toDataWithIntendedValidatorHash(address,bytes)'](RANDOM_ADDRESS, NON_HASH_MESSAGE),
+      ).to.equal(toDataWithIntendedValidatorHash(RANDOM_ADDRESS, NON_HASH_MESSAGE));
+    });
+  });
 });