Add kkt protocol
This commit is contained in:
Generated
+267
-8
@@ -1457,6 +1457,16 @@ version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||
|
||||
[[package]]
|
||||
name = "core-models"
|
||||
version = "0.0.2"
|
||||
source = "git+https://github.com/cryspen/libcrux#96abd9f2460ff92811a1c181662590d96c37949c"
|
||||
dependencies = [
|
||||
"hax-lib",
|
||||
"pastey",
|
||||
"rand 0.9.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cosmos-sdk-proto"
|
||||
version = "0.26.1"
|
||||
@@ -3141,6 +3151,40 @@ dependencies = [
|
||||
"hashbrown 0.15.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hax-lib"
|
||||
version = "0.3.0"
|
||||
source = "git+https://github.com/cryspen/hax/#27ba29ff727fb4c4fffecad5e736181087ce2537"
|
||||
dependencies = [
|
||||
"hax-lib-macros",
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hax-lib-macros"
|
||||
version = "0.3.0"
|
||||
source = "git+https://github.com/cryspen/hax/#27ba29ff727fb4c4fffecad5e736181087ce2537"
|
||||
dependencies = [
|
||||
"hax-lib-macros-types",
|
||||
"proc-macro-error2",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hax-lib-macros-types"
|
||||
version = "0.3.0"
|
||||
source = "git+https://github.com/cryspen/hax/#27ba29ff727fb4c4fffecad5e736181087ce2537"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hdrhistogram"
|
||||
version = "7.5.4"
|
||||
@@ -3250,7 +3294,7 @@ dependencies = [
|
||||
"idna",
|
||||
"ipnet",
|
||||
"once_cell",
|
||||
"rand 0.9.0",
|
||||
"rand 0.9.1",
|
||||
"ring",
|
||||
"rustls 0.23.25",
|
||||
"thiserror 2.0.12",
|
||||
@@ -3275,7 +3319,7 @@ dependencies = [
|
||||
"moka",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"rand 0.9.0",
|
||||
"rand 0.9.1",
|
||||
"resolv-conf",
|
||||
"rustls 0.23.25",
|
||||
"smallvec",
|
||||
@@ -4150,6 +4194,193 @@ version = "0.2.171"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
|
||||
|
||||
[[package]]
|
||||
name = "libcrux-chacha20poly1305"
|
||||
version = "0.0.2"
|
||||
source = "git+https://github.com/cryspen/libcrux#96abd9f2460ff92811a1c181662590d96c37949c"
|
||||
dependencies = [
|
||||
"libcrux-hacl-rs",
|
||||
"libcrux-macros",
|
||||
"libcrux-poly1305",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libcrux-curve25519"
|
||||
version = "0.0.2"
|
||||
source = "git+https://github.com/cryspen/libcrux#96abd9f2460ff92811a1c181662590d96c37949c"
|
||||
dependencies = [
|
||||
"libcrux-hacl-rs",
|
||||
"libcrux-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libcrux-ecdh"
|
||||
version = "0.0.3-alpha.1"
|
||||
source = "git+https://github.com/cryspen/libcrux#96abd9f2460ff92811a1c181662590d96c37949c"
|
||||
dependencies = [
|
||||
"libcrux-curve25519",
|
||||
"libcrux-p256",
|
||||
"rand 0.9.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libcrux-ed25519"
|
||||
version = "0.0.3-alpha.1"
|
||||
source = "git+https://github.com/cryspen/libcrux#96abd9f2460ff92811a1c181662590d96c37949c"
|
||||
dependencies = [
|
||||
"libcrux-hacl-rs",
|
||||
"libcrux-macros",
|
||||
"libcrux-sha2",
|
||||
"rand_core 0.9.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libcrux-hacl-rs"
|
||||
version = "0.0.2"
|
||||
source = "git+https://github.com/cryspen/libcrux#96abd9f2460ff92811a1c181662590d96c37949c"
|
||||
dependencies = [
|
||||
"libcrux-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libcrux-hkdf"
|
||||
version = "0.0.3-alpha.1"
|
||||
source = "git+https://github.com/cryspen/libcrux#96abd9f2460ff92811a1c181662590d96c37949c"
|
||||
dependencies = [
|
||||
"libcrux-hacl-rs",
|
||||
"libcrux-hmac",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libcrux-hmac"
|
||||
version = "0.0.3-alpha.1"
|
||||
source = "git+https://github.com/cryspen/libcrux#96abd9f2460ff92811a1c181662590d96c37949c"
|
||||
dependencies = [
|
||||
"libcrux-hacl-rs",
|
||||
"libcrux-macros",
|
||||
"libcrux-sha2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libcrux-intrinsics"
|
||||
version = "0.0.2"
|
||||
source = "git+https://github.com/cryspen/libcrux#96abd9f2460ff92811a1c181662590d96c37949c"
|
||||
dependencies = [
|
||||
"core-models",
|
||||
"hax-lib",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libcrux-kem"
|
||||
version = "0.0.3-alpha.1"
|
||||
source = "git+https://github.com/cryspen/libcrux#96abd9f2460ff92811a1c181662590d96c37949c"
|
||||
dependencies = [
|
||||
"libcrux-ecdh",
|
||||
"libcrux-ml-kem",
|
||||
"libcrux-sha3",
|
||||
"libcrux-traits",
|
||||
"rand 0.9.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libcrux-macros"
|
||||
version = "0.0.2"
|
||||
source = "git+https://github.com/cryspen/libcrux#96abd9f2460ff92811a1c181662590d96c37949c"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libcrux-ml-kem"
|
||||
version = "0.0.3-alpha.1"
|
||||
source = "git+https://github.com/cryspen/libcrux#96abd9f2460ff92811a1c181662590d96c37949c"
|
||||
dependencies = [
|
||||
"hax-lib",
|
||||
"libcrux-intrinsics",
|
||||
"libcrux-platform",
|
||||
"libcrux-secrets",
|
||||
"libcrux-sha3",
|
||||
"rand 0.9.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libcrux-p256"
|
||||
version = "0.0.3-alpha.1"
|
||||
source = "git+https://github.com/cryspen/libcrux#96abd9f2460ff92811a1c181662590d96c37949c"
|
||||
dependencies = [
|
||||
"libcrux-hacl-rs",
|
||||
"libcrux-macros",
|
||||
"libcrux-sha2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libcrux-platform"
|
||||
version = "0.0.2"
|
||||
source = "git+https://github.com/cryspen/libcrux#96abd9f2460ff92811a1c181662590d96c37949c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libcrux-poly1305"
|
||||
version = "0.0.2"
|
||||
source = "git+https://github.com/cryspen/libcrux#96abd9f2460ff92811a1c181662590d96c37949c"
|
||||
dependencies = [
|
||||
"libcrux-hacl-rs",
|
||||
"libcrux-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libcrux-psq"
|
||||
version = "0.0.3-alpha.1"
|
||||
source = "git+https://github.com/cryspen/libcrux#96abd9f2460ff92811a1c181662590d96c37949c"
|
||||
dependencies = [
|
||||
"libcrux-chacha20poly1305",
|
||||
"libcrux-ed25519",
|
||||
"libcrux-hkdf",
|
||||
"libcrux-hmac",
|
||||
"libcrux-kem",
|
||||
"libcrux-traits",
|
||||
"rand 0.9.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libcrux-secrets"
|
||||
version = "0.0.2"
|
||||
source = "git+https://github.com/cryspen/libcrux#96abd9f2460ff92811a1c181662590d96c37949c"
|
||||
dependencies = [
|
||||
"hax-lib",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libcrux-sha2"
|
||||
version = "0.0.3-alpha.1"
|
||||
source = "git+https://github.com/cryspen/libcrux#96abd9f2460ff92811a1c181662590d96c37949c"
|
||||
dependencies = [
|
||||
"libcrux-hacl-rs",
|
||||
"libcrux-macros",
|
||||
"libcrux-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libcrux-sha3"
|
||||
version = "0.0.2"
|
||||
source = "git+https://github.com/cryspen/libcrux#96abd9f2460ff92811a1c181662590d96c37949c"
|
||||
dependencies = [
|
||||
"hax-lib",
|
||||
"libcrux-intrinsics",
|
||||
"libcrux-platform",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libcrux-traits"
|
||||
version = "0.0.3-alpha.1"
|
||||
source = "git+https://github.com/cryspen/libcrux#96abd9f2460ff92811a1c181662590d96c37949c"
|
||||
dependencies = [
|
||||
"rand 0.9.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
version = "0.2.11"
|
||||
@@ -6904,6 +7135,29 @@ dependencies = [
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-psq-kkt"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"bytes",
|
||||
"criterion",
|
||||
"futures",
|
||||
"libcrux-kem",
|
||||
"libcrux-psq",
|
||||
"libcrux-traits",
|
||||
"nym-crypto",
|
||||
"pin-project",
|
||||
"rand 0.9.1",
|
||||
"sha2 0.10.9",
|
||||
"snow",
|
||||
"strum 0.26.3",
|
||||
"thiserror 2.0.12",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-sdk"
|
||||
version = "0.1.0"
|
||||
@@ -8284,6 +8538,12 @@ version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "pastey"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3a8cb46bdc156b1c90460339ae6bfd45ba0394e5effbaa640badb4987fdc261"
|
||||
|
||||
[[package]]
|
||||
name = "peg"
|
||||
version = "0.8.4"
|
||||
@@ -8604,7 +8864,7 @@ dependencies = [
|
||||
"hmac",
|
||||
"md-5",
|
||||
"memchr",
|
||||
"rand 0.9.0",
|
||||
"rand 0.9.1",
|
||||
"sha2 0.10.9",
|
||||
"stringprep",
|
||||
]
|
||||
@@ -8855,7 +9115,7 @@ checksum = "b820744eb4dc9b57a3398183639c511b5a26d2ed702cedd3febaa1393caa22cc"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"getrandom 0.3.1",
|
||||
"rand 0.9.0",
|
||||
"rand 0.9.1",
|
||||
"ring",
|
||||
"rustc-hash",
|
||||
"rustls 0.23.25",
|
||||
@@ -8909,13 +9169,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.9.0"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
|
||||
checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
|
||||
dependencies = [
|
||||
"rand_chacha 0.9.0",
|
||||
"rand_core 0.9.1",
|
||||
"zerocopy 0.8.20",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -10980,7 +11239,7 @@ dependencies = [
|
||||
"pin-project-lite",
|
||||
"postgres-protocol",
|
||||
"postgres-types",
|
||||
"rand 0.9.0",
|
||||
"rand 0.9.1",
|
||||
"socket2",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
|
||||
@@ -64,6 +64,7 @@ members = [
|
||||
"common/node-tester-utils",
|
||||
"common/nonexhaustive-delayqueue",
|
||||
"common/nym-id",
|
||||
"common/nym-psq-kkr",
|
||||
"common/nym-metrics",
|
||||
"common/nym_offline_compact_ecash",
|
||||
"common/nymnoise",
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
[package]
|
||||
name = "nym-psq-kkt"
|
||||
version = "0.1.0"
|
||||
authors = ["Georgio Nicolas <georgio@nymtech.net>"]
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
arc-swap = { workspace = true }
|
||||
bytes = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
pin-project = { workspace = true }
|
||||
sha2 = { workspace = true }
|
||||
snow = { workspace = true }
|
||||
strum = { workspace = true, features = ["derive"] }
|
||||
thiserror = { workspace = true }
|
||||
tokio = { workspace = true, features = ["full"] }
|
||||
tokio-util = { workspace = true, features = ["codec"] }
|
||||
|
||||
# internal
|
||||
nym-crypto = { path = "../crypto", features = ["asymmetric", "serde"]}
|
||||
|
||||
libcrux-traits = { git = "https://github.com/cryspen/libcrux" }
|
||||
libcrux-kem = { git = "https://github.com/cryspen/libcrux" }
|
||||
libcrux-psq = { git = "https://github.com/cryspen/libcrux" }
|
||||
rand = "0.9.1"
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = {workspace = true}
|
||||
|
||||
[[bench]]
|
||||
name = "benches"
|
||||
harness = false
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
@@ -0,0 +1,135 @@
|
||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use criterion::{criterion_group, criterion_main, Criterion};
|
||||
use libcrux_psq::impls::MlKem768;
|
||||
use nym_crypto::asymmetric::ed25519;
|
||||
use nym_psq_kkt::kkt::{
|
||||
KKTInitiator, KKTResponder, KKT_REQ_LEN, KKT_RES_LEN_MLKEM768, KKT_TAG_LEN,
|
||||
};
|
||||
use rand::prelude::*;
|
||||
|
||||
pub fn gen_ed25519_keypair(c: &mut Criterion) {
|
||||
c.bench_function("Generate Ed25519 Keypair", |b| {
|
||||
b.iter(|| {
|
||||
let mut s: [u8; 32] = [0u8; 32];
|
||||
rand::rng().fill_bytes(&mut s);
|
||||
ed25519::KeyPair::from_secret(s, 0)
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
pub fn gen_mlkem768_keypair(c: &mut Criterion) {
|
||||
c.bench_function("Generate MlKem768 Keypair", |b| {
|
||||
b.iter(|| {
|
||||
libcrux_kem::key_gen(libcrux_kem::Algorithm::MlKem768, &mut rand::rng()).unwrap()
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
pub fn kkt_benchmark(c: &mut Criterion) {
|
||||
// generate ed25519 keys
|
||||
let mut secret_initiator: [u8; 32] = [0u8; 32];
|
||||
rand::rng().fill_bytes(&mut secret_initiator);
|
||||
let initiator_ed25519_keypair = ed25519::KeyPair::from_secret(secret_initiator, 0);
|
||||
|
||||
let mut secret_responder: [u8; 32] = [0u8; 32];
|
||||
rand::rng().fill_bytes(&mut secret_responder);
|
||||
let responder_ed25519_keypair = ed25519::KeyPair::from_secret(secret_responder, 1);
|
||||
|
||||
// generate kem keypair
|
||||
let (_, responder_kem_public_key) =
|
||||
libcrux_kem::key_gen(libcrux_kem::Algorithm::MlKem768, &mut rand::rng()).unwrap();
|
||||
|
||||
// initialize parties
|
||||
let initiator: KKTInitiator<MlKem768> =
|
||||
KKTInitiator::init(initiator_ed25519_keypair.private_key());
|
||||
|
||||
c.bench_function("Initialize Initiator", |b| {
|
||||
b.iter(|| KKTInitiator::<MlKem768>::init(initiator_ed25519_keypair.private_key()));
|
||||
});
|
||||
|
||||
let responder: KKTResponder<MlKem768> = KKTResponder::init(
|
||||
responder_ed25519_keypair.private_key(),
|
||||
&responder_kem_public_key,
|
||||
);
|
||||
|
||||
c.bench_function("Initialize Responder", |b| {
|
||||
b.iter(|| {
|
||||
KKTResponder::init(
|
||||
responder_ed25519_keypair.private_key(),
|
||||
&responder_kem_public_key,
|
||||
)
|
||||
});
|
||||
});
|
||||
|
||||
// create buffers
|
||||
let mut request_buffer: [u8; KKT_REQ_LEN] = [0u8; KKT_REQ_LEN];
|
||||
let mut response_buffer: [u8; KKT_RES_LEN_MLKEM768] = [0u8; KKT_RES_LEN_MLKEM768];
|
||||
let mut tag_buffer: [u8; KKT_TAG_LEN] = [0u8; KKT_TAG_LEN];
|
||||
|
||||
c.bench_function("Initiator: Generate Request", |b| {
|
||||
b.iter(|| {
|
||||
initiator.request_kem_pk(&mut request_buffer, &mut tag_buffer);
|
||||
});
|
||||
});
|
||||
|
||||
// generate request
|
||||
initiator.request_kem_pk(&mut request_buffer, &mut tag_buffer);
|
||||
|
||||
c.bench_function("Responder: Ingest Request and Generate Response", |b| {
|
||||
b.iter(|| {
|
||||
responder
|
||||
.respond_kem_pk(
|
||||
&mut response_buffer,
|
||||
initiator_ed25519_keypair.public_key(),
|
||||
&request_buffer,
|
||||
)
|
||||
.unwrap();
|
||||
});
|
||||
});
|
||||
|
||||
// ingest request, generate response
|
||||
responder
|
||||
.respond_kem_pk(
|
||||
&mut response_buffer,
|
||||
initiator_ed25519_keypair.public_key(),
|
||||
&request_buffer,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
c.bench_function("Initiator: Ingest Response and Store Key", |b| {
|
||||
b.iter(|| {
|
||||
let _ = initiator
|
||||
.ingest_response_kem_pk::<MlKem768>(
|
||||
&response_buffer,
|
||||
&tag_buffer,
|
||||
responder_ed25519_keypair.public_key(),
|
||||
)
|
||||
.unwrap();
|
||||
});
|
||||
});
|
||||
|
||||
// ingest response
|
||||
let received_responder_key = initiator
|
||||
.ingest_response_kem_pk::<MlKem768>(
|
||||
&response_buffer,
|
||||
&tag_buffer,
|
||||
responder_ed25519_keypair.public_key(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// check if the public key received is the same one that we generated at the start
|
||||
assert_eq!(
|
||||
responder_kem_public_key.encode(),
|
||||
received_responder_key.encode()
|
||||
);
|
||||
}
|
||||
|
||||
criterion_group!(
|
||||
benches,
|
||||
gen_ed25519_keypair,
|
||||
gen_mlkem768_keypair,
|
||||
kkt_benchmark
|
||||
);
|
||||
criterion_main!(benches);
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum KKTError {
|
||||
#[error("Signature constructor error")]
|
||||
SigConstructorError,
|
||||
|
||||
#[error("Signature verification error")]
|
||||
SigVerifError,
|
||||
// #[error("Protocol did not complete")]
|
||||
// ProtocolError,
|
||||
|
||||
// #[error("encountered an IO error: {0}")]
|
||||
// IoError(#[from] io::Error),
|
||||
|
||||
// #[error("Handshake timeout")]
|
||||
// HandshakeTimeout(#[from] tokio::time::error::Elapsed),
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use nym_crypto::asymmetric::ed25519;
|
||||
use rand::prelude::*;
|
||||
|
||||
use libcrux_kem::MlKem768PublicKey;
|
||||
use libcrux_psq::{impls::MlKem768, traits::PSQ};
|
||||
use libcrux_traits::kem::KEM;
|
||||
|
||||
use crate::error::KKTError;
|
||||
|
||||
const REQ_STR: &[u8] = "KEM_REQ".as_bytes();
|
||||
const RES_STR: &[u8] = "KEM_RES".as_bytes();
|
||||
|
||||
const REQ_LEN: usize = REQ_STR.len() + KKT_TAG_LEN;
|
||||
const RES_LEN_MLKEM768: usize = REQ_LEN + MlKem768PublicKey::len();
|
||||
|
||||
pub const KKT_TAG_LEN: usize = 16;
|
||||
pub const KKT_REQ_LEN: usize = REQ_LEN + ed25519::SIGNATURE_LENGTH;
|
||||
pub const KKT_RES_LEN_MLKEM768: usize = RES_LEN_MLKEM768 + ed25519::SIGNATURE_LENGTH;
|
||||
|
||||
pub struct KKTInitiator<'a, T: PSQ> {
|
||||
signing_key: &'a ed25519::PrivateKey,
|
||||
_t: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<'a, T: PSQ> KKTInitiator<'a, T> {
|
||||
pub fn init(signing_key: &'a ed25519::PrivateKey) -> Self {
|
||||
Self {
|
||||
signing_key,
|
||||
_t: PhantomData,
|
||||
}
|
||||
}
|
||||
pub fn request_kem_pk(
|
||||
&self,
|
||||
request_buffer: &mut [u8; KKT_REQ_LEN],
|
||||
tag_buffer: &mut [u8; KKT_TAG_LEN],
|
||||
) {
|
||||
// request_buffer[0..7] <- request string
|
||||
request_buffer[0..REQ_STR.len()].copy_from_slice(REQ_STR);
|
||||
|
||||
// tag_buffer <- generate tag
|
||||
rand::rng().fill_bytes(tag_buffer);
|
||||
|
||||
// request_buffer[7..23] <- tag
|
||||
request_buffer[REQ_STR.len()..REQ_LEN].copy_from_slice(tag_buffer);
|
||||
|
||||
// sig <- Sign request_buffer[0..23]
|
||||
let sig = self.signing_key.sign(&request_buffer[0..REQ_LEN]);
|
||||
|
||||
// request_buffer[23..87] <- sig
|
||||
request_buffer[REQ_LEN..].copy_from_slice(&sig.to_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> KKTInitiator<'a, MlKem768> {
|
||||
pub fn ingest_response_kem_pk<T: PSQ>(
|
||||
&self,
|
||||
response: &[u8],
|
||||
tag: &[u8; KKT_TAG_LEN],
|
||||
responder_verification_key: &ed25519::PublicKey,
|
||||
) -> Result<libcrux_kem::PublicKey, KKTError> {
|
||||
// TODO: Refactor asserts into errors
|
||||
// Check size of message
|
||||
assert_eq!(response.len(), KKT_RES_LEN_MLKEM768);
|
||||
// Check if the response string is there at the start of the message
|
||||
assert_eq!(&response[0..RES_STR.len()], RES_STR);
|
||||
// Check if the tag is the one we expect
|
||||
assert_eq!(
|
||||
&response[RES_STR.len()..RES_STR.len() + KKT_TAG_LEN],
|
||||
&tag[..]
|
||||
);
|
||||
|
||||
// Attempt to reconstruct a signature from the received bytes
|
||||
match ed25519::Signature::from_bytes(&response[RES_LEN_MLKEM768..]) {
|
||||
Ok(sig) => {
|
||||
// Attempt to verify signature
|
||||
match responder_verification_key.verify(&response[0..RES_LEN_MLKEM768], &sig) {
|
||||
Ok(()) => {
|
||||
// Extract key from bytes
|
||||
// (has to be an owned sized array, unless I'm missing some function that works with slices)
|
||||
let mut key_bytes: [u8; MlKem768PublicKey::len()] =
|
||||
[0u8; MlKem768PublicKey::len()];
|
||||
key_bytes.copy_from_slice(
|
||||
&response[RES_STR.len() + KKT_TAG_LEN..RES_LEN_MLKEM768],
|
||||
);
|
||||
|
||||
// Create key from bytes and return it
|
||||
Ok(libcrux_kem::PublicKey::MlKem768(MlKem768PublicKey::from(
|
||||
key_bytes,
|
||||
)))
|
||||
}
|
||||
Err(_) => Err(KKTError::SigVerifError),
|
||||
}
|
||||
}
|
||||
Err(_) => Err(KKTError::SigConstructorError),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct KKTResponder<'a, T: PSQ> {
|
||||
signing_key: &'a ed25519::PrivateKey,
|
||||
kem_public_key: &'a <T::InnerKEM as KEM>::EncapsulationKey,
|
||||
}
|
||||
|
||||
impl<'a> KKTResponder<'a, MlKem768> {
|
||||
pub fn init(
|
||||
signing_key: &'a ed25519::PrivateKey,
|
||||
kem_public_key: &'a libcrux_kem::PublicKey,
|
||||
) -> Self {
|
||||
Self {
|
||||
signing_key,
|
||||
kem_public_key,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn respond_kem_pk(
|
||||
&self,
|
||||
response_buffer: &mut [u8; KKT_RES_LEN_MLKEM768],
|
||||
initiator_verification_key: &ed25519::PublicKey,
|
||||
request: &[u8],
|
||||
) -> Result<(), KKTError> {
|
||||
// TODO: Refactor asserts into errors
|
||||
// Check request size
|
||||
assert_eq!(request.len(), KKT_REQ_LEN);
|
||||
// Check request string
|
||||
assert_eq!(&request[0..REQ_STR.len()], REQ_STR);
|
||||
|
||||
match ed25519::Signature::from_bytes(&request[REQ_LEN..]) {
|
||||
Ok(sig) => match initiator_verification_key.verify(&request[0..REQ_LEN], &sig) {
|
||||
Ok(()) => {
|
||||
// response_buffer[0..7] <- RES_STR (7 bytes)
|
||||
response_buffer[0..RES_STR.len()].copy_from_slice(RES_STR);
|
||||
|
||||
// response_buffer[7..23] <- tag (16 bytes, sent by initiator)
|
||||
response_buffer[RES_STR.len()..REQ_LEN]
|
||||
.copy_from_slice(&request[REQ_STR.len()..REQ_LEN]);
|
||||
|
||||
// response_buffer[23..1207] <- MlKem768 Public Key (1184 bytes)
|
||||
response_buffer[REQ_LEN..RES_LEN_MLKEM768]
|
||||
.copy_from_slice(self.kem_public_key.encode().as_slice());
|
||||
|
||||
// sign response_buffer[0..1207]
|
||||
let sig = self.signing_key.sign(&response_buffer[0..RES_LEN_MLKEM768]);
|
||||
|
||||
// response_buffer[1207..1271] <- signature (64 bytes)
|
||||
response_buffer[RES_LEN_MLKEM768..].copy_from_slice(&sig.to_bytes());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Err(_) => Err(KKTError::SigConstructorError),
|
||||
},
|
||||
Err(_) => Err(KKTError::SigVerifError),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
use crate::kkt::{KKT_REQ_LEN, KKT_RES_LEN_MLKEM768, KKT_TAG_LEN, REQ_LEN, RES_LEN_MLKEM768};
|
||||
|
||||
use super::{KKTInitiator, KKTResponder};
|
||||
use libcrux_psq::impls::MlKem768;
|
||||
use nym_crypto::asymmetric::ed25519;
|
||||
use rand::prelude::*;
|
||||
|
||||
#[test]
|
||||
fn test_kkt_e2e() {
|
||||
// generate ed25519 keys
|
||||
let mut secret_initiator: [u8; 32] = [0u8; 32];
|
||||
rand::rng().fill_bytes(&mut secret_initiator);
|
||||
let initiator_ed25519_keypair = ed25519::KeyPair::from_secret(secret_initiator, 0);
|
||||
|
||||
let mut secret_responder: [u8; 32] = [0u8; 32];
|
||||
rand::rng().fill_bytes(&mut secret_responder);
|
||||
let responder_ed25519_keypair = ed25519::KeyPair::from_secret(secret_responder, 1);
|
||||
|
||||
// generate kem keypair
|
||||
let (_, responder_kem_public_key) =
|
||||
libcrux_kem::key_gen(libcrux_kem::Algorithm::MlKem768, &mut rand::rng()).unwrap();
|
||||
|
||||
// initialize parties
|
||||
let initiator: KKTInitiator<MlKem768> =
|
||||
KKTInitiator::init(initiator_ed25519_keypair.private_key());
|
||||
|
||||
let responder: KKTResponder<MlKem768> = KKTResponder::init(
|
||||
responder_ed25519_keypair.private_key(),
|
||||
&responder_kem_public_key,
|
||||
);
|
||||
|
||||
// create buffers
|
||||
let mut request_buffer: [u8; KKT_REQ_LEN] = [0u8; KKT_REQ_LEN];
|
||||
let mut response_buffer: [u8; KKT_RES_LEN_MLKEM768] = [0u8; KKT_RES_LEN_MLKEM768];
|
||||
let mut tag_buffer: [u8; KKT_TAG_LEN] = [0u8; KKT_TAG_LEN];
|
||||
|
||||
// generate request
|
||||
initiator.request_kem_pk(&mut request_buffer, &mut tag_buffer);
|
||||
|
||||
// ingest request, generate response
|
||||
responder
|
||||
.respond_kem_pk(
|
||||
&mut response_buffer,
|
||||
initiator_ed25519_keypair.public_key(),
|
||||
&request_buffer,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// ingest response
|
||||
let received_responder_key = initiator
|
||||
.ingest_response_kem_pk::<MlKem768>(
|
||||
&response_buffer,
|
||||
&tag_buffer,
|
||||
responder_ed25519_keypair.public_key(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// check if the public key received is the same one that we generated at the start
|
||||
assert_eq!(
|
||||
responder_kem_public_key.encode(),
|
||||
received_responder_key.encode()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
pub mod error;
|
||||
pub mod kkt;
|
||||
Reference in New Issue
Block a user