Подпишите сообщение с помощью web3 и проверьте с помощью openzeppelin-solidity ECDSA.sol

Я пытаюсь получить небольшой пример работы с ECDSA.sol здесь: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/cryptography/ECDSA.sol

Этот контракт:

  1. Сгенерируйте случайный (ish) bytes32 (заглушка для будущего дайджеста сообщения).
  2. Превратите его в EthSignedHash с помощьюkeccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
  3. Используйте ecrecover, чтобы выяснить, кто подписал сообщение.
pragma solidity 0.5.8;

import "../../node_modules/openzeppelin-solidity/contracts/cryptography/ECDSA.sol";

contract Sigs {

    using ECDSA for bytes32;

    function rndHash() public view returns(bytes32) {
        return keccak256(abi.encodePacked(block.number));
    }

    function ethSignedHash(bytes32 messageHash) public pure returns(bytes32) {
        return messageHash.toEthSignedMessageHash();
    }

    function recover(bytes32 hash, bytes memory signature) public pure returns(address) {
        return hash.recover(signature);
    }
}

На стороне клиента:

  1. Создайте случайное сообщение.
  2. Сделайте ethHash сообщения.
  3. Подписать его.
  4. Отправьте ethHash и подпись в ecRecover и получите адрес подписавшего.

Я не уверен, что мне не хватает. Я думаю, что исходный хэш сообщения должен быть подписан, а EIP-712 выполняет «подписание Ethereum», поэтому я должен отправить «хэш Ethereum» в ecrecover (как реализовано в ECDSA.sol). В любом случае, никакая комбинация не приносит никакой радости.

var Sigs = artifacts.require("./Junk/Sigs");

contract("Sigs", accounts => {

  var signer;

  beforeEach(async () => {
    signer = accounts[0];
    sigs = await Sigs.new({from: signer}); 
  });

  it("should recover signer address.", async () =>  {

    console.log("SIGNER: ", signer);

    var random  = await sigs.rndHash({from: signer});
    var ethHash = await sigs.ethSignedHash(random);

    // four possible combinations tried for the next step :/
    var signature = await web3.eth.sign(random, signer);    // sign the random hash or the ethHash
    var recovered = await sigs.recover(ethHash, signature); // recover from the random hash or the ethHash

    console.log("random1: ", random);
    console.log("signature: ", signature);
    console.log("recovered: ", recovered);

    assert.strictEqual(recovered, signer, "The recovered signature does not match the signer.");

  });    
});

Буду очень признателен, если кто-нибудь сможет меня развести.

Truffle v5.0.41 (core: 5.0.41)
Solidity - 0.5.8 (solc-js)
Node v8.10.0
Web3.js v1.2.1

Спасибо!

Обновлять

Для всех, кто сталкивается с этим, это пересмотренный, проходной тест.

const Sigs = artifacts.require("./Junk/Sigs");
const EthCrypto = require("eth-crypto");

contract("Sigs", accounts => {

  var signer;

  beforeEach(async () => {
    signer = accounts[0];
    sigs = await Sigs.new({from: signer}); 
  });

  it("should recover signer address.", async () =>  {

    console.log("SIGNER: ", signer);

    var message = "0x1234";
    console.log("message: ", message);
    var msgHash    = await sigs.messageHash(message);
    var ethHash = await sigs.ethSignedHash(msgHash);

    var signature = await web3.eth.sign(msgHash, signer);    // sign the mesage hash
    signature = signature.substr(0, 130) + (signature.substr(130) == "00" ? "1b" : "1c"); // v: 0,1 => 27,28
    var recovered = await sigs.recover(ethHash, signature); // recover from the ethHash

    console.log("msgHash: ", msgHash);
    console.log("ethHash: ", ethHash);
    console.log("signature: ", signature);
    console.log("recovered: ", recovered);

    assert.strictEqual(recovered, signer, "The recovered signature does not match the signer.");

  });    
});
Пробовали ли вы опубликовать вопрос (проблему) на их GitHub или в сообществе OpenZeppelin ? Обычно они очень отзывчивы (намного больше, чем это сообщество) и очень полезны.
Роб, openzeppelin-solidityсейчас @openzeppelin/contracts. Кроме того, в таких средах, как трюфель, вы можете записать свой импорт как: import "@openzeppelin/contracts/cryptography/ECDSA.sol";вам не нужно указыватьnode_modules
Спасибо @goodvibration, я менеджер сообщества OpenZeppelin. Я регистрируюсь здесь, но большую часть времени провожу на форуме сообщества OpenZeppelin.

Ответы (2)

Проблема в том, что eth.signвозвращает подпись, где v0 или 1, и ecrecoverожидается, что она будет 27 или 28.

Примечание в документации для web3 v0.20 ясно:

Обратите внимание, что если вы используете ecrecover, vбудет либо , "00"либо "01". В результате, чтобы использовать это значение, вам придется преобразовать его в целое число, а затем добавить 27. Это приведет либо к a, 27либо к 28.

Вы должны сделать что-то вроде этого

var signature = await web3.eth.sign(random, signer);    // sign the random hash or the ethHash
signature = signature.substr(0, 130) + (signature.substr(130) == "00" ? "1b" : "1c");
var recovered = await sigs.recover(ethHash, signature); // recover from the random hash or the ethHash
Об этой проблеме также сообщается в пакете 'ethereumjs-util'/функции 'fromRpcSig' , где в документации указано, что "все из-за ошибки в geth: github.com/ethereum/go-ethereum/issues/2053 " (у меня только что получилось столкнуться с этим пару дней назад).
Как видите, функция добавляет 27 к последнему байту в 65-байтовом буфере (последние два символа в 130-символьной строке).
Спасибо, оба. Я не могу подойти к компьютеру сегодня, но я с нетерпением жду возможности попробовать это.
Не мог отпустить, лол. Работает как шарм. Большое спасибо.

Роб, я вижу, что ты уже решил (и это здорово).

Для будущих читателей:

Дополнительные сведения о контрактах OpenZeppelin можно найти в документации, в данном случае в разделе «Криптография»: https://docs.openzeppelin.com/contracts/2.x/utilities#cryptography .

Тесты для контрактов могут быть полезны для просмотра, в данном случае ECDSA.test.js: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/test/cryptography/ECDSA.test.js .

На форуме есть руководство по подписанию: https://forum.openzeppelin.com/t/sign-it-like-you-mean-it-creating-and-verifying-ethereum-signatures/697 .

Если у вас есть вопросы по использованию OpenZeppelin, вы также можете задать их на форуме сообщества: https://forum.openzeppelin.com/

Раскрытие информации: я менеджер сообщества в OpenZeppelin