packages feed

crypton-2.1.8: cbits/tests/ct/ct_mlkem.c

/* ML-KEM-768, which is the parameter set TLS uses.  The seed and the
 * decapsulation key are secret; the encapsulation key and the ciphertext are
 * published, and the shared secret is the answer the caller asked for.
 *
 * mlkem-native's AArch64 and x86-64 assembly carries a HOL-Light proof of
 * secret-independent timing, so a report from the backend build means the
 * proof does not cover what crypton built, or that crypton reached it
 * wrongly.  The portable C has no such proof, which is the reason to ask it
 * the question at all. */
#include "tests/ct/ct.h"

int crypton_mlkem768_keypair_derand(uint8_t *pk, uint8_t *sk,
                                    const uint8_t *coins);
int crypton_mlkem768_enc_derand(uint8_t *ct, uint8_t *ss, const uint8_t *pk,
                                const uint8_t *coins);
int crypton_mlkem768_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk);

int main(void) {
    uint8_t pk[1184], sk[2400], ct[1088], ss[32], ss2[32];
    uint8_t kcoins[64], ecoins[32];

    ct_fill(kcoins, sizeof kcoins);
    ct_fill(ecoins, sizeof ecoins);

    CT_SECRET(kcoins, sizeof kcoins);
    if (crypton_mlkem768_keypair_derand(pk, sk, kcoins) != 0) return 1;
    CT_PUBLIC(pk, sizeof pk);
    ct_sink(pk, sizeof pk);

    /* The message encapsulation draws is as secret as the key it derives. */
    CT_SECRET(ecoins, sizeof ecoins);
    if (crypton_mlkem768_enc_derand(ct, ss, pk, ecoins) != 0) return 1;
    CT_PUBLIC(ct, sizeof ct);
    CT_PUBLIC(ss, sizeof ss);
    ct_sink(ct, sizeof ct);
    ct_sink(ss, sizeof ss);

    /* sk is still undefined here: decapsulation is the half that runs on the
     * long-lived secret, and the half an attacker can drive by sending
     * ciphertexts of their choosing. */
    if (crypton_mlkem768_dec(ss2, ct, sk) != 0) return 1;
    CT_PUBLIC(ss2, sizeof ss2);
    ct_sink(ss2, sizeof ss2);
    return 0;
}