js-peer-id
js-peer-id copied to clipboard
Import metamask web3j keys to Libp2p
Hello,
How can I create a libp2p key from the metamask ethereum's public key I tried:
const web3 = window.web3
const accounts = await web3.eth.getAccounts()
this.setState({ account: accounts[0] })
console.log(accounts)
let temp = await PeerId.createFromPubKey(accounts[0])
I am getting error in the last line.
Help please.
The key is 0xe4054F19da776c7a342Fc9DBDDd17000d8cE061F
- Public key for ethereum..
Do you know what is the type of the key? From what I can understand, it does not seem like any of the ones we support:
- RSA
- Ed25519
- Secp256k1
- ECDSA
Sorry, @vasco-santos I am unable to understand this actually. i.e. the spec of this key.
The libp2p spec accepts keys in the following formats:
- RSA
- Ed25519
- Secp256k1
- ECDSA
From my understanding, the Ethereum key from web3js
is a ECDSA key, right?
You will need to get that into a libp2p valid key with https://github.com/libp2p/js-libp2p-crypto#cryptokeysmarshalpublickeykey-type and then use this in the peer-id
From my understanding, the Ethereum key from web3js is a ECDSA key, right?
-- I can't seem to find it even in web3js docs.
But if you are saying it should be correct.
crypto.keys.marshalPublicKey("0xe4054F19da776c7a342Fc9DBDDd17000d8cE061F")
returns undefined
It would be worth to make sure on the actual key type. You can try to generate keys using https://github.com/libp2p/js-libp2p-crypto#cryptokeysgeneratekeypairtype-bits and see the actual format of public key you would need. For marshalPublicKey you need one of keys.rsa.RsaPublicKey | keys.ed25519.Ed25519PublicKey | keys.secp256k1.Secp256k1PublicKey
, and not a string format. So I think you will need to have an intermediate step where you convert that into a valid key for libp2p
@kuabhish
I had found the solution. I don't know its perfect or not but I found it.
S.p Thanks to @AztecProtocol for sign,verify and recover
functionality.
Idea is we are generating same peer id and ethereum address from same private Key. Since in metamask we dont have private key or public key access. From metamask we can sign message and send to the node. If signature match with public key then we can verify the request from particular peer is from the same owner of private id.
libp2p peer id 16Uiu2HAm1yMWq1bKaVuREsMXjRFmw1LX2kwNbpet92cziYEkzJxd
Private key with secpk2561: 080212206c728e2600f11c4d123539c5d8a1a7a7eba36f90b0084f64e383ce23d6b3e2a1
Compressed Private key: 026c728e2600f11c4d123539c5d8a1a7a7eba36f90b0084f64e383ce23d6b3e2a1
Uncompressed publick key: 046143d4403bcd61d1dd2571e13c016c80eee48ee2c9f374bca9893b790de6d4f6f3de4486c18f1ffe3d5cccf145e0ae2d0006f48ec78f593ec6c1052b1be0a706
Compressed public key 026143d4403bcd61d1dd2571e13c016c80eee48ee2c9f374bca9893b790de6d4f6
Public key Keccak Compressed b93572dc74e9828a6eadb139076773f63ee7da121d40cf610a63ba65007a4cc8
EthAddress 0x076773f63ee7da121d40cf610a63ba65007a4cc8
//////////////////////////////// -> Hash
0x984868cdcfa94a105990d7df844e662dab4bc8559a6e8728a6aeb11ef9ff2701
//////////////////////////////// -> Sign
[
'0x000000000000000000000000000000000000000000000000000000000000001c',
'0xedc9e4946f8c894176b1a78c8ae012149bf100509955e861914c3745d123e904',
'0x4d3a30bc8d2410f5de58423c28bb3ce5e32fcc05a0f53954ebf564def689ed87'
]
//////////////////////////////// -> Recover
uncompressed 046143d4403bcd61d1dd2571e13c016c80eee48ee2c9f374bca9893b790de6d4f6f3de4486c18f1ffe3d5cccf145e0ae2d0006f48ec78f593ec6c1052b1be0a706
0x6485a5BB371447F43e0629bcd1aEb11ff8B9905a
//////////////////////////////// -> Verify
true
/**
https://iancoleman.io/bip39/
alarm okay buyer write hamster make very okay such obey purchase trash boat universe hotel
Working 6c728e2600f11c4d123539c5d8a1a7a7eba36f90b0084f64e383ce23d6b3e2a1
Not working b3ed6bb8909ac5f7d155d28c8ed177232bb009fc1cdf10d18269d0f94c66d269
*/
import { createFromPrivKey } from "@libp2p/peer-id-factory";
import keccak256 from "keccak256";
import { fromString as uint8ArrayFromString } from "uint8arrays/from-string";
import { keys } from "@libp2p/crypto";
import { toString as uint8ArrayToString } from "uint8arrays/to-string";
import elliptic from "elliptic";
import BN from "bn.js";
import web3Utils from "web3-utils";
var ec = new elliptic.ec("secp256k1");
const secpK256Wallet = await ec.keyFromPrivate(
"6c728e2600f11c4d123539c5d8a1a7a7eba36f90b0084f64e383ce23d6b3e2a1"
);
const buf = uint8ArrayFromString("08021220" + secpK256Wallet.getPrivate("hex"), "hex");
const privateKeyLibp2p = await keys.unmarshalPrivateKey(buf);
const peerId = await createFromPrivKey(privateKeyLibp2p);
console.log("libp2p peer id ", peerId.toString());
const privateKeyAsHex = peerId.privateKey;
const privateKey = uint8ArrayToString(privateKeyAsHex, "hex");
const privateKey2 = keys.unmarshalPublicKey(privateKeyAsHex);
console.log("Private key with secpk2561:", privateKey);
console.log(
"Compressed Private key:",
uint8ArrayToString(privateKey2.marshal(), "base16")
);
const publicKeyAsHex = peerId.publicKey;
const publicKey2 = keys.unmarshalPublicKey(publicKeyAsHex);
console.log("Uncompressed publick key:", secpK256Wallet.getPublic(false, "hex"));
console.log(
"Compressed public key",
uint8ArrayToString(publicKey2.marshal(), "base16")
);
const keccak = keccak256(Buffer.from(secpK256Wallet.getPublic(false, "hex"), "hex"));
console.log("Public key Keccak Compressed", keccak.toString("hex"));
var slicedHash = "0x" + keccak.toString("hex").slice(-40);
console.log("EthAddress", slicedHash);
console.log("//////////////////////////////// -> Hash");
const initialMessage = "0x4173696d";
const initialBuffer = Buffer.from(web3Utils.hexToBytes(initialMessage, "hex"));
const pream = Buffer.from(
`\x19Ethereum Signed Message:\n${initialBuffer.length}`
);
const messageBuffer = Buffer.concat([pream, initialBuffer]);
const hash = web3Utils.sha3(messageBuffer);
console.log(hash);
console.log("//////////////////////////////// -> Sign");
/* -------------------------------------------------------------------------- */
/* Sign */
/* -------------------------------------------------------------------------- */
const signature = ec
.keyFromPrivate(
Buffer.from(
// we need to slice 02 as it is compressed private key
uint8ArrayToString(privateKey2.marshal(), "base16").slice(2),
"hex"
)
)
.sign(Buffer.from(hash.slice(2), "hex"), { canonical: true });
const [v, r, s] = [
`0x${web3Utils.padLeft(
Number(27 + Number(signature.recoveryParam)).toString(16),
64
)}`,
`0x${web3Utils.padLeft(signature.r.toString(16), 64)}`,
`0x${web3Utils.padLeft(signature.s.toString(16), 64)}`,
];
console.log([v, r, s]);
console.log("//////////////////////////////// -> Recover");
/* -------------------------------------------------------------------------- */
/* Recover */
/* -------------------------------------------------------------------------- */
const rBn = new BN(r.slice(2), 16);
const sBn = new BN(s.slice(2), 16);
const vn = new BN(v.slice(2), 16).toNumber();
const ecPublicKey = ec.recoverPubKey(
Buffer.from(web3Utils.padLeft(hash.slice(2), 64), "hex"),
{ r: rBn, s: sBn },
vn < 2 ? vn : 1 - (vn % 2)
);
const ecKey = ec.keyFromPublic(ecPublicKey);
console.log("uncompressed", ecKey.getPublic(false, "hex"));
const publicKeyHex = `0x${ecKey.getPublic(false, "hex").slice(2)}`;
const publicHash = web3Utils.sha3(publicKeyHex);
const address = web3Utils.toChecksumAddress(`0x${publicHash.slice(-40)}`);
console.log(address);
/* -------------------------------------------------------------------------- */
/* Verify */
/* -------------------------------------------------------------------------- */
console.log("//////////////////////////////// -> Verify");
console.log(
ec.verify(hash.slice(2), { r: rBn, s: sBn }, ec.keyFromPublic(ecKey, "hex"))
);