Add kkt protocol

This commit is contained in:
Georgio Nicolas
2025-05-29 01:19:35 +02:00
parent afbdc107bf
commit 118f836690
7 changed files with 687 additions and 8 deletions
Generated
+267 -8
View File
@@ -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",
+1
View File
@@ -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",
+37
View File
@@ -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
+135
View File
@@ -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);
+21
View File
@@ -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),
}
+224
View File
@@ -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()
);
}
}
+2
View File
@@ -0,0 +1,2 @@
pub mod error;
pub mod kkt;