Repository navigation
Feature/x25519 - #186
Feature/x25519#186ounsworth wants to merge 26 commits into
Conversation
|
In bc-java we've found the formulation completely different - I don't think there's any common code between the Edwards and the Weierstrass form - the basis chosen is usually based on efficiency and simplicity as well, so while it's technically possible, it's unlikely to be worth it. I think we have a Weierstrass representation of Curve 25519 somewhere, but I think it's only their for compatibility (usage wise) with someone else's implementation... |
|
Can you do me a favor and add perf tests? |
| type SharedSecretType: AsRef<[u8]>; | ||
|
|
||
| /// Perform a key agreement | ||
| fn key_agreement(pk: &PK, sk: SK) -> Result<Self::SharedSecretType, KeyAgreementError>; |
There was a problem hiding this comment.
sk in this context may vary - in the sense it could be unavailable to the software layer and hardware only. I'd suggest only passing pk, and having the key agreement constructed with sk, and what ever other parameters might be required (for what we're doing it might be useful to be able to apply KDFs as well).
This might actually be a good place for using KeyMaterial as well - ideally we'd make someone do extra work if they want to use a 128 bit secure secret to create a 256 bit shared secret.
There was a problem hiding this comment.
Yes, I know that you want to suggest a refactor like that, and we'll get to that, but for now I'm making the new KeyAgreement trait match the existing KEMEncapsulator trait.
Do you mean having key_agreement(..) -> KeyMaterial instead of returning a DH public key?
I tried this, but:
- A lot of things really do assume that the output of
key_agreementis another public key. For example, the iterated tests in RFC 7748 section 5.2 work that way. Also, I think that group protocols (and maybe Signal / MLS) chain DH's together using the property that the output of DH is a usable public key. - If you are going to hash an X25519PublicKey to get a usable shared KeyMaterial, then which KDF do you use? And what do you include in the KDF? RFC7748 suggests all three values: K, K_A, K_B. But since DH is symmetric, the crypto library doesn't know who is Alice and who is Bob, so it's going to get the order of K_A, K_B wrong.
- To do this robustly, you really need to wrap it in a standardized KEM, both to establish direction, to stardardize the inputs to the KDF, and which KDF to use. That's why I'm also adding a new crate
crypto/hpkeand using that to implKEMEncryptor/KEMDecryptoron the X25519 object.
Does that make sense?
Also, I'm still actively building this. I only put up a PR so that I could see the diff. While I appreciate the enthusiasm, maybe everyone should hold off on review until I've finished thinking this through and it's ready to be reviewed.
There was a problem hiding this comment.
No, it doesn't really make sense.
Concerning the suggestion, yes, 6 times, now 7. We've already gotten to that re-factor so I don't really understand why something would be getting designed with the idea that we haven't - PR #170 does this and we even spent the afternoon reviewing it in Prague.
Also, ECCDH only returns one coordinate, at least as defined in FIPS, strictly speaking so does XDH, although the RFC does hint more is possible. It's possible to create multi-party agreement, but not the way that's suggested, it needs a phased approach so you can tell when the right number of parties have come through the door. For most things, such as HPKE, 2 party is enough. I would only start returning public keys if I was trying to implement multi-party up front, which is something, at the moment at least, I would definitely not suggest we do, but if I was we would need an API which reflected the need to provide phases - it's the reason the Java KeyAgreement API has phases.
Concerning KeyMaterial, I noted that seemed to be the first thing being produced in the doc code. The security strength was correct, but we'd be able to take the guess work out if we simply returned it.
Yes that's on my TODO list! That'll be in place before I mark this PR ready for review. UPDATE: done Everything is about the same (basically a single x25519 scalar mult), except the KEM Encaps, which is a KeyGen + a KeyAgreement, so is about 1/2. The DHKEM's also include a round of HKDF to derive the output shared secret. Neat that that is not really noticeable next to the core x25519 op. |
…o/hpke/dhkem implementation. Also started crate docs.
…from ~1600 to ~1200 bytes.
…ey returned from key_agreement().
4ce23c2 to
78ab66f
Compare
| /// Structurally, this is an X25519PublicKey, but it is wrapped in its own type to protect it with | ||
| /// [`Secret`]. If it needs to be treated as a public key, use [`X25519DerivedKey::as_pk`]. | ||
| /// | ||
| /// Note that this impls `From<X25519PublicKey> for X25519DerivedKey` so that any public key can be |
There was a problem hiding this comment.
This felt surprising, is it really needed as part of the public API?
There was a problem hiding this comment.
Maybe not. Let me try removing it.
There was a problem hiding this comment.
All but the doc comment bit on the struct!
Creating as a draft. This is very much not ready for review, but this is the easiest way for me to see the diff.
Plan
I'm planning to do this feature in stages:
bouncycastle-mathcrate, or something. (in theory, this could happen in parallel any time after 1)How to review this PR
cargo doc -p bouncycastle-ed. The sample code is where an end-user would start, and probably also where a reviewer should start.crypto/core/src/traits.rs.crypto/ed/src/curve25519.rs. This is the core math. Don't worry about all the commented-out code that's waiting for ed25519; just skip it and it'll be in a future PR.crypto/ed/src/x25519.rs.x25519.rs, actually using the KeyAgreement trait to obtain a shared symmetric key is surprisingly tricky. So I wanted to impl the KEM traits over a DHKEM construction to hide the details, but then the question becomes: which DHKEM construction to use? RFC9180 HPKE is the only standardized one, so I decided to bite the bullet and add a new cratecrypto/hpkethat provides the generic DHKEM construction, and expose it by impl'ingKEMEcapsulatorandKEMDecapsulatoron theX25519struct.crypto/ed/src/ed_todo.mdthat tracks all the stuff I've done. It's also tracking the x448, ed25519, and ed448 work that I want to add as separate PRs stacked on top of this one.Open Questions
bouncycastle-edis not a great name for the crate, because technically only the signature variants ed25519 / ed448 use Twisted Edwards curves while x25519 / x448 are Montgomery curves. That said, there doesn't seem to be a generally-accepted overarching term for{x25519, x448, ed25519, ed448}. Maybexcurvesoredcurves? I don't want to split them up into separate crates just because there doesn't exist a good name.TODO before merging
crypto/ed/src/ed_todo.md.