Join GitHub today
GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.Sign up
Peer ID Calculation History And Resolution #138
Forks off #111 to focus on the backwards compatibility issue instead of the CID/PID design space.
Peer ID calculation has changed a couple of times over the past year.
This all grew out of several requirements and wants:
Note: "inlining" peer IDs look like
Below is an exhaustive history of this issue:
This issue covers the peer ID issue, not the timeout issues.
This covers the affected subsystems and some hacky fixes that I don't recommend.
When establishing an outbound connection, go-libp2p will:
Textile is seeing this fail after updating go-libp2p because they're passing a
Example Fix: This could be fixed by a hack to convert a peer ID created using
When receiving an inbound connection, we compute the peer's ID from their public key. That means:
Example Fix: In practice, this "just works". That is, we use our version of the
The DHT is the first place where we really care about calculating the same peer
Let's say there's some peer A that wants to connect to a peer B. Let's assume
When peer A tries to connect to peer B, it'll walk the DHT looking asking nodes if they either:
In this case,
Example Fix: So, if we have an inlining peer ID, we can extract the key and
I don't believe IPNS is affected but I haven't thought through it thoroughly. At
Same as IPNS.
Unfortunately, this whole issue also relates to the ask from IPFS In Web
The real worry is that if we allow arbitrary mulithash functions, we need to
This was referenced
Jan 29, 2019
Shouldn't these two be reversed? .18 would use sha256 and .19-dev would use inline.
These are incompatible (without embedding hash function in the protobuf):
Edit: moved to #139
referenced this issue
Jan 31, 2019
While I agree with the goal (I struggled with encryption key management in one of my experiments), I'm not sure it can be done securely.
For Ed25519 to Curve25519 the community currently thinks it's likely to be secure but I haven't found a formal proof of that yet, which is why the golang library doesn't even offer to convert an Ed25519 key to a Curve25519 point.
And even if that turns out to be secure for the specific case of Ed25519 keys, it's likely to be insecure for other types of keys so we shouldn't encourage users to use the peer ID key for encryption. I think some kind of handshake is preferable, as it also provides nice features like perfect forward secrecy (at the expense of performance unfortunately).
Ed25519 is only a signing scheme (see here), not an encryption scheme.
Thanks for pointing out that document! We've been discussing doing something like it in ipfs/notes#291 (comment). Note, that doesn't actually require (as far as I can tell) embedding the public key in the peer ID. Instead of deriving the encryption key from the public key, we'd derive it from the peer ID.
The reason I believe in-lining is required is because
With in-line keys this becomes
Regarding encryption, I think there's no free lunch. If you want to have long-term encryption keys, you lose forward secrecy. That's the reason most protocols don't have long term encryption keys or rotate them regularly (tor's hidden services' master key used to derive the address is just a signing key, not an encryption key).
I think forward secrecy is important, which means there will always be a handshake/roundtrips to retrieve an encryption key for a given peer. We'll just have to live with it and make it efficient enough. TLS 1.3's 0-RTT is a good way to mitigate the performance issue (for actions that are not vulnerable to replay attacks).
Having a look at Signal's double ratchet could be an inspiration. I also remembered that Signal seems to have a solution that can provide signature and encryption with a single key, which they call XEdDSA, but I need to re-read the protocol because I remember that there are some caveats.
Otherwise the hidden service v3 spec is a very solid protocol (but not necessarily very performant) so it can also be a good starting point.
@Stebalien so here's our plan for ob... As part of the rebase to 0.18 I've put in patches to our
However, I would like to switch to inline keys in the future as not having to look up the public key simplifies our code quit a bit in various places. If you guys did absolutely nothing I would probably be OK with that as once enough of our peers upgrade to our latest release I can migrate everyone to inline keys and stop patching go-ipfs in
However, I do think it makes sense to from an architecture standpoint to support both formats but it would seem like there might be easier solutions. For example you could patch
Also the way I patched 0.18 connections was to change the
But overall from our perspective we'd like to make sure go-ipfs remains compatible with inline keys in the future as it would greatly improve our stuff to make the switch.
Note: IPNS records now include the key if it isn't inlined into the ID.
This is still the goal and we'll make sure to support it no matter what.
Take a look at the "Affected Subsystems" section above. The real issue happens when accepting an inbound connection. In that case, the "acceptor" doesn't know how the dialer calculated their peer ID so they may end up calculating it differently. This can affect things like DHT lookups.
referenced this issue
Feb 7, 2019
@Stebalien can go into more detail on this or maybe link to the part of the affected code.
I'm asking because in my code I've only patched
@parkan this isn't about any specific code, just how DHTs work.