From 408136a45a839a2f4226613b1e5a49684d3859ab Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Wed, 28 Oct 2026 20:56:01 -0600 Subject: [PATCH] ml-kem: add `cargo checkct` driver for decapsulation --- ml-kem/checkct/driver/src/driver.rs | 27 ++++++++++++++++++ ml-kem/checkct/driver/src/fixtures/ek1024.bin | Bin 0 -> 1600 bytes ml-kem/checkct/driver/src/fixtures/ek512.bin | Bin 0 -> 832 bytes ml-kem/checkct/driver/src/fixtures/ek768.bin | Bin 0 -> 1216 bytes 4 files changed, 27 insertions(+) create mode 100644 ml-kem/checkct/driver/src/fixtures/ek1024.bin create mode 100644 ml-kem/checkct/driver/src/fixtures/ek512.bin create mode 100644 ml-kem/checkct/driver/src/fixtures/ek768.bin diff --git a/ml-kem/checkct/driver/src/driver.rs b/ml-kem/checkct/driver/src/driver.rs index cfe860e..742af35 100644 --- a/ml-kem/checkct/driver/src/driver.rs +++ b/ml-kem/checkct/driver/src/driver.rs @@ -40,3 +40,30 @@ pub fn small_reduce_u32() { black_box(PublicRng.next_u32()); black_box(DilithiumField::small_reduce(PrivateRng.next_u32())); } + +// Public key and H(ek) are concrete; s_hat and z are independent secrets. +// Expanded-key import avoids treating key generation's public rho as secret. +macro_rules! check_decapsulation { + ($name:ident, $kem:ident, $sk_len:expr, $fixture:literal) => { + #[checkct] + #[allow(deprecated)] + pub fn $name() { + use ml_kem::{Ciphertext, Decapsulate, DecapsulationKey, ExpandedDecapsulationKey}; + + let public = include_bytes!($fixture); + let mut expanded = ExpandedDecapsulationKey::::default(); + PrivateRng.fill_bytes(&mut expanded[..$sk_len]); + expanded[$sk_len..$sk_len + public.len()].copy_from_slice(public); + PrivateRng.fill_bytes(&mut expanded[$sk_len + public.len()..]); + let dk = DecapsulationKey::::from_expanded(&expanded).unwrap(); + + let mut ct = Ciphertext::::default(); + PublicRng.fill_bytes(&mut ct); + black_box(dk.decapsulate(&ct)); + } + }; +} + +check_decapsulation!(decapsulate_512, MlKem512, 768, "fixtures/ek512.bin"); +check_decapsulation!(decapsulate_768, MlKem768, 1152, "fixtures/ek768.bin"); +check_decapsulation!(decapsulate_1024, MlKem1024, 1536, "fixtures/ek1024.bin"); diff --git a/ml-kem/checkct/driver/src/fixtures/ek1024.bin b/ml-kem/checkct/driver/src/fixtures/ek1024.bin new file mode 100644 index 0000000000000000000000000000000000000000..780ab93d7eb7f2f4c11e9dc0b81494c5ce6956a9 GIT binary patch literal 1600 zcmV-G2EX~BL4?%2ds8Y8aHUOmSIy=ZT4+PKVaqGTgA4!?RZRR{EQ%l}syx|e6Aqh} zBpVULG7NS}%p<28ujY}jz>a7O&h#k<00$W4>duX#f)p8h;lgR!oV7vWqt2Jlt@*|U zhk*WPliT`&7@~FyfGdrnswWyacO@gIXEvv!8=WvWts&045u|dsc`mVaSh+yw2!rxu zSuALqBnz}XR0zLBWHR&;^tq+>hFro@q&)NrG6RuSRgu$wMn>q-mGgH+Y zVH2w_r5%@6NbV&{_?jaH1fn*iWrA093*5WmaEh=Z!^McC5ZgPPFp35zTi;tqS<|9n zdMRESBKZNBy3iJHN|ZDg#ketZY_iB$3cuc06t#w{?!cjSpo_;4$D)Z{={m$X1{?Qw zT@4}4L4jw=_?;g7G)TO=me!j-0StoCT&rxX#(AAKIcAz$A*M6PW%yY;TYJa=CM&o% zsU)VwL=I2KJ3+EAlEaZNOl#}3$F#;N2(UMGW^5uN4f)83BjZHJFoQBQT#I>KH0Z!l z@*i3u!W6ccK{ba7vBL$kEW*QpYU#|=fuH|H2mVqIzrt~uyd%DAn=LBAadmmDc9MDG zr>e$^HyTH}I(@zYZxrFDCo?u<#HGy|4~RC;dt6DZQAk{-14YS@;An_)00VOqBE`7P zUTFvYp%s5dkJJ1h`hj)s$y_NKCM&4LzL^MeL5VPhBRSZL8MA-yqtECeb;2Y-e54e* z>o<}+O)Y~HO5s%Gkg2p<1!J&ml{_;6MG7HypnPFUbmK>kNKl`eV6K!}j=Xpk5*?7E zu;6f!pq9@9#d{^ZrGX}`3}T$&W~c46voax|)AuWd)ne>vi+u`_J#&C>99)O9j=%%U zFgiWO8%s4cYG;CNZrZ5+xjUFiJ1ra$wsxkil?I`zt`n#v$H0voY%EQ>mO{sFr}oGu zOJt%v%&DhFHT=H=;13&DBC-@WXOMY2EKdp(wZsQtv>}ciC6wH=3UJxMcq(1f1$O#D zM8C*EZrXtu{A6);#8IFr=jYTG3VI&>G%aEybZV6M9NeS?& z0$aC7Aa|SOKNi>=jK*f^mk`*-i?z&767v-4C8bgDoW+m>q4|4&k3&6QC9pF%ODF%oAYEzPD7E~xq*~rX3x`69DW-hfpw^0^wN+0W7Ed^sZ zQz&TN@=my!D!5i%o=FU?@kj(V4XTiFj;mp7s|RJ%Ift}<`(>HMRx&l_9!utM>3LPF zDJ_>W%ZV_QipVYUFsyPZdLw6@Ym~u%6InC~{IqV1}x1{3Ykc?ARic}3X18Mpg zoMCB0_m~}a7|#Nwu%f)gBIsAqq9JqRg092c9-z(a6p5Of$IU)z{gVmpkcwv@?i z2um07JGS2vvd_E1u;9Z>0MPuXW8`P}}wj@a)$B literal 0 HcmV?d00001 diff --git a/ml-kem/checkct/driver/src/fixtures/ek512.bin b/ml-kem/checkct/driver/src/fixtures/ek512.bin new file mode 100644 index 0000000000000000000000000000000000000000..960960a869795e9d3932e5aed3fdd0fe5cd5fbf8 GIT binary patch literal 832 zcmV-G1Hb&EBsut6JR#B=ak;rFn`G(=xI+@ha3g6?)=sLq2c$JQ-LiY2s8h_4Y3j&O zjAcGx3o5`EI2%i}sClf~(?aQdq86RWtDx z$F*3tP}>C6qHe07j6UUk|M5!R+7GnF@lj3pLnlpT<s~HF1N%xC#*ffNy-eor2ANxz_&yQ zii!t$(;_p1Y60D3iIplyCFM1Wa0}q!d8`?C5ZFGZ^ z)Pt~en-RS?vxD5qarp@tG@)r#0>rsr$q|ek{4~f+B4xY0Ry-&sX0{6D$Mc09CG5LU zAhKO10>*Pn*y}rD0Wj9WxXA>gyORgLQ3Lqc6i{EbrV96y Kex}Ny7cpLGRFy6O literal 0 HcmV?d00001 diff --git a/ml-kem/checkct/driver/src/fixtures/ek768.bin b/ml-kem/checkct/driver/src/fixtures/ek768.bin new file mode 100644 index 0000000000000000000000000000000000000000..3e37a45f39e868b85db6ca84ea5713b673515066 GIT binary patch literal 1216 zcmV;x1V8(26rgeU%ta+w)#n;}2ykNTu{dZ%Sb|0pWCF4J7B_P|)%Fa?OUqgF zd{ME-@uGQ=GVwGg+(;o<+9gDArJew!S z*1J*j5>J?$pw&Qg%p@)eXm|^UT85tcg%yUmsA!{vx#of!ARCh`MN?^~IqV`xW&fi_mJTULJfleL6mOolookO1*}B}$Zy|LqgzPP30gGTaFMju|r^! ztmn>-akN;~C1*2Z1X?>j>XcPNiaCb`q$4M-vv*5ySM)0Ze!z2@m_HflAx#MxU!qMd zR~@%J8K(F~4p4&)L0@8fi0Mju6*rNfz{lxGOmx*eaY%{q;~}_yf&LAtQv`J!@`G9)cyB;$vZ-64Qp^W|1s3kDA z)9?qwH8_~rX3Q)h%R)rG07O3^m~gDbE5k5o$0Y0*A~qSp2|UVb>nTtMWYHo}Hng}9 zk&tO=NFN+>JQNF^Y!;7OWWJ`HU)DHX_clw1BfQ971B`w~N{|g`q7rx*nL-z?$i1_g zmkOC<-jisKD#$9l!Y{ced!ir-=y*69I2Jhp$JEGB8B>il%C4M2uZ)tO;tQ~hrWxlf zFCt>W$&-b0RT{u8$tI7y!(Dj+96SjM)Cx}#9Gm4_LVmZF!ILe9b61-2w8l8FlthUE zDkWK?uq1)78p8{ymJfiy!n2fpHlZvC1em_$NO5eJG#1DtC-qeZuAf+&Lf%_7-9`RiDu+ zV2LX06+PBbyGEH1w6jKO`5mZbO&+%{w%{lLv#_Voq>O`TRMV(FWmcTGBMY=oKNLD` z>|ZQ7tB~?^@(7F5)~5WR2Lf}x+=O?3wJtnWiwfXjgVm&sMK5UKQU~~9VtUFHCzdey zF2kV82Zl4Y0I#Q)L#6;BTjgVPSk5fyul1mgwE=r9c4c=*pN+=9pIpaKiIX8=xoqk{ zW+1NHV+05HXnwo2flPUUV|qxb4d#F`;9{q*b`rGp$EMnby%S|A=0cUFVLqoj)6_(a zxE~}jHNd7|zPZ7EWgYKEnthO=T{M9S3(N8+0V61sAEa+N#Q