Holen Sie sich den öffentlichen Schlüssel eines beliebigen Ethereum-Kontos

Kann ich den öffentlichen Schlüssel eines Ethereum-Kontos irgendwie bekommen, wenn ich nur die entsprechende Ethereum-Adresse (z. B. 0x54dbb737eac5007103e729e9ab7ce64a6850a310) kenne?

Antworten (5)

Dies ist nur möglich, wenn eine Transaktion vom Konto gesendet wurde. Wenn Sie eine tx senden, signieren Sie die Transaktion und sie enthält diese v rund sWerte. Sie analysieren diese aus dem signierten TX und übergeben diese v rund sWerte und den Hash der Transaktion zurück an eine Funktion, die den öffentlichen Schlüssel ausspuckt. Auf diese Weise erhalten Sie eigentlich die Absenderadresse einer Transaktion.

Sie können dies selbst mit einem Tool wie ethereumjs-utils tun :

/**
 * ECDSA public key recovery from signature
 * @param {Buffer} msgHash
 * @param {Number} v
 * @param {Buffer} r
 * @param {Buffer} s
 * @return {Buffer} publicKey
 */
exports.ecrecover = function (msgHash, v, r, s) {
  var signature = Buffer.concat([exports.setLength(r, 32), exports.setLength(s, 32)], 64)
  var recovery = v - 27
  if (recovery !== 0 && recovery !== 1) {
    throw new Error('Invalid signature v value')
  }
  var senderPubKey = secp256k1.recover(msgHash, signature, recovery)
  return secp256k1.publicKeyConvert(senderPubKey, false).slice(1)
}

Als weiteres reales Szenario verwendet ethereumjs-tx diese Funktion, um die Signatur zu überprüfen:

/**
* Determines if the signature is valid
* @return {Boolean}
*/
verifySignature () {
  const msgHash = this.hash(false)
  // All transaction signatures whose s-value is greater than secp256k1n/2 are considered invalid.
  if (this._homestead && new BN(this.s).cmp(N_DIV_2) === 1) {
    return false
  }

  try {
    let v = ethUtil.bufferToInt(this.v)
    if (this._chainId > 0) {
      v -= this._chainId * 2 + 8
    }
    this._senderPubKey = ethUtil.ecrecover(msgHash, v, this.r, this.s)
  } catch (e) {
    return false
  }

  return !!this._senderPubKey
}

Weitere Informationen zu v rund s:

v, r und s sind Parameter, die aus der Signatur geparst werden können. Hier ist ein gutes Beispiel aus der utils-Bibliothek von ethereumjs:

 var sig = secp256k1.sign(msgHash, privateKey)
  var ret = {}
  ret.r = sig.signature.slice(0, 32)
  ret.s = sig.signature.slice(32, 64)
  ret.v = sig.recovery + 27

Beachten Sie, wie Sie jeden Wert einer bestimmten Signatur parsen können.

Quelle

Sehr hilfreich. Ich musste nachsehen, warum ein "zusätzlicher" Aufruf secp256k1.publicKeyConverterforderlich ist, und der Grund scheint darin zu bestehen, den dekomprimierten öffentlichen Schlüssel zu erhalten, da secp256k1.recoverein komprimierter öffentlicher Schlüssel zurückgegeben wird.
Wofür stehen die Werte s, r, v?
Was ist der msgHash? Ist das der Hash der als Teil der Transaktion gesendeten Nachricht oder der eigentliche Hash der Transaktion selbst?
Wie werden Sie v, r analysieren und wenn Sie den privaten Schlüssel des Endbenutzers nicht haben?

Es ist jetzt möglich, den öffentlichen Schlüssel aus der Ethereum-Transaktion ohne Codierung wiederherzustellen:

  1. Öffnen Sie die Transaktion in Etherscan.io
  2. Klicken Sie auf die vertikalen Auslassungspunkte in der oberen rechten Ecke
  3. Klicken Sie im Popup-Menü auf „Get Raw Tx Hex“.
  4. Sie werden eine Rohtransaktion in Hex sehen, kopieren Sie sie
  5. Öffnen Sie das Tool „Adresse wiederherstellen“ aus dem ABDK Toolkit
  6. Wählen Sie das Optionsfeld "Transaktion".
  7. Fügen Sie die Rohtransaktion in das Feld "Nachricht" ein
  8. Siehe den öffentlichen Schlüssel im Textbogen unten
Das funktioniert sehr gut. Allerdings konnte ich den Quellcode dafür nirgendwo finden, obwohl sie sagen, dass dies Open Source ist.
Das Beste, was ich tun könnte, ist hier eine WARC-Datei für die Offline-Nutzung zu erstellen .
Wie hilft das, nur die Adresse zu kennen?

Ich denke nicht, dass dies möglich ist, da Sie Informationen verlieren, wenn Sie vom öffentlichen Schlüssel zur Adresse wechseln:

  1. Beginnen Sie mit dem öffentlichen Schlüssel (64 Bytes)
  2. Nehmen Sie den Keccak-256-Hash des öffentlichen Schlüssels. Sie sollten jetzt eine Zeichenfolge mit 32 Bytes haben. (Hinweis: SHA3-256 wurde schließlich zum Standard, aber Ethereum verwendet Keccak)
  3. Nehmen Sie die letzten 20 Bytes dieses öffentlichen Schlüssels (Keccak-256). Oder mit anderen Worten, die ersten 12 Bytes löschen . Diese 20 Bytes sind die Adresse oder 40 Zeichen. Wenn 0x vorangestellt wird, wird es 42 Zeichen lang.

Wie werden Ethereum-Adressen generiert?

Ich dachte, dass alle Transaktionen von einer Ethereum-Adresse mit dem privaten Schlüssel des Kontos signiert und mit dem öffentlichen Schlüssel des Kontos in der Kette validiert werden. Wenn dies der Fall ist, sollten die öffentlichen Schlüssel aller Konten für alle Knoten in einem Netzwerk verfügbar sein. Liege ich falsch?
@EdwardRuchevits Die Adresse in der Frage hat keine Transaktion signiert, daher ist es nicht möglich, den öffentlichen Schlüssel zu erhalten. Wenn es eine Signatur gibt, kann dies hilfreich sein. crypto.stackexchange.com/questions/18105/… und stackoverflow.com/questions/19665491/… Vielleicht können einige Leute hier auch großartige Antworten hinzufügen.
Eine nette Eigenschaft von Adressen ist, dass, da der öffentliche Schlüssel nicht bekannt ist, bis das Konto verwendet wird, das Konto vor Quantenangriffen sicher ist, bis es ausgegeben wird
@TjadenHess Sind Quantenangriffe heutzutage ein Thema?

Mit dem @tayvano-Hinweis können Sie dies wie folgt tun:

  1. Gehen Sie zu etherscan und prüfen Sie, ob es ausgehende Transaktionen gibt: https://etherscan.io/address/0x54dbb737eac5007103e729e9ab7ce64a6850a310
  2. Holen Sie sich Hash von einem von ihnen, z0xa8206c5fcfb6a2527fb8540ab543b4701f4c86d1c21862ad89fa220c84bad260
  3. Verwenden Sie ipython mit web3
In [1]: import web3
w3 = web3.Web3(web3.HTTPProvider('https://geth.golem.network:55555'))
tx = w3.eth.getTransaction(0xa8206c5fcfb6a2527fb8540ab543b4701f4c86d1c21862ad89fa220c84bad260)
tx.hash
Out[1]: HexBytes('0xa8206c5fcfb6a2527fb8540ab543b4701f4c86d1c21862ad89fa220c84bad260')

In [2]: from eth_account.internal.signing import extract_chain_id, to_standard_v
s = w3.eth.account._keys.Signature(vrs=(
    to_standard_v(extract_chain_id(tx.v)[1]),
    w3.toInt(tx.r),
    w3.toInt(tx.s)
))

from eth_account.internal.transactions import ALLOWED_TRANSACTION_KEYS
tt = {k:tx[k] for k in ALLOWED_TRANSACTION_KEYS - {'chainId', 'data'}}
tt['data']=tx.input
tt['chainId']=extract_chain_id(tx.v)[0]

from eth_account.internal.transactions import serializable_unsigned_transaction_from_dict
ut = serializable_unsigned_transaction_from_dict(tt)
s.recover_public_key_from_msg_hash(ut.hash())
Out[2]: '0x9678ad0aa2fbd7f212239e21ed1472e84ca558fecf70a54bbf7901d89c306191c52e7f10012960085ecdbbeeb22e63a8e86b58f788990b4db53cdf4e0a55ac1e'

In [3]: s.recover_public_key_from_msg_hash(ut.hash()).to_checksum_address()
Out[3]: '0x54Dbb737EaC5007103E729E9aB7ce64a6850a310'

In [4]: t['from']
Out[4]: '0x54Dbb737EaC5007103E729E9aB7ce64a6850a310'
Dies funktioniert nicht für Vertragsbereitstellungstransaktionen. Und für die neueste Version müssen Sie den Code anpassenfrom eth_account._utils.signing import extract_chain_id, to_standard_v, serializable_unsigned_transaction_from_dict from eth_account._utils.transactions import ALLOWED_TRANSACTION_KEYS

Lösung in Java. Vielleicht geht es einfacher, aber es funktioniert.

Utility-Klassen kommen von web3j.crypto.

    BigInteger v = new BigInteger("26", 16);
    BigInteger r = new BigInteger("5fd883bb01a10915ebc06621b925bd6d624cb6768976b73c0d468b31f657d15b", 16);
    BigInteger s = new BigInteger("121d855c539a23aadf6f06ac21165db1ad5efd261842e82a719c9863ca4ac04c", 16);
    BigInteger chainId = new BigInteger("1", 16);
    v = v.subtract(chainId.multiply(BigInteger.valueOf(2)).add(BigInteger.valueOf(8)));
    Sign.SignatureData signatureData = new Sign.SignatureData(v.toByteArray(), r.toByteArray(), s.toByteArray());
    byte[] raw = DatatypeConverter.parseHexBinary("f86b0b85250523760082520894eafaf9bb8f35235d0df61275e86fd65d9ef2c3f9870aaa0065c66b8b8026a05fd883bb01a10915ebc06621b925bd6d624cb6768976b73c0d468b31f657d15ba0121d855c539a23aadf6f06ac21165db1ad5efd261842e82a719c9863ca4ac04c");

    RawTransaction decoded = TransactionDecoder.decode(DatatypeConverter.printHexBinary(raw));
    byte[] encoded = TransactionEncoder.encode(decoded, chainId.longValue());
    byte[] rawTxHash = Hash.sha3(encoded);

    System.out.println("Raw tx hash:                    " + DatatypeConverter.printHexBinary(rawTxHash));
    System.out.println("Pub key from raw tx hash :      " + signedMessageHashToKey(rawTxHash, signatureData).toString(16));