Uh oh!
There was an error while loading. Please reload this page.
Add SimpleKEM and FullKEM traits to kem - #1559
Conversation
tarcieri
commented
Apr 19, 2024
This is also very similar to pubtraitKemCore{typeSharedKeySize:ArraySize;typeCiphertextSize:ArraySize;typeDecapsulationKey:Decapsulate<Ciphertext<Self>,SharedKey<Self>> + EncodedSizeUser + Debug + PartialEq;#[cfg(not(feature = "deterministic"))]typeEncapsulationKey:Encapsulate<Ciphertext<Self>,SharedKey<Self>> + EncodedSizeUser + Debug + PartialEq;#[cfg(feature = "deterministic")]typeEncapsulationKey:Encapsulate<Ciphertext<Self>,SharedKey<Self>> + EncapsulateDeterministic<Ciphertext<Self>,SharedKey<Self>> + EncodedSizeUser + Debug + PartialEq;fngenerate(rng:&mutimplCryptoRngCore) -> (Self::DecapsulationKey,Self::EncapsulationKey);#[cfg(feature = "deterministic")]fngenerate_deterministic(d:&B32,z:&B32) -> (Self::DecapsulationKey,Self::EncapsulationKey);}In particular let dk_bytes = Encoded::<K::DecapsulationKey>::from_slice(self.dk);assert_eq!(dk,K::DecapsulationKey::from_bytes(dk_bytes));let ek_bytes = Encoded::<K::EncapsulationKey>::from_slice(self.ek);assert_eq!(ek,K::EncapsulationKey::from_bytes(ek_bytes));In the general model, this requires an adapter trait to be written for tests and included as an additional trait bound for generic tests. pubtraitSecretBytes{fnas_slice(&self) -> &[u8];}implSecretBytesforSecret{fnas_slice(&self) -> &[u8]{self.0.as_bytes().as_slice()}}// use a generic SimpleKEM function to ensure correctnessfntest_kemtrait_basic<K:SimpleKEM>()where
<KasSimpleKEM>::SharedSecret:SecretBytes,{letmut rng = rand::thread_rng();let(sk, pk) = K::random_keypair(&mut rng);let(ek, ss1) = K::encapsulate(&pk,&mut rng).expect("never fails");let ss2 = K::decapsulate(&sk,&ek).expect("never fails");assert_eq!(ss1.as_slice(), ss2.as_slice());} |
rozbb
commented
Apr 19, 2024
I agree ml-kem probably shouldn't be defining its own traits. I guess I'm not sure what functionality is needed by users. The primary addition I see in Thinking through alternatives: suppose a function is generic over a KEM and needs to be able to generate a fresh ephemeral keypair. Then perhaps it should be of the form fnfoo<EK,SS,E,F>(gen:F)whereE:Encapsulate<EK,SS>,F:Fn(&mutimplCryptoRngCore) -> (E,[u8;32]){let rng = rand::thread_rng();let(ek, dk) = gen(&mut rng);// ...}This is nice because Thoughts? |
I don't have an opinion per se, but the goal of the trait is so that one can precisely express what a specific KEM model does. i.e.
As for how these types are specified, it is ultimately up to the user. The X3DH test includes an example of how implFullKEMforX3Dh{typePrivateKey = X3DhPrivkeyBundle;typePublicKey = X3DhPubkeyBundle;typeDecapsulatingKey = DecapContext;typeEncapsulatingKey = EncapContext;typeEncapsulatedKey = EphemeralKey;typeSharedSecret = SharedSecret;fnrandom_keypair(_:&mutimplCryptoRngCore) -> (Self::PrivateKey,Self::PublicKey){let sk = Self::PrivateKey::gen();let pk = sk.as_pubkeys();(sk, pk)}}fntest_kemtrait_x3dh(){letmut rng = rand::thread_rng();let sk_ident_a = IdentityKey::default();let pk_ident_a = sk_ident_a.strip();let(sk_bundle_b, pk_bundle_b) = X3Dh::random_keypair(&mut rng);let encap_context = EncapContext(pk_bundle_b, sk_ident_a);let decap_context = DecapContext(sk_bundle_b, pk_ident_a);// Now do an authenticated encaplet(encapped_key, ss1) = X3Dh::encapsulate(&encap_context,&mut rng).unwrap();let ss2 = X3Dh::decapsulate(&decap_context,&encapped_key).unwrap();assert_eq!(ss1, ss2);}The primary motivation for these traits is to develop the general TLS KEM combiner so we can ultimately do |
I see what you mean. Though I might be missing the point on the example API and impl for X3DH you give. If you defined a function that generically created a keypair and did some operations, it's very unlikely that it would generate an identity key AND a prekey AND an ephemeral key (more likely: keep the identity key, pick a prekey from a set, and generate a fresh ephemeral key). For that reason, it seems like there's no concrete use case for a |
incertia
commented
Apr 20, 2024
I do agree that key generation can probably be moved outside of the trait. I think the main reason I included it is due to it being in |
tarcieri
commented
Apr 23, 2024
I think having a trait for capturing these details is good. I'm unclear why we need two traits and why they can't build on each other. It feels like a lot of duplication. The names should follow RFC430, i.e. |
bifurcation
commented
Apr 24, 2024
My initial impression is that this seems like a regression over the simplification we did in #1509. It looks to me like the only details this interface exposes is key generation, which has not been exposed in, e.g., the traits in the traitKemKeyGenerate{typeEncapKey:Encapsulator<EK>,typeDecapKey:Decapsulator<EK>,fngenerate(rng:&mutCryptoRng) -> Result<(Self::DecapKey,Self::EncapKey),Error>;}Having If we're copying patterns from |
incertia
commented
Apr 24, 2024
For KEMs in particular it seemed very weird to me why the original traits also split Encapsulator and Decapsulator. In particular, for KEMs, these actions are closely tied together and it would make sense to bundle these into a single trait.
I think the point here is similar to above. In practice, KEMs are essentially specified by their Perhaps the best design here is to unify |
bifurcation
commented
Apr 24, 2024
Why is this any different from a signature algorithm that specifies both sign and verify? These are reflected in Signer and Verifier traits in this repo. Just because they're in different traits doesn't mean they can't be implemented together, say in the same file. To put it differently, think of what application code needs to have in order to do something. With the |
tarcieri
commented
Apr 24, 2024
@incertia having a ZST to hang the overall scheme off of seems fine to me, but I would think it would only have associated types for the |
bifurcation
commented
Apr 24, 2024
@tarcieri what value would that add over say |
tarcieri
commented
Apr 24, 2024
Alternatively, |
@bifurcation being able to write generic code that can locate the type which performs decapsulation, similar to Edit: whoops, it would probably make more sense to be able to look up the associated encapsulator for a given decapsulator, but hopefully you get the idea |
incertia
commented
Apr 24, 2024
This also makes sense |
bifurcation
commented
Apr 24, 2024
|
tarcieri
commented
Apr 24, 2024
As a more concrete example of a (sidebar: it would be nice to support RSA-KEM eventually) |
@bifurcation |
Ok, to sketch out at bit: we have as a starting point pubtraitsignature::Keypair{typeVerifyingKey:Clone;fnverifying_key(&self) -> Self::VerifyingKey;}Replacing everything with the appropriate types, we get pubtraitkem::Keypair<EK,SS>{typeEncapsulationKey:Encapsulation<EK,SS>;fnencapsulation_key(&self) -> Self::EncapsulationKey;}Did we want to support getting the decap key from this? If so, do we know why the |
tarcieri
commented
May 7, 2024
@rozbb in The reason As I mentioned in this earlier, since that complication doesn't exist here, |
I see. So iteration 2: pubtraitkem::Keypair<EK,SS>{typeEncapsulationKey:Encapsulation<EK,SS>;typeDecapsulationKey:Decapsulation<EK,SS>;fnencapsulation_key(&self) -> Self::EncapsulationKey;fndecapsulation_key(&self) -> Self::DecapsulationKey;}Actually, by this logic, why can't we just do: struct kem::Keypair<EK,SS,E,D>whereE:Encapsulation<EK,SS>,D:Decapsulation<EK,SS>,{pubencap_key:E,pubdecap_key:D,} |
tarcieri
commented
May 7, 2024
@rozbb of those, the struct looks better to me. Either are a bit different from |
incertia
commented
May 7, 2024
following in this vein, perhaps |
tarcieri
commented
Apr 10, 2026
The |
This adds a
SimpleKEMtrait, representing KEM models where the public and private keys from key generation are equivalent to the encapsulating and decapsulating keys. We also add aFullKEMtrait, which is more general, which allows for KEM models where this is not the case, such as when trying to model authenticated X3DH as a KEM.Motivation for this PR is mostly just promoting the
DhKemtrait from RustCrypto/KEMs#16 into the kem crate itself.I think it is also good to have some code that forwards the calls from
SimpleKEM::encapsulateandFullKEM::encapsulateto the actualEncapsulate<EK, SS>implementation. That way, a user can directly writeKemModel::encapsulateand ensure that the types are correct, in the case that there are separate models that use very similar setups. e.g. unauthenticated vs authenticated modes of key exchange.