Skip to content

Keypair::to_protobuf_encoding - #2142

Merged
mxinden merged 4 commits into
libp2p:masterfrom
rubdos:identity-protobuf-encode
Jul 28, 2021
Merged

mxinden merged 4 commits into
libp2p:masterfrom
rubdos:identity-protobuf-encode

Conversation

@rubdos

@rubdos rubdos commented Jul 15, 2021

Copy link
Copy Markdown
Contributor

Keypair was able to decode protobuf-encoded keys, but not to encode them yet afaik. This adds a method to encode identity::Keypairs.

@rubdos
rubdos force-pushed the identity-protobuf-encode branch from 740317d to 66d5837 Compare July 15, 2021 11:37
@rubdos

rubdos commented Jul 15, 2021

Copy link
Copy Markdown
Contributor Author

I now also notice that PublicKey has into_protobuf_encoding, taking self (and not &self), however, no fields of PublicKey are ever moved out; every encode step is by reference. I think it makes sense to unify those, for which I'd vote to_ and not into_

@rubdos
rubdos force-pushed the identity-protobuf-encode branch from 66d5837 to 8ba0b8c Compare July 15, 2021 11:53

@thomaseizinger thomaseizinger left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Agree with PublicKey::into_protobuf_encoding -> PublicKey::to_protobuf_encoding

@rubdos

rubdos commented Jul 16, 2021 •

Copy link
Copy Markdown
Contributor Author

Agree with PublicKey::into_protobuf_encoding -> PublicKey::to_protobuf_encoding

Do I put that in here, or shall I make a separate PR?

EDIT: and while we're at it, into_peer_id() is probably the same story...

@thomaseizinger

thomaseizinger commented Jul 16, 2021 •

Copy link
Copy Markdown
Contributor

Do I put that in here, or shall I make a separate PR?

Can we do it in separate without having dependencies to this code? I think so right?
Then a separate PR would be better because it will be an API breaking change. Personally, I'd actually favor if we can make more use of deprecated instead of breaking APIs right away but I know that @mxinden doesn't mind as much as long as the transition is easy (which it should be if it is just a rename).

Speaking of changes, can you add a changelog entry please?

EDIT: and while we're at it, into_peer_id() is probably the same story...

I think that was because PeerId used to not be Copy so it made sense to use into. But now that it is Copy, it might as well be named to_peer_id although I think clippy would still want you to take self then and not &self.

@rubdos
rubdos force-pushed the identity-protobuf-encode branch from 8ba0b8c to fe43968 Compare July 16, 2021 14:22
@rubdos

rubdos commented Jul 16, 2021

Copy link
Copy Markdown
Contributor Author

Can we do it in separate without having dependencies to this code? I think so right?

Definitely.

Then a separate PR would be better because it will be an API breaking change. Personally, I'd actually favor if we can make more use of deprecated instead of breaking APIs right away but I know that @mxinden doesn't mind as much as long as the transition is easy (which it should be if it is just a rename).

I mean, we can leave both in, but it's really only deleting two characters :-)

Speaking of changes, can you add a changelog entry please?

Done

EDIT: and while we're at it, into_peer_id() is probably the same story...

I think that was because PeerId used to not be Copy so it made sense to use into. But now that it is Copy, it might as well be named to_peer_id although I think clippy would still want you to take self then and not &self.

Hmm, into vs to are related to the source type (PublicKey), not the destination type (PeerId), right?

@rubdos rubdos mentioned this pull request Jul 16, 2021
3 tasks done
@thomaseizinger

thomaseizinger commented Jul 16, 2021 •

Copy link
Copy Markdown
Contributor

Hmm, into vs to are related to the source type (PublicKey), not the destination type (PeerId), right?

They are, but if a type is not Copy, it is more flexible to offer into_ because it allows the user to potentially avoid an allocation (if the implementation allows it) whereas to_ can always be worked around with .clone().into_.

For encoding to protobuf, we need to allocate anyway so there is no point in offering into_.

Comment thread core/src/identity.rs
}

/// Encode a private key as protobuf structure.
pub fn to_protobuf_encoding(&self) -> Result<Vec<u8>, DecodingError> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you expand on your use-case for encoding private keys?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is a usecase: https://github.com/comit-network/rendezvous-server/blob/c5dedb5119569ff523da981f5bb3b02d3e3cb903/src/main.rs#L143-L151

We want the server to always have the same identity, which is why we store the secret key in a file. Using normal unix user ACLs, we can control which parts of the machine have access to this private key.

Our design was inspired by: https://smallstep.com/blog/command-line-secrets/

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same case here: a bootstrap server (set of bootstrap servers) with a fixed identity.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be a bit paranoid, but I would really like to keep the extra safety measure of not being able to extract private key material once moved to a Keypar.

Why not do something along the lines of GenerateNodeKeyCmd and InspectNodeKeyCmd?

I would even suggest that we alter our peer ID generator, enabling it to generate a random private key and saving it to a file, preferably in the IPFS format. The rendezvous-server or your bootstrap server can then read that file and load it as a Keypair.

I am taking a similar approach with rust-libp2p-server and ipfs init.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense. I was confused that Keypair::generate_*() was a thing, with seemingly no way to persist the private key. Maybe this is a documentation issue after all, if it's indeed possible to construct the private information, persist it, and then yield a key.

Would you agree if I say that it's strange to generate a Ed25519 keypair, persist the secret (somehow) and then read that as a Keypair? I wouldn't expect a struct to serialize, then deserialize to a different type.

It's not too paranoid IMO.

I would even suggest that we alter our peer ID generator, enabling it to generate a random private key and saving it to a file, preferably in the IPFS format. The rendezvous-server or your bootstrap server can then read that file and load it as a Keypair.

Note that saving to files is not a general solution; I imagine some people want to persist to a database, either in a file or in memory, etc.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A patch to the docs would be very much appreciated, so others don't get confused too.

Making a lot of promises against rust-libp2p lately, but since I'll have to revise my own stuff now (it's currently using this branch), I suppose it's not a lot of work to create some docs and example code with doctests on the Keypair struct.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be a bit paranoid, but I would really like to keep the extra safety measure of not being able to extract private key material once moved to a Keypar.

But that is already possible or am I missing something?

  • Fields in enums are public, hence one can just match on the variant and get for example an ed25519::Keypair
  • ed25519::Keypair can be converted .into() an ed25519::SecretKey.
  • ed25519::SecretKey implements AsRef<[u8]>

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having a look at how to apply the approach you take in GenerateNodeKeyCmd and InspectNodeKeyCmd, but those seem not to use the protobuf encoding (which is what IPFS seems to use).

If the PeerID generator is altered to allow writing IPFS-style secret keys, I don't currently see how it can do without a patch like this one. Am I missing something here?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤦‍♂️ my bad, you are absolutely right @thomaseizinger! Sorry for the confusion.

If the PeerID generator is altered to allow writing IPFS-style secret keys, I don't currently see how it can do without a patch like this one. Am I missing something here?

Again, 100% correct.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries, better to triple check and make sure! Thanks for having this :-)

@mxinden mxinden left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for bearing with me! Looks good to me. Also thanks for changelog entry and test.

Comment thread core/CHANGELOG.md Outdated
@rubdos

rubdos commented Jul 27, 2021

Copy link
Copy Markdown
Contributor Author

Current failure seems to be due to some incompatibility between #2142 and some new commit.

This should fix it:

diff --git a/core/src/identity.rs b/core/src/identity.rs                  
index 1569d4db..298797cd 100644                                           
--- a/core/src/identity.rs                                                
+++ b/core/src/identity.rs                                                
@@ -285,12 +285,12 @@ mod tests {                                         
     #[test]                                                              
     fn keypair_protobuf_roundtrip() {                                    
         let expected_keypair = Keypair::generate_ed25519();              
-        let expected_peer_id = expected_keypair.public().into_peer_id(); 
+        let expected_peer_id = expected_keypair.public().to_peer_id();   
                                                                          
         let encoded = expected_keypair.to_protobuf_encoding().unwrap();  
                                                                          
         let keypair = Keypair::from_protobuf_encoding(&encoded).unwrap();
-        let peer_id = keypair.public().into_peer_id();                   
+        let peer_id = keypair.public().to_peer_id();                     
                                                                          
         assert_eq!(expected_peer_id, peer_id);                           
     }                                                                    

@thomaseizinger

Copy link
Copy Markdown
Contributor

Current failure seems to be due to some incompatibility between #2142 and some new commit.

That is because CI runs on pull_request and not push which is always a merge-commit between HEAD and target branch. Merging in latest master / rebasing onto master should allow you to reproduce the issue locally :)

@rubdos

rubdos commented Jul 28, 2021

Copy link
Copy Markdown
Contributor Author

Right, I didn't realize it's code from this PR that messed that up. Too many things in parallel. Should work now :'-)

@mxinden
mxinden merged commit 50b0957 into libp2p:master Jul 28, 2021
@rubdos
rubdos deleted the identity-protobuf-encode branch December 28, 2021 11:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants