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

Feature Request: Out-of band cryptographic signatures #123

Closed betamos closed 4 years ago

betamos commented 4 years ago

A signing API would be useful when libp2p is used with non-libp2p transports or for persistent storage of a message that some other entity can verify the origin of. It could look e.g. like:

const myId = PeerId.createFromPrivKey(..)
myId.sign(nonce, message)  // Nonce for preventing replay attacks.
..
const theirId = PeerId.createFromPubKey(..)
theirId.verify(message)

// TODO: Maybe some algorithm selection?

Verifying would require the presence of a public key (not just a B58String). From a quick experiment, it seems the public key is populated on handle but not upon a successful dial, when peer id is created from a B58String. This could probably be added in some way in libp2p since the public key is available during a handshake anyway.

Would y'all be open to such a feature? Happy to put in some work if so.

vasco-santos commented 4 years ago

Hey @betamos

Why not simply using the peerId provided getters like: peerId.privKey and do peerId.privKey.sign()?

I am not seeing any reason on having more code, which implies a bigger bundle that is particularly bad for browser environments and more code to maintain and test. Can you help me understand what would this bring that we cannot already achieve easily?

betamos commented 4 years ago

Thanks, that's great. Signing with the private key and verifying with a public key does work as described. However, I couldn't get the public key of remote peers, in order to invoke verify. This was my journey:

  1. PeerId.privKey, PeerId.pubKey, PrivateKey.sign and PublicKey.verify were not documented in the README files, but the TS files did indeed contain these APIs.. Learnt too late.
  2. A PeerId created from a B58String does not get the public key populated after a successful outbound dial
  3. Neither was it populated in the peer store.
  4. Neither did any of the return values to Libp2p.dialProtocol contain the peer id.
  5. Calling Libp2p.dial directly returns a connection which has a remotePeer (PeerId) present, but it didn't have the public key either.
  6. After digging around, I found that the public key isn't always populated during the SECIO handshake (v0.12.14). See https://github.com/libp2p/js-libp2p-secio/pull/119. With this change, (2) and (5) now works (and possibly other methods - not verifed).

Closing out since the remaining issue is not in this repository.

vasco-santos commented 4 years ago

@betamos I just got to the same conclusion as you in https://github.com/libp2p/js-libp2p/pull/626#discussion_r421336544

So yes, you are right, and we will need to work on that change :) The same for noise

vasco-santos commented 4 years ago

FYI, this is also an issue using NodeFactoryIo/js-libp2p-noise, which we will want to have people using on 0.28 release of libp2p. Would you like to also fix it there?