Ich habe eine Frage zur Verwendung von Schlüsseln in Ethereum zum Signieren von Anfragen/Daten AUSSERHALB von Ethereum.
Nehmen wir an, ich habe einen regulären Ethereum-EOA mit einer Adresse und einem Schlüsselpaar. Ich möchte nun eine Information an einen Dritten (Off-Chain) übertragen lassen und diesem Dritten die Überprüfung ermöglichen, dass diese Information von mir, also dem Inhaber des betreffenden EOA, stammt. Ansatz: Signieren Sie die Informationen digital mit meinem privaten Schlüssel, der mit meinem EOA verknüpft ist.
Nun stellt sich die Frage, wie der Dritte die Signatur verifiziert. Was er hat, ist die Unterschrift, die Daten und (nehmen wir an, wir haben dies angegeben) die Adresse meines EOA.
Damit er die Signatur verifizieren kann, benötigt er den öffentlichen Schlüssel meines EOA. Um ihm das zukommen zu lassen, sehe ich zwei Möglichkeiten:
Gibt es eine dritte, noch bessere Option?
Erstens ist es nicht möglich, den öffentlichen Schlüssel nur von einer Adresse abzuleiten. Die Adresse ist Teil des Keccak256-Hashes des öffentlichen Schlüssels, und Hash-Funktionen sind Einwegfunktionen. Sie können eine Adresse aus einem öffentlichen Schlüssel berechnen, indem Sie die letzten 40 Bytes des Keccak256-Hashes nehmen.
Sie benötigen den öffentlichen Schlüssel jedoch nicht, um eine Signatur zu überprüfen. Angenommen, Sie verwenden ECDSA-Signaturen (Standard in Ethereum), können Sie den öffentlichen Schlüssel aus einer Signatur und Nachricht wiederherstellen. Wenn Sie beispielsweise eine Nachricht mit MyCrypto signieren, sieht die „signierte Nachricht“ folgendermaßen aus:
{
"address": "0xa6ad0945cd3c5539d92d49b140842a0673e17041",
"msg": "Hello, world!",
"sig": "0x1e15325a942ae03788b63902ccc4703a65993dc9c692cf14d2bf16d62407da6824f045ebbbc0eb8423934a87c95872703fcec742ea03ded4d88aa5e219d9494c1c",
"version": "2"
}
Dann können Sie den öffentlichen Schlüssel mit der Wiederherstellungsfunktion von ECDSA ( ecrecover
in Solidity) berechnen, indem Sie den öffentlichen Schlüssel der Nachricht und Signatur berechnen, den öffentlichen Schlüssel mit Keccak256 hashen und die letzten 40 Bytes nehmen, um die Adresse zu erhalten. Die Signatur ist gültig, wenn die wiederhergestellte Adresse mit der in der signierten Nachricht angegebenen übereinstimmt.
Sie sollten einige spezifische Informationen in die Nachricht aufnehmen (z. B. „Nachricht von Person am Datum signiert“), um sicherzustellen, dass die Nachricht tatsächlich von der Person signiert wurde, die behauptet, sie signiert zu haben (und um mögliche Replay-Angriffe zu verhindern).
Mit Java können Sie web3j verwenden Sign.recoverFromSignature
. Leider scheint dies nicht dokumentiert zu sein, aber der Quellcode sollte Ihnen den Einstieg erleichtern.
Ich habe einen ausführlichen Artikel über ECDSA-Signaturen auf Ethereum geschrieben, den Sie hier finden können , wenn Sie daran interessiert sind.
Diese Bibliothek hilft Ihnen, den öffentlichen Schlüssel aus der ECDSA-signierten Nachricht https://github.com/0xcyphered/secp256k1-solidity wiederherzustellen
Beispiel:
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;
import "@0xcyphered/secp256k1-solidity/contracts/SECP256K1.sol";
contract Example {
function recoverPersonalSignPublicKey(
bytes32 message,
uint8 v,
bytes32 r,
bytes32 s
) public pure returns (bytes memory) {
string memory header = '\x19Ethereum Signed Message:\n32';
bytes32 _message = keccak256(abi.encodePacked(header, message));
(uint256 x, uint256 y) = SECP256K1.recover(uint256(_message), v - 27, uint256(r), uint256(s));
return abi.encodePacked(x, y);
}
}