tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

kyber.c (12485B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #ifdef FREEBL_NO_DEPEND
      6 #include "stubs.h"
      7 #endif
      8 
      9 #include <stdbool.h>
     10 
     11 #include "blapi.h"
     12 #include "secerr.h"
     13 #include "secitem.h"
     14 
     15 #include "kyber-pqcrystals-ref.h"
     16 #include "kyber.h"
     17 #include "verified/internal/libcrux_core.h"
     18 #include "verified/libcrux_mlkem768_portable.h"
     19 #include "verified/libcrux_mlkem768.h"
     20 #include "verified/libcrux_mlkem1024_portable.h"
     21 #include "verified/libcrux_mlkem1024.h"
     22 
     23 /* Consistency check between kyber-pqcrystals-ref.h and kyber.h */
     24 PR_STATIC_ASSERT(KYBER768_PUBLIC_KEY_BYTES == pqcrystals_kyber768_PUBLICKEYBYTES);
     25 PR_STATIC_ASSERT(KYBER768_PRIVATE_KEY_BYTES == pqcrystals_kyber768_SECRETKEYBYTES);
     26 PR_STATIC_ASSERT(KYBER768_CIPHERTEXT_BYTES == pqcrystals_kyber768_CIPHERTEXTBYTES);
     27 PR_STATIC_ASSERT(KYBER_SHARED_SECRET_BYTES == pqcrystals_kyber768_BYTES);
     28 PR_STATIC_ASSERT(KYBER_KEYPAIR_COIN_BYTES == pqcrystals_kyber768_KEYPAIRCOINBYTES);
     29 PR_STATIC_ASSERT(KYBER_ENC_COIN_BYTES == pqcrystals_kyber768_ENCCOINBYTES);
     30 
     31 /* Consistency check between libcrux_mlkem768_portable.h and kyber.h */
     32 PR_STATIC_ASSERT(KYBER768_PUBLIC_KEY_BYTES == LIBCRUX_ML_KEM_MLKEM768_CPA_PKE_PUBLIC_KEY_SIZE);
     33 PR_STATIC_ASSERT(KYBER768_PRIVATE_KEY_BYTES == LIBCRUX_ML_KEM_MLKEM768_SECRET_KEY_SIZE);
     34 PR_STATIC_ASSERT(KYBER768_CIPHERTEXT_BYTES == LIBCRUX_ML_KEM_MLKEM768_CPA_PKE_CIPHERTEXT_SIZE);
     35 PR_STATIC_ASSERT(KYBER_SHARED_SECRET_BYTES == LIBCRUX_ML_KEM_CONSTANTS_SHARED_SECRET_SIZE);
     36 PR_STATIC_ASSERT(KYBER_KEYPAIR_COIN_BYTES == 64);
     37 PR_STATIC_ASSERT(KYBER_ENC_COIN_BYTES == 32);
     38 
     39 /* Consistency check between libcrux_mlkem1024_portable.h and kyber.h */
     40 PR_STATIC_ASSERT(MLKEM1024_PUBLIC_KEY_BYTES == LIBCRUX_ML_KEM_MLKEM1024_CPA_PKE_PUBLIC_KEY_SIZE);
     41 PR_STATIC_ASSERT(MLKEM1024_PRIVATE_KEY_BYTES == LIBCRUX_ML_KEM_MLKEM1024_SECRET_KEY_SIZE);
     42 PR_STATIC_ASSERT(MLKEM1024_CIPHERTEXT_BYTES == LIBCRUX_ML_KEM_MLKEM1024_CPA_PKE_CIPHERTEXT_SIZE);
     43 
     44 static bool
     45 valid_params(KyberParams params)
     46 {
     47    switch (params) {
     48 #ifndef NSS_DISABLE_KYBER
     49        case params_kyber768_round3:
     50        case params_kyber768_round3_test_mode:
     51 #endif
     52        case params_ml_kem768:
     53        case params_ml_kem768_test_mode:
     54        case params_ml_kem1024:
     55        case params_ml_kem1024_test_mode:
     56            return true;
     57        default:
     58            return false;
     59    }
     60 }
     61 
     62 static bool
     63 valid_pubkey(KyberParams params, const SECItem *pubkey)
     64 {
     65    switch (params) {
     66        case params_kyber768_round3:
     67        case params_kyber768_round3_test_mode:
     68        case params_ml_kem768:
     69        case params_ml_kem768_test_mode:
     70            return pubkey && pubkey->len == KYBER768_PUBLIC_KEY_BYTES;
     71        case params_ml_kem1024:
     72        case params_ml_kem1024_test_mode:
     73            return pubkey && pubkey->len == MLKEM1024_PUBLIC_KEY_BYTES;
     74        default:
     75            return false;
     76    }
     77 }
     78 
     79 static bool
     80 valid_privkey(KyberParams params, const SECItem *privkey)
     81 {
     82    switch (params) {
     83        case params_kyber768_round3:
     84        case params_kyber768_round3_test_mode:
     85        case params_ml_kem768:
     86        case params_ml_kem768_test_mode:
     87            return privkey && privkey->len == KYBER768_PRIVATE_KEY_BYTES;
     88        case params_ml_kem1024:
     89        case params_ml_kem1024_test_mode:
     90            return privkey && privkey->len == MLKEM1024_PRIVATE_KEY_BYTES;
     91        default:
     92            return false;
     93    }
     94 }
     95 
     96 static bool
     97 valid_ciphertext(KyberParams params, const SECItem *ciphertext)
     98 {
     99    switch (params) {
    100        case params_kyber768_round3:
    101        case params_kyber768_round3_test_mode:
    102        case params_ml_kem768:
    103        case params_ml_kem768_test_mode:
    104            return ciphertext && ciphertext->len == KYBER768_CIPHERTEXT_BYTES;
    105        case params_ml_kem1024:
    106        case params_ml_kem1024_test_mode:
    107            return ciphertext && ciphertext->len == MLKEM1024_CIPHERTEXT_BYTES;
    108        default:
    109            return false;
    110    }
    111 }
    112 
    113 static bool
    114 valid_secret(KyberParams params, const SECItem *secret)
    115 {
    116    switch (params) {
    117        case params_kyber768_round3:
    118        case params_kyber768_round3_test_mode:
    119        case params_ml_kem768:
    120        case params_ml_kem768_test_mode:
    121        case params_ml_kem1024:
    122        case params_ml_kem1024_test_mode:
    123            return secret && secret->len == KYBER_SHARED_SECRET_BYTES;
    124        default:
    125            return false;
    126    }
    127 }
    128 
    129 static bool
    130 valid_keypair_seed(KyberParams params, const SECItem *seed)
    131 {
    132    switch (params) {
    133        case params_kyber768_round3:
    134        case params_kyber768_round3_test_mode:
    135        case params_ml_kem768:
    136        case params_ml_kem768_test_mode:
    137        case params_ml_kem1024:
    138        case params_ml_kem1024_test_mode:
    139            return !seed || seed->len == KYBER_KEYPAIR_COIN_BYTES;
    140        default:
    141            return false;
    142    }
    143 }
    144 
    145 static bool
    146 valid_enc_seed(KyberParams params, const SECItem *seed)
    147 {
    148    switch (params) {
    149        case params_kyber768_round3:
    150        case params_ml_kem768:
    151            return !seed;
    152        case params_kyber768_round3_test_mode:
    153        case params_ml_kem768_test_mode:
    154        case params_ml_kem1024:
    155        case params_ml_kem1024_test_mode:
    156            return !seed || seed->len == KYBER_SHARED_SECRET_BYTES;
    157        default:
    158            return false;
    159    }
    160 }
    161 
    162 SECStatus
    163 Kyber_NewKey(KyberParams params, const SECItem *keypair_seed, SECItem *privkey, SECItem *pubkey)
    164 {
    165    if (!valid_params(params)) {
    166        PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
    167        return SECFailure;
    168    }
    169 
    170    if (!(valid_keypair_seed(params, keypair_seed) && valid_privkey(params, privkey) && valid_pubkey(params, pubkey))) {
    171        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    172        return SECFailure;
    173    }
    174 
    175    uint8_t randbuf[KYBER_KEYPAIR_COIN_BYTES];
    176    uint8_t *coins;
    177    if (keypair_seed) {
    178        coins = keypair_seed->data;
    179    } else {
    180        if (RNG_GenerateGlobalRandomBytes(randbuf, sizeof randbuf) != SECSuccess) {
    181            PORT_SetError(SEC_ERROR_NEED_RANDOM);
    182            return SECFailure;
    183        }
    184        coins = randbuf;
    185    }
    186    NSS_CLASSIFY(coins, KYBER_KEYPAIR_COIN_BYTES);
    187    if (params == params_ml_kem768 || params == params_ml_kem768_test_mode) {
    188        libcrux_ml_kem_mlkem768_MlKem768KeyPair keys = libcrux_ml_kem_mlkem768_portable_generate_key_pair(coins);
    189        memcpy(pubkey->data, keys.pk.value, KYBER768_PUBLIC_KEY_BYTES);
    190        memcpy(privkey->data, keys.sk.value, KYBER768_PRIVATE_KEY_BYTES);
    191    } else if (params == params_ml_kem1024 || params == params_ml_kem1024_test_mode) {
    192        libcrux_ml_kem_mlkem1024_MlKem1024KeyPair keys = libcrux_ml_kem_mlkem1024_portable_generate_key_pair(coins);
    193        memcpy(pubkey->data, keys.pk.value, MLKEM1024_PUBLIC_KEY_BYTES);
    194        memcpy(privkey->data, keys.sk.value, MLKEM1024_PRIVATE_KEY_BYTES);
    195    } else if (params == params_kyber768_round3 || params == params_kyber768_round3_test_mode) {
    196 #ifdef NSS_DISABLE_KYBER
    197        PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
    198        return SECFailure;
    199 #else
    200        pqcrystals_kyber768_ref_keypair_derand(pubkey->data, privkey->data, coins);
    201 #endif
    202    } else {
    203        /* unreachable */
    204        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
    205        return SECFailure;
    206    }
    207    NSS_DECLASSIFY(pubkey->data, pubkey->len);
    208    return SECSuccess;
    209 }
    210 
    211 SECStatus
    212 Kyber_Encapsulate(KyberParams params, const SECItem *enc_seed, const SECItem *pubkey, SECItem *ciphertext, SECItem *secret)
    213 {
    214    if (!valid_params(params)) {
    215        PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
    216        return SECFailure;
    217    }
    218 
    219    if (!(valid_enc_seed(params, enc_seed) && valid_pubkey(params, pubkey) && valid_ciphertext(params, ciphertext) && valid_secret(params, secret))) {
    220        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    221        return SECFailure;
    222    }
    223 
    224    uint8_t randbuf[KYBER_ENC_COIN_BYTES];
    225    uint8_t *coins;
    226    if (enc_seed) {
    227        coins = enc_seed->data;
    228    } else {
    229        if (RNG_GenerateGlobalRandomBytes(randbuf, sizeof randbuf) != SECSuccess) {
    230            PORT_SetError(SEC_ERROR_NEED_RANDOM);
    231            return SECFailure;
    232        }
    233        coins = randbuf;
    234    }
    235    NSS_CLASSIFY(coins, KYBER_ENC_COIN_BYTES);
    236    if (params == params_ml_kem768 || params == params_ml_kem768_test_mode) {
    237        /* shouldn't this just use the typedef im libcrux_mlkem768.h? */
    238        libcrux_ml_kem_mlkem768_MlKem768PublicKey pk_value;
    239        memcpy(pk_value.value, pubkey->data, KYBER768_PUBLIC_KEY_BYTES);
    240 
    241        bool valid_pk = libcrux_ml_kem_mlkem768_portable_validate_public_key(&pk_value);
    242        if (!valid_pk) {
    243            PORT_SetError(SEC_ERROR_INVALID_ARGS);
    244            return SECFailure;
    245        }
    246 
    247        tuple_c2 encap = libcrux_ml_kem_mlkem768_portable_encapsulate(&pk_value, coins);
    248        memcpy(ciphertext->data, encap.fst.value, KYBER768_CIPHERTEXT_BYTES);
    249        memcpy(secret->data, encap.snd, KYBER_SHARED_SECRET_BYTES);
    250    } else if (params == params_ml_kem1024 || params == params_ml_kem1024_test_mode) {
    251        /* shouldn't this just use the typedef im libcrux_mlkem1024.h? */
    252        libcrux_ml_kem_mlkem1024_MlKem1024PublicKey pk_value;
    253        memcpy(pk_value.value, pubkey->data, MLKEM1024_PUBLIC_KEY_BYTES);
    254 
    255        bool valid_pk = libcrux_ml_kem_mlkem1024_portable_validate_public_key(&pk_value);
    256        if (!valid_pk) {
    257            PORT_SetError(SEC_ERROR_INVALID_ARGS);
    258            return SECFailure;
    259        }
    260 
    261        tuple_fa encap = libcrux_ml_kem_mlkem1024_portable_encapsulate(&pk_value, coins);
    262        memcpy(ciphertext->data, encap.fst.value, MLKEM1024_CIPHERTEXT_BYTES);
    263        memcpy(secret->data, encap.snd, KYBER_SHARED_SECRET_BYTES);
    264    } else if (params == params_kyber768_round3 || params == params_kyber768_round3_test_mode) {
    265 #ifdef NSS_DISABLE_KYBER
    266        PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
    267        return SECFailure;
    268 #else
    269        pqcrystals_kyber768_ref_enc_derand(ciphertext->data, secret->data, pubkey->data, coins);
    270 #endif
    271    } else {
    272        /* unreachable */
    273        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
    274        return SECFailure;
    275    }
    276 
    277    return SECSuccess;
    278 }
    279 
    280 SECStatus
    281 Kyber_Decapsulate(KyberParams params, const SECItem *privkey, const SECItem *ciphertext, SECItem *secret)
    282 {
    283    if (!valid_params(params)) {
    284        PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
    285        return SECFailure;
    286    }
    287 
    288    if (!(valid_privkey(params, privkey) && valid_ciphertext(params, ciphertext) && valid_secret(params, secret))) {
    289        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    290        return SECFailure;
    291    }
    292 
    293    if (params == params_ml_kem768 || params == params_ml_kem768_test_mode) {
    294        libcrux_ml_kem_mlkem768_MlKem768PrivateKey private_key;
    295        memcpy(private_key.value, privkey->data, KYBER768_PRIVATE_KEY_BYTES);
    296 
    297        libcrux_ml_kem_mlkem768_MlKem768Ciphertext cipher_text;
    298        memcpy(cipher_text.value, ciphertext->data, KYBER768_CIPHERTEXT_BYTES);
    299 
    300        bool valid = libcrux_ml_kem_mlkem768_portable_validate_private_key(&private_key, &cipher_text);
    301        if (!valid) {
    302            PORT_SetError(SEC_ERROR_INVALID_ARGS);
    303            return SECFailure;
    304        }
    305 
    306        libcrux_ml_kem_mlkem768_portable_decapsulate(&private_key, &cipher_text, secret->data);
    307    } else if (params == params_ml_kem1024 || params == params_ml_kem1024_test_mode) {
    308        libcrux_ml_kem_mlkem1024_MlKem1024PrivateKey private_key;
    309        memcpy(private_key.value, privkey->data, MLKEM1024_PRIVATE_KEY_BYTES);
    310 
    311        libcrux_ml_kem_mlkem1024_MlKem1024Ciphertext cipher_text;
    312        memcpy(cipher_text.value, ciphertext->data, MLKEM1024_CIPHERTEXT_BYTES);
    313 
    314        bool valid = libcrux_ml_kem_mlkem1024_portable_validate_private_key(&private_key, &cipher_text);
    315        if (!valid) {
    316            PORT_SetError(SEC_ERROR_INVALID_ARGS);
    317            return SECFailure;
    318        }
    319 
    320        libcrux_ml_kem_mlkem1024_portable_decapsulate(&private_key, &cipher_text, secret->data);
    321    } else if (params == params_kyber768_round3 || params == params_kyber768_round3_test_mode) {
    322 #ifdef NSS_DISABLE_KYBER
    323        PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
    324        return SECFailure;
    325 #else
    326        pqcrystals_kyber768_ref_dec(secret->data, ciphertext->data, privkey->data);
    327 #endif
    328    } else {
    329        // unreachable
    330        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
    331        return SECFailure;
    332    }
    333 
    334    return SECSuccess;
    335 }