feat(l1): Integrate real LibOQS (ML-KEM-768)
- Build System: Link against static liboqs.a (built without OpenSSL) - PQXDH: Replace stubs with OQS_KEM_ml_kem_768 functions - Tests: Verify full handshake with real post-quantum KEM - Disable Kyber (old) in liboqs build to fix symbol conflicts
This commit is contained in:
parent
97e1ad3f69
commit
97251137af
|
|
@ -152,6 +152,9 @@ pub fn build(b: *std.Build) void {
|
||||||
.root_module = l1_pqxdh_mod,
|
.root_module = l1_pqxdh_mod,
|
||||||
});
|
});
|
||||||
l1_pqxdh_tests.linkLibC();
|
l1_pqxdh_tests.linkLibC();
|
||||||
|
l1_pqxdh_tests.addIncludePath(b.path("vendor/liboqs/install/include"));
|
||||||
|
l1_pqxdh_tests.addLibraryPath(b.path("vendor/liboqs/install/lib")); // For liboqs.a
|
||||||
|
l1_pqxdh_tests.linkSystemLibrary("oqs");
|
||||||
const run_l1_pqxdh_tests = b.addRunArtifact(l1_pqxdh_tests);
|
const run_l1_pqxdh_tests = b.addRunArtifact(l1_pqxdh_tests);
|
||||||
|
|
||||||
// Link time module to l1_vector_mod
|
// Link time module to l1_vector_mod
|
||||||
|
|
|
||||||
|
|
@ -21,20 +21,20 @@ const crypto = std.crypto;
|
||||||
// FIPS 203: ML-KEM-768 (post-standardization naming for Kyber-768)
|
// FIPS 203: ML-KEM-768 (post-standardization naming for Kyber-768)
|
||||||
|
|
||||||
/// ML-KEM-768 key generation
|
/// ML-KEM-768 key generation
|
||||||
extern "c" fn OQS_KEM_kyber768_keypair(
|
extern "c" fn OQS_KEM_ml_kem_768_keypair(
|
||||||
public_key: ?*u8,
|
public_key: ?*u8,
|
||||||
secret_key: ?*u8,
|
secret_key: ?*u8,
|
||||||
) c_int;
|
) c_int;
|
||||||
|
|
||||||
/// ML-KEM-768 encapsulation (creates shared secret + ciphertext)
|
/// ML-KEM-768 encapsulation (creates shared secret + ciphertext)
|
||||||
extern "c" fn OQS_KEM_kyber768_encaps(
|
extern "c" fn OQS_KEM_ml_kem_768_encaps(
|
||||||
ciphertext: ?*u8,
|
ciphertext: ?*u8,
|
||||||
shared_secret: ?*u8,
|
shared_secret: ?*u8,
|
||||||
public_key: ?*const u8,
|
public_key: ?*const u8,
|
||||||
) c_int;
|
) c_int;
|
||||||
|
|
||||||
/// ML-KEM-768 decapsulation (recovers shared secret from ciphertext)
|
/// ML-KEM-768 decapsulation (recovers shared secret from ciphertext)
|
||||||
extern "c" fn OQS_KEM_kyber768_decaps(
|
extern "c" fn OQS_KEM_ml_kem_768_decaps(
|
||||||
shared_secret: ?*u8,
|
shared_secret: ?*u8,
|
||||||
ciphertext: ?*const u8,
|
ciphertext: ?*const u8,
|
||||||
secret_key: ?*const u8,
|
secret_key: ?*const u8,
|
||||||
|
|
@ -246,7 +246,7 @@ pub fn initiator(
|
||||||
var kem_ct: [ML_KEM_768.CIPHERTEXT_SIZE]u8 = undefined;
|
var kem_ct: [ML_KEM_768.CIPHERTEXT_SIZE]u8 = undefined;
|
||||||
|
|
||||||
// Call liboqs ML-KEM encapsulation
|
// Call liboqs ML-KEM encapsulation
|
||||||
const kem_result = OQS_KEM_kyber768_encaps(
|
const kem_result = OQS_KEM_ml_kem_768_encaps(
|
||||||
@ptrCast(&kem_ct),
|
@ptrCast(&kem_ct),
|
||||||
@ptrCast(&kem_ss),
|
@ptrCast(&kem_ss),
|
||||||
@ptrCast(&bob_prekey_bundle.signed_prekey_mlkem),
|
@ptrCast(&bob_prekey_bundle.signed_prekey_mlkem),
|
||||||
|
|
@ -332,7 +332,7 @@ pub fn responder(
|
||||||
var kem_ss: [ML_KEM_768.SHARED_SECRET_SIZE]u8 = undefined;
|
var kem_ss: [ML_KEM_768.SHARED_SECRET_SIZE]u8 = undefined;
|
||||||
|
|
||||||
// Call liboqs ML-KEM decapsulation
|
// Call liboqs ML-KEM decapsulation
|
||||||
const kem_result = OQS_KEM_kyber768_decaps(
|
const kem_result = OQS_KEM_ml_kem_768_decaps(
|
||||||
@ptrCast(&kem_ss),
|
@ptrCast(&kem_ss),
|
||||||
@ptrCast(&alice_initial_message.mlkem_ciphertext),
|
@ptrCast(&alice_initial_message.mlkem_ciphertext),
|
||||||
@ptrCast(&bob_mlkem_private),
|
@ptrCast(&bob_mlkem_private),
|
||||||
|
|
|
||||||
|
|
@ -9,60 +9,12 @@ const pqxdh = @import("pqxdh.zig");
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// STUB: ML-KEM-768 Functions (for testing without liboqs)
|
// Real LibOQS Functions (via C Import)
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// These will be replaced with real liboqs FFI once library is built
|
|
||||||
|
|
||||||
export fn OQS_KEM_kyber768_keypair(
|
const c = @cImport({
|
||||||
public_key: ?*u8,
|
@cInclude("oqs/oqs.h");
|
||||||
secret_key: ?*u8,
|
});
|
||||||
) c_int {
|
|
||||||
// Stub: Fill with deterministic test data
|
|
||||||
if (public_key) |pk| {
|
|
||||||
const pk_slice: [*]u8 = @ptrCast(pk);
|
|
||||||
@memset(pk_slice[0..pqxdh.ML_KEM_768.PUBLIC_KEY_SIZE], 0xAA);
|
|
||||||
}
|
|
||||||
if (secret_key) |sk| {
|
|
||||||
const sk_slice: [*]u8 = @ptrCast(sk);
|
|
||||||
@memset(sk_slice[0..pqxdh.ML_KEM_768.SECRET_KEY_SIZE], 0xBB);
|
|
||||||
}
|
|
||||||
return 0; // Success
|
|
||||||
}
|
|
||||||
|
|
||||||
export fn OQS_KEM_kyber768_encaps(
|
|
||||||
ciphertext: ?*u8,
|
|
||||||
shared_secret: ?*u8,
|
|
||||||
public_key: ?*const u8,
|
|
||||||
) c_int {
|
|
||||||
_ = public_key; // Use in real impl
|
|
||||||
|
|
||||||
// Stub: Generate deterministic shared secret + ciphertext
|
|
||||||
if (ciphertext) |ct| {
|
|
||||||
const ct_slice: [*]u8 = @ptrCast(ct);
|
|
||||||
@memset(ct_slice[0..pqxdh.ML_KEM_768.CIPHERTEXT_SIZE], 0xCC);
|
|
||||||
}
|
|
||||||
if (shared_secret) |ss| {
|
|
||||||
const ss_slice: [*]u8 = @ptrCast(ss);
|
|
||||||
@memset(ss_slice[0..pqxdh.ML_KEM_768.SHARED_SECRET_SIZE], 0xDD);
|
|
||||||
}
|
|
||||||
return 0; // Success
|
|
||||||
}
|
|
||||||
|
|
||||||
export fn OQS_KEM_kyber768_decaps(
|
|
||||||
shared_secret: ?*u8,
|
|
||||||
ciphertext: ?*const u8,
|
|
||||||
secret_key: ?*const u8,
|
|
||||||
) c_int {
|
|
||||||
_ = ciphertext; // Use in real impl
|
|
||||||
_ = secret_key; // Use in real impl
|
|
||||||
|
|
||||||
// Stub: Must return SAME shared secret as encaps for protocol to work
|
|
||||||
if (shared_secret) |ss| {
|
|
||||||
const ss_slice: [*]u8 = @ptrCast(ss);
|
|
||||||
@memset(ss_slice[0..pqxdh.ML_KEM_768.SHARED_SECRET_SIZE], 0xDD);
|
|
||||||
}
|
|
||||||
return 0; // Success
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Helper: Generate Test Keypairs
|
// Helper: Generate Test Keypairs
|
||||||
|
|
@ -132,7 +84,7 @@ test "PQXDHInitialMessage serialization roundtrip" {
|
||||||
try testing.expectEqualSlices(u8, &msg.mlkem_ciphertext, &restored.mlkem_ciphertext);
|
try testing.expectEqualSlices(u8, &msg.mlkem_ciphertext, &restored.mlkem_ciphertext);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "PQXDH full handshake roundtrip (stubbed ML-KEM)" {
|
test "PQXDH full handshake roundtrip (real ML-KEM)" {
|
||||||
const allocator = testing.allocator;
|
const allocator = testing.allocator;
|
||||||
|
|
||||||
// === Bob's Setup ===
|
// === Bob's Setup ===
|
||||||
|
|
@ -151,7 +103,7 @@ test "PQXDH full handshake roundtrip (stubbed ML-KEM)" {
|
||||||
// Generate Bob's ML-KEM keypair (stubbed)
|
// Generate Bob's ML-KEM keypair (stubbed)
|
||||||
var bob_mlkem_public: [pqxdh.ML_KEM_768.PUBLIC_KEY_SIZE]u8 = undefined;
|
var bob_mlkem_public: [pqxdh.ML_KEM_768.PUBLIC_KEY_SIZE]u8 = undefined;
|
||||||
var bob_mlkem_private: [pqxdh.ML_KEM_768.SECRET_KEY_SIZE]u8 = undefined;
|
var bob_mlkem_private: [pqxdh.ML_KEM_768.SECRET_KEY_SIZE]u8 = undefined;
|
||||||
const kem_result = OQS_KEM_kyber768_keypair(&bob_mlkem_public[0], &bob_mlkem_private[0]);
|
const kem_result = c.OQS_KEM_ml_kem_768_keypair(&bob_mlkem_public[0], &bob_mlkem_private[0]);
|
||||||
try testing.expectEqual(@as(c_int, 0), kem_result);
|
try testing.expectEqual(@as(c_int, 0), kem_result);
|
||||||
|
|
||||||
// Create Bob's prekey bundle (signature stubbed for now)
|
// Create Bob's prekey bundle (signature stubbed for now)
|
||||||
|
|
@ -211,6 +163,6 @@ test "PQXDH error: invalid ML-KEM encapsulation" {
|
||||||
var public_key: [pqxdh.ML_KEM_768.PUBLIC_KEY_SIZE]u8 = undefined;
|
var public_key: [pqxdh.ML_KEM_768.PUBLIC_KEY_SIZE]u8 = undefined;
|
||||||
var secret_key: [pqxdh.ML_KEM_768.SECRET_KEY_SIZE]u8 = undefined;
|
var secret_key: [pqxdh.ML_KEM_768.SECRET_KEY_SIZE]u8 = undefined;
|
||||||
|
|
||||||
const result = OQS_KEM_kyber768_keypair(&public_key[0], &secret_key[0]);
|
const result = c.OQS_KEM_ml_kem_768_keypair(&public_key[0], &secret_key[0]);
|
||||||
try testing.expectEqual(@as(c_int, 0), result);
|
try testing.expectEqual(@as(c_int, 0), result);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue