Closed DorianCoding closed 6 months ago
I can have a look at it later tomorrow if need be but from initial inspection it is perhaps in novel C implementation of the AKE?
Could you give a try with the kyber reference AKE functions instead? https://github.com/pq-crystals/kyber/blob/main/ref/kex.c
I'm not a fan of the current AKE and UAKE structs, they are inefficient and clunky, but will certainly investigate to make sure of interop if it doesn't work with those.
Actually my mistake, the AKE struct isn't being used at all here.
Can you reduce it to a Minimum Reproducible Example without all the extra parts and we can go from there?
Thanks.
Hello and first of all thanks for your help.
Sure I'II try this evening. I have redefined the C code too as there were some mistakes when converting. Now I have a C code that extracts correctly everything from Rust but still fails (I have changed the C code to indicate the fail so the use of cmov but should not be an issue). It explains why I don't have an error that I was expecting (it's the spec AFAIK). I'm reducing the code and sending you ASAP. I've investigated the code of both libraries yesterday but have not found anything that could explain it.
First, please execute the following rust code (add hex that is not present in this crate), I use the following Cargo.toml :
[package]
name = "kyber"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
hex = "0.4.3"
rand = "0.8.5"
[target.'cfg(target_arch = "x86_64")'.dependencies]
#pqc_kyber = { version = "0.7.1", features = ["std", "kyber1024", "avx", "zeroize", "benchmarking"] }
pqc_kyber = { version = "0.7.1", features = ["std", "kyber1024", "zeroize", "benchmarking"] }
[target.'cfg(not(target_arch = "x86_64"))'.dependencies]
pqc_kyber = { version = "0.7.1", features = ["std", "kyber1024", "zeroize", "benchmarking"] }
The following test was done with avx disabled.
use hex::{self, decode, FromHexError};
use pqc_kyber::*;
use rand;
use std::fs::{self, File};
use std::io::{Error, Write};
#[cfg(target_family = "unix")]
use std::os::unix::fs::PermissionsExt;
fn encodehex(data: &[u8]) -> String {
hex::encode(data)
}
fn main() -> Result<(), KyberError> {
let mut rng = rand::thread_rng();
let keys_bob = keypair(&mut rng)?;
fs::write("bobpublickey.pem", &keys_bob.public);
fs::write("bobsecretkey.pem", &keys_bob.secret);
let (ciphertext, shared_secret_alice) = encapsulate(&keys_bob.public, &mut rng)?;
let _ = fs::write("cipher.pem", &ciphertext).unwrap();
println!("Shared secret is {}", hex::encode(shared_secret_alice));
return Ok(());
}
Then, use the three created files to get the same shared secret from C library in ref folder (not avx but I can try and activate it in Rust too) : I compile as follows :
cc -Wall -Wextra -Wpedantic -Wmissing-prototypes -Wredundant-decls -Wshadow -Wpointer-arith -O3 -fomit-frame-pointer -DKYBER_K=4 kex.c kem.c indcpa.c polyvec.c poly.c ntt.c cbd.c reduce.c verify.c fips202.c symmetric-shake.c randombytes.c test.c -o testing
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "kem.h"
#include <fcntl.h>
#include <sys/stat.h>
#include "randombytes.h"
#include <string.h>
#include <errno.h>
int main(void)
{
unsigned int j;
uint8_t pk[CRYPTO_PUBLICKEYBYTES + 1] = {0};
uint8_t sk[CRYPTO_SECRETKEYBYTES + 1] = {0};
uint8_t ct[CRYPTO_CIPHERTEXTBYTES + 1] = {0};
uint8_t key_a[CRYPTO_BYTES + 1] = {0}; // Null terminated (does not change anything without anyway)
FILE *skey;
FILE *pkey;
FILE *cipher;
mode_t umode;
//Read files created by Rust
pkey = fopen("bobpublickey.pem", "rb");
if (fread(pk, sizeof(pk[0]), CRYPTO_PUBLICKEYBYTES, pkey) != CRYPTO_PUBLICKEYBYTES)
{
fprintf(stderr, "Cannot extract public key.\n");
exit(EXIT_FAILURE);
}
fclose(pkey);
skey = fopen("bobsecretkey.pem", "rb");
if (fread(sk, sizeof(sk[0]), CRYPTO_SECRETKEYBYTES, skey) != CRYPTO_SECRETKEYBYTES)
{
fprintf(stderr, "Cannot extract secret key\n");
exit(EXIT_FAILURE);
}
fclose(skey);
cipher = fopen("cipher.pem", "rb");
if (fread(ct, sizeof(ct[0]), CRYPTO_CIPHERTEXTBYTES, cipher) != CRYPTO_CIPHERTEXTBYTES)
{
fprintf(stderr, "Cannot extract cipher\n");
exit(EXIT_FAILURE);
}
fclose(cipher);
crypto_kem_dec(key_a, ct, sk);
for (j = 0; j < CRYPTO_BYTES; j++)
printf("%02x", key_a[j]);
return 0;
}
I don't achieve to get the same and I get a Fail: 1 (from verify.c that I have edited). I have tried the opposite (generation from C and test from Rust) but unfortunately, I don't achieve to make it work :/ Of course, Rust alone or C alone works well. Maybe there is features different between the both... I don't know if it could matter.
Hello,
I'm sorry. It seems 90-fixslice was activated on the C compilation and therefore result was therefore different. Setting same option solves the problem for unauthentificated and UAKE handshake (I did not try AKE).
Sorry.
Hello,
Sorry if I'm doing something wrong but I have some inconsistent. And if I was indeed doing wrong, I'm wondering why it would not give an error...
Let's say Bob and Alice uses Kyber in Rust and C respectively because they are purist. Bob uses this code after the first part of Alice one (it was for convenient) :
Bob shares its key to Alice (just to test, we don't do that in real life) so she can try her Rust code :
However at the end, the shared secret is different :
I don't know if I'm doing something wrong or if the implementation has some issues but the shared secret should be the same using same keys and same cipher.