[solved] How to use the IPFS self public and private key in node.js?

Awesome, this brought me further :slight_smile:
This code can sign and verify!

const fs = require("fs");
const crypto = require('libp2p-crypto');

function str2ab(text) {
    return new TextEncoder().encode(text);
}

function ab2str(buf) {
    return new TextDecoder().decode(buf);
}

(async function() {
    try {
        let data = fs.readFileSync("./test.key")
        let key = await crypto.keys.unmarshalPrivateKey(data);
        let sign = await key.sign(str2ab("QmReEZnKLvXvfric19kv6crts7ijK3xPicNEMkHFqBWfEq"));
        let hexSign = Buffer.from(sign).toString("hex");
        
        // At this point you have a readable (hex format) sign buffer.
        console.log("Sign: " + hexSign)

        // This public key should be created from the data you received
        let publicKey = key.public;

        // Verify the hash is signed by the private key
        let verify = await publicKey.verify(str2ab("QmReEZnKLvXvfric19kv6crts7ijK3xPicNEMkHFqBWfEq"), Buffer.from(hexSign, "hex"))

        // Should print true if verified
        console.log(verify)
    } catch (error) {
        console.log(error)
    }
}());

Now i’m stuck with the next issue… It never stops :wink: (well, nearly there)
I want to give “the other party”:

  • the signature
  • my peer id
  • the Qm… it needs to verify with that sign

The way (js-)libp2p seems to be working is by accepting the protobuf key object to unmarshal it. That is fine for the signing side, as there you need to have the private key. It should not be shared so having that in a protobuf as a binary is OK.

However, i would like to send the receiving side a string version of my peer id (which should be a public key). But that won’t work because the peer id is in a different format (not in the protobuf format).

How would i tackle that one?

Also, another issue is that you apparently can’t export the self key. Is there a way to get that key in the protobuf format? In this case it is an option to add a new key, as long as it’s all in ipfs

I’m curious what your thoughts would be for this one and how you’d solve it?

Edit
Got it!

        const multihashes = require('multihashes')
        let peerId = "<your peer id>"
        let multiHashPeerID = multihashes.decode(multihashes.fromB58String(peerId))
        let peerPubKey = await crypto.keys.unmarshalPublicKey(multiHashPeerID.digest)

That gives a proper public key i think :slight_smile:
Took a bit of “reverse logic” fiddling from the go code that extracts a the public key: https://github.com/libp2p/go-libp2p-core/blob/a39b84ea2e340466d57fdb342c7d62f12957d972/peer/peer.go#L92

Last thing i now need to know is how to get the self private key from IPFS?

Edit 2
For whoever ends up here with google. The IPFS private key (the self one that can’t be exported) is in the ipfs config file under the name PrivKey. It’s base64 encoded.

To be complete, loading your private key in (js-)libp2p is done like so:

        let data = Buffer.from("<your private key>", "base64")
        let key = await crypto.keys.unmarshalPrivateKey(data);
        // ... the same as my other example in this post

Got it all working now :smiley:
This took quite a while!
Your help, @jacobheun, was really valuable here! Thank you very much!

1 Like