Nachricht mit web3 signieren und mit openzeppelin-solidity ECDSA.sol verifizieren

Ich versuche hier ein kleines Beispiel für die Arbeit mit ECDSA.sol zu bekommen: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/cryptography/ECDSA.sol

Dieser Vertrag:

  1. Generieren Sie zufällige (ish) Bytes32 (Stub für einen zukünftigen Nachrichten-Digest).
  2. Morphen Sie es in einen EthSignedHash mitkeccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
  3. Verwenden Sie ecrecover, um herauszufinden, wer eine Nachricht signiert hat.
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);
    }
}

Auf der Client-Seite:

  1. Zaubere eine zufällige (ish) Nachricht herauf.
  2. Erstellen Sie einen ethHash der Nachricht.
  3. Unterschreib es.
  4. Senden Sie ethHash und die Signatur an ecRecover und erhalten Sie die Unterzeichneradresse.

Ich bin mir nicht sicher, was mir fehlt. Ich denke , der ursprüngliche Nachrichten-Hash sollte signiert werden und EIP-712 führt die "Ethereum-Signierung" durch, also sollte ich den "Ethereum-Hash" an ecrecover senden (wie in ECDSA.sol implementiert). Jedenfalls bringt keine Kombination Freude.

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.");

  });    
});

Ich wäre sehr dankbar, wenn mich jemand aufklären könnte.

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

Danke!

Aktualisieren

Für alle anderen, denen das passiert, ist dies der überarbeitete, bestandene Test.

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.");

  });    
});
Haben Sie versucht, eine Frage (ein Problem) auf ihrem GitHub oder in der OpenZeppelin Community zu posten ? Sie sind normalerweise sehr reaktionsschnell (viel mehr als diese Community) und sehr hilfreich.
Rob, openzeppelin-solidityist jetzt @openzeppelin/contracts. Auch in Umgebungen wie Truffle können Sie Ihren Import schreiben als: import "@openzeppelin/contracts/cryptography/ECDSA.sol";Sie müssen nicht angebennode_modules
Danke @goodvibration, ich bin der Community Manager bei OpenZeppelin. Ich melde mich zwar hier an, verbringe aber die meiste Zeit im OpenZeppelin Community Forum

Antworten (2)

Das Problem ist, dass eth.signeine Signatur zurückgegeben wird, bei der v0 oder 1 ist, und ecrecovererwartet wird, dass sie 27 oder 28 ist.

Ein Hinweis in der Dokumentation zu web3 v0.20 ist klar:

Beachten Sie, dass wenn Sie verwenden ecrecover, entweder oder vsein wird . Um diesen Wert zu verwenden, müssen Sie ihn daher in eine ganze Zahl parsen und dann hinzufügen . Dies ergibt entweder ein oder ein ."00""01"272728

Sie müssen so etwas tun

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
Dieses Problem wird auch im Paket 'ethereumjs-util' / function 'fromRpcSig' gemeldet , wo die Dokumentation besagt, dass "alles wegen eines Fehlers in geth: github.com/ethereum/go-ethereum/issues/2053 " (ich bin gerade passiert um vor ein paar Tagen selbst darauf zu stoßen).
Wie Sie sehen können, fügt die Funktion 27 zum letzten Byte im 65-Byte-Puffer hinzu (die letzten beiden Zeichen in der 130-Zeichen-Zeichenfolge).
Danke, beide. Ich kann heute nicht in die Nähe eines Computers kommen, aber ich freue mich darauf, dies zu versuchen.
Konnte es nicht lassen, lol. Klappt wunderbar. Vielen Dank.

Rob, wie ich sehe, hast du bereits eine Lösung gefunden (was großartig ist).

Für zukünftige Leser:

Weitere Informationen zu OpenZeppelin-Verträgen finden Sie in der Dokumentation, in diesem Fall im Abschnitt Kryptographie: https://docs.openzeppelin.com/contracts/2.x/utilities#cryptography

Die Tests für die Verträge können hilfreich sein, in diesem Fall ECDSA.test.js: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/test/cryptography/ECDSA.test.js

Im Forum gibt es ein Tutorial zum Signieren: https://forum.openzeppelin.com/t/sign-it-like-you-mean-it-creating-and-verifying-ethereum-signatures/697

Wenn Sie Fragen zur Verwendung von OpenZeppelin haben, können Sie diese auch im Community-Forum stellen: https://forum.openzeppelin.com/

Offenlegung: Ich bin der Community Manager bei OpenZeppelin