libp2p / js-peer-id

peer-id implementation in JavaScript. Deprecated; use https://github.com/libp2p/js-libp2p-peer-id instead.
https://github.com/libp2p/js-libp2p-peer-id
MIT License
80 stars 44 forks source link

Import metamask web3j keys to Libp2p #140

Open kuabhish opened 3 years ago

kuabhish commented 3 years ago

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.

vasco-santos commented 3 years ago

What type of key is this?

You can check the supported key types in the peer id spec

kuabhish commented 3 years ago

The key is 0xe4054F19da776c7a342Fc9DBDDd17000d8cE061F - Public key for ethereum..

vasco-santos commented 3 years ago

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:

kuabhish commented 3 years ago

Sorry, @vasco-santos I am unable to understand this actually. i.e. the spec of this key.

vasco-santos commented 3 years ago

The libp2p spec accepts keys in the following formats:

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

kuabhish commented 3 years ago

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 
vasco-santos commented 3 years ago

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

asimashfaq commented 1 year ago

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