@@ -2,24 +2,28 @@ use byteorder::{BigEndian, ByteOrder};
22use curve25519_dalek:: constants:: ED25519_BASEPOINT_TABLE ;
33use curve25519_dalek:: montgomery:: MontgomeryPoint ;
44use curve25519_dalek:: scalar:: Scalar ;
5- use libcrux_ml_kem:: mlkem768:: {
6- decapsulate, encapsulate, generate_key_pair, MlKem768Ciphertext , MlKem768PrivateKey ,
7- MlKem768PublicKey ,
8- } ;
9- use libcrux_ml_kem:: { KEY_GENERATION_SEED_SIZE , SHARED_SECRET_SIZE } ;
105use log:: debug;
6+ use ml_kem:: {
7+ EncodedSizeUser , KemCore , MlKem768 , MlKem768Params ,
8+ kem:: { Decapsulate , DecapsulationKey , Encapsulate , EncapsulationKey } ,
9+ } ;
1110use sha2:: Digest ;
1211use ssh_encoding:: { Encode , Writer } ;
1312
14- use super :: { compute_keys, KexAlgorithm , KexAlgorithmImplementor , KexType , SharedSecret } ;
13+ use super :: { KexAlgorithm , KexAlgorithmImplementor , KexType , SharedSecret , compute_keys} ;
14+ use crate :: keys:: ssh_key:: rand_core:: OsRng ;
1515use crate :: mac;
1616use crate :: session:: Exchange ;
17- use crate :: { cipher , msg , CryptoVec , Error } ;
17+ use crate :: { CryptoVec , Error , cipher , msg } ;
1818
1919const MLKEM768_PUBLIC_KEY_SIZE : usize = 1184 ;
2020const MLKEM768_CIPHERTEXT_SIZE : usize = 1088 ;
2121const X25519_PUBLIC_KEY_SIZE : usize = 32 ;
2222
23+ type MlKem768PublicKey = EncapsulationKey < MlKem768Params > ;
24+ type MlKem768PrivateKey = DecapsulationKey < MlKem768Params > ;
25+ type MlKem768Ciphertext = ml_kem:: Ciphertext < MlKem768 > ;
26+
2327pub struct MlKem768X25519KexType { }
2428
2529impl KexType for MlKem768X25519KexType {
@@ -38,7 +42,7 @@ impl KexType for MlKem768X25519KexType {
3842pub struct MlKem768X25519Kex {
3943 mlkem_secret : Option < Box < MlKem768PrivateKey > > ,
4044 x25519_secret : Option < Scalar > ,
41- k_pq : Option < [ u8 ; SHARED_SECRET_SIZE ] > ,
45+ k_pq : Option < ml_kem :: SharedKey < MlKem768 > > ,
4246 k_cl : Option < MontgomeryPoint > ,
4347}
4448
@@ -82,25 +86,25 @@ impl KexAlgorithmImplementor for MlKem768X25519Kex {
8286 #[ allow( clippy:: indexing_slicing) ]
8387 let c_pk1_bytes = & c_init[ MLKEM768_PUBLIC_KEY_SIZE ..] ;
8488
85- let mut c_pk2_array = [ 0u8 ; MLKEM768_PUBLIC_KEY_SIZE ] ;
86- c_pk2_array . copy_from_slice ( c_pk2_bytes) ;
87- let c_pk2 = MlKem768PublicKey :: from ( c_pk2_array) ;
89+ let c_pk2_array =
90+ ml_kem :: Encoded :: < MlKem768PublicKey > :: try_from ( c_pk2_bytes) . map_err ( |_| Error :: Kex ) ? ;
91+ let c_pk2 = MlKem768PublicKey :: from_bytes ( & c_pk2_array) ;
8892
8993 let mut c_pk1 = MontgomeryPoint ( [ 0 ; 32 ] ) ;
9094 c_pk1. 0 . copy_from_slice ( c_pk1_bytes) ;
9195
92- let mut randomness = [ 0u8 ; SHARED_SECRET_SIZE ] ;
93- getrandom:: getrandom ( & mut randomness) . map_err ( |_| Error :: KexInit ) ?;
94-
95- let ( s_ct2, k_pq_shared_secret) = encapsulate ( & c_pk2, randomness) ;
96+ let ( s_ct2, k_pq_shared_secret) =
97+ c_pk2. encapsulate ( & mut OsRng ) . map_err ( |_| Error :: KexInit ) ?;
9698
9799 let s_secret = Scalar :: from_bytes_mod_order ( rand:: random :: < [ u8 ; 32 ] > ( ) ) ;
98100 let s_pk1 = ( ED25519_BASEPOINT_TABLE * & s_secret) . to_montgomery ( ) ;
99101
100102 let k_cl = s_secret * c_pk1;
101103
102104 exchange. server_ephemeral . clear ( ) ;
103- exchange. server_ephemeral . extend_from_slice ( s_ct2. as_slice ( ) ) ;
105+ exchange
106+ . server_ephemeral
107+ . extend_from_slice ( s_ct2. as_slice ( ) ) ;
104108 exchange. server_ephemeral . extend_from_slice ( & s_pk1. 0 ) ;
105109
106110 self . k_pq = Some ( k_pq_shared_secret) ;
@@ -114,22 +118,18 @@ impl KexAlgorithmImplementor for MlKem768X25519Kex {
114118 client_ephemeral : & mut Vec < u8 > ,
115119 writer : & mut impl Writer ,
116120 ) -> Result < ( ) , Error > {
117- let mut randomness = [ 0u8 ; KEY_GENERATION_SEED_SIZE ] ;
118- getrandom:: getrandom ( & mut randomness) . map_err ( |_| Error :: KexInit ) ?;
119-
120- let keypair = generate_key_pair ( randomness) ;
121- let ( mlkem_sk, mlkem_pk) = keypair. into_parts ( ) ;
121+ let ( mlkem_sk, mlkem_pk) = MlKem768 :: generate ( & mut OsRng ) ;
122122
123123 let x25519_secret = Scalar :: from_bytes_mod_order ( rand:: random :: < [ u8 ; 32 ] > ( ) ) ;
124124 let x25519_pk = ( ED25519_BASEPOINT_TABLE * & x25519_secret) . to_montgomery ( ) ;
125125
126126 client_ephemeral. clear ( ) ;
127- client_ephemeral. extend_from_slice ( mlkem_pk. as_slice ( ) ) ;
128- client_ephemeral. extend_from_slice ( & x25519_pk. 0 ) ;
127+ client_ephemeral. extend ( & mlkem_pk. as_bytes ( ) ) ;
128+ client_ephemeral. extend ( & x25519_pk. 0 ) ;
129129
130130 msg:: KEX_HYBRID_INIT . encode ( writer) ?;
131131 let mut c_init = Vec :: < u8 > :: new ( ) ;
132- c_init. extend ( mlkem_pk. as_slice ( ) ) ;
132+ c_init. extend ( mlkem_pk. as_bytes ( ) ) ;
133133 c_init. extend ( & x25519_pk. 0 ) ;
134134 c_init. as_slice ( ) . encode ( writer) ?;
135135
@@ -149,12 +149,12 @@ impl KexAlgorithmImplementor for MlKem768X25519Kex {
149149 #[ allow( clippy:: indexing_slicing) ]
150150 let s_pk1_bytes = & remote_pubkey_[ MLKEM768_CIPHERTEXT_SIZE ..] ;
151151
152- let mut s_ct2_array = [ 0u8 ; MLKEM768_CIPHERTEXT_SIZE ] ;
153- s_ct2_array. copy_from_slice ( s_ct2_bytes) ;
154- let s_ct2 = MlKem768Ciphertext :: from ( s_ct2_array) ;
152+ let s_ct2 = MlKem768Ciphertext :: try_from ( s_ct2_bytes) . map_err ( |_| Error :: KexInit ) ?;
155153
156154 let mlkem_secret = self . mlkem_secret . take ( ) . ok_or ( Error :: KexInit ) ?;
157- let k_pq_shared_secret = decapsulate ( & mlkem_secret, & s_ct2) ;
155+ let k_pq_shared_secret = mlkem_secret
156+ . decapsulate ( & s_ct2)
157+ . map_err ( |_| Error :: KexInit ) ?;
158158
159159 let mut s_pk1 = MontgomeryPoint ( [ 0 ; 32 ] ) ;
160160 s_pk1. 0 . copy_from_slice ( s_pk1_bytes) ;
@@ -366,8 +366,7 @@ mod tests {
366366 . unwrap ( ) ;
367367
368368 assert_eq ! (
369- client_hash,
370- server_hash,
369+ client_hash, server_hash,
371370 "Exchange hashes should match between client and server"
372371 ) ;
373372 assert_eq ! ( client_hash. len( ) , 32 , "SHA-256 hash should be 32 bytes" ) ;
0 commit comments