-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add peer id inlining for small public keys #1230
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure if we want to support "identity" hashes for up to 4 GiB.
misc/multihash/src/hashes.rs
Outdated
@@ -60,6 +63,7 @@ impl Hash { | |||
/// Get the hash length in bytes. | |||
pub fn size(&self) -> u8 { | |||
match self { | |||
Hash::Identity => 42, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also note that this is entirely redundant. A go implementation uses this:
https://github.com/multiformats/go-multihash/blob/64ffd94071a5bc58130ea88fd8404408aef993f2/multihash.go#L141
I would tend to agree. The only reason I did this, was because the more featured go-implementation of multi-hashes do it. https://github.com/multiformats/go-multihash/blob/master/multihash.go#L258 It shouldnt affect libp2p really as we are only using this for known-sized keys. Happy to reduce this, am indifferent to the size of identity hashes to support. |
The PR looks good. The only problem with it would break any existing network using rust-libp2p (which includes Substrate and Polkadot 😅 ). If you don't mind, I think we should for now accept both hashed and non-hashed keys, but only send out our key hashed. In other words, The disadvantage of doing so is that during this transition period, two different |
This originally came from compatibility issues with other implementations. If we broadcast a hashed version, the other implementations will reject that multiaddr when trying to connect on that multiaddr, which was the initial problem. It sounds like I am the only one really with this issue, and our client uses a forked version of rust-libp2p where I've already added these changes. So perhaps if this is not causing any issues for anyone else at the moment, perhaps we leave this PR, until a later release? However if you want these in now, I'm happy to make the changes you suggest. |
We definitely want this in master sooner or later. Also, apparently js-libp2p introduced the inlining between 0.12.2 and 0.12.3, which broke compatibility with rust-libp2p until this PR is in. |
Yeah, I usually use "the go implementation" as a synonym of "the libp2p-spec" as most of the specs are based off this and anything mismatching, we should consult the go-impl, so not surprising js-libp2p also matches this. I'll leave this PR in your hands and let you merge/modify next release/when dependent projects are ready. |
Small note: let's keep that PR open in order to not forget to finish this change. |
I merged master on top of this PR and added a comment. |
Tested on Polkadot. Unfortunately doesn't work, and nodes refuse our connections. Will need to figure out what is happening before merging. |
The problem comes from here: rust-libp2p/protocols/secio/src/lib.rs Line 145 in 481849e
At the end of the secio handshake, a node on an older version of libp2p will generate a SHA256 PeerId for the remote and compare it against the expected identity PeerId , which will fail comparison.
Similarly, a node on a newer version will generate an identity I'm not sure how to fix that. Maybe we can make |
I think this points into the right direction. The digest of an identity hash equals the original input, so we can always hash the digest with a different algorithm and compare the result with the other one at hand: impl PartialEq<PeerId> for PeerId {
fn eq(&self, other: &PeerId) -> bool {
match (self.multihash.algorithm(), other.multihash.algorithm()) {
(a, b) if a == b => {
self.multihash.digest() == other.multihash.digest()
}
(multihash::Hash::Identity, b) => {
let x = multihash::encode(b, self.multihash.digest());
x.as_ref() == Ok(&other.multihash)
}
(a, multihash::Hash::Identity) => {
let x = multihash::encode(a, other.multihash.digest());
x.as_ref() == Ok(&self.multihash)
}
_ => false
}
}
} Edit: A property test to add: #[test]
fn equals() {
use multihash::Hash;
use quickcheck::{Arbitrary, Gen};
#[derive(Debug, Clone, PartialEq, Eq)]
struct HashAlgo(Hash);
impl Arbitrary for HashAlgo {
fn arbitrary<G: Gen>(g: &mut G) -> Self {
match g.next_u32() % 16 { // make Hash::Identity more likely
0 => HashAlgo(Hash::SHA1),
1 => HashAlgo(Hash::SHA2256),
2 => HashAlgo(Hash::SHA2512),
3 => HashAlgo(Hash::SHA3512),
4 => HashAlgo(Hash::SHA3256),
5 => HashAlgo(Hash::Keccak256),
6 => HashAlgo(Hash::Blake2b512),
7 => HashAlgo(Hash::Blake2s256),
_ => HashAlgo(Hash::Identity)
}
}
}
fn property(data: Vec<u8>, algo1: HashAlgo, algo2: HashAlgo) -> bool {
let a = PeerId { multihash: multihash::encode(algo1.0, &data).unwrap() };
let b = PeerId { multihash: multihash::encode(algo2.0, &data).unwrap() };
if algo1 == algo2 || algo1.0 == Hash::Identity || algo2.0 == Hash::Identity {
a == b
} else {
a != b
}
}
quickcheck::quickcheck(property as fn(Vec<u8>, HashAlgo, HashAlgo) -> bool)
} |
One thing to not forget is that we derive (nothing unfixable, but I thought I'd add a note to not forget) |
Any chance we can get this merged behind a disabled feature flag? It is essential for interop with go-libp2p and presumably also js-libp2p. I tried to get the chat example to work with go-ipfs, and one problem is that the peer id on the rust side is different than on the go side. Working from this branch, the peer id is identical. @koivunej thanks for the hint |
This PR needs the changes so that |
Finished in #1413 |
This adds peer id inlining to match the behaviour of the go implementation.
Specifically, it addresses the rust side of libp2p/go-libp2p-daemon#137
A few points to note:
secp256k1
anded25519
keysmultihash
crate needed to be updated to include the identity hash. The go-implementation of this allows for up to 2^32 byte identity objects and this is mimicked here. The current rust-implementation relied on fixed hash sizes, where the identity "hash" can have sizes up to this length. There is now split logic in this implementation, between true hashes and theIdentity
type (which isn't great, feel free modify it, if there is a cleaner solution).I've tested this with
RSA
,ed25519
andsecp256k1
curves. This now connects and handshakes correctly with the go-daemon. May want to run further tests to ensure nothing upstream gets broken by these changes.