Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ autobenches = false
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
qfall-tools = { git = "https://github.com/qfall/tools", branch="update" }
qfall-math = { git = "https://github.com/qfall/math", rev="1ee0b9f41676894d48520322109a3364b8f3338e" }
qfall-tools = { git = "https://github.com/qfall/tools", branch = "dev" }
qfall-math = { git = "https://github.com/qfall/math", branch = "dev" }
sha2 = "0.10.6"
serde = {version="1.0", features=["derive"]}
serde_json = "1.0"
typetag = "0.2"
criterion = { version = "0.7", features = ["html_reports"] }
criterion = { version = "0.8", features = ["html_reports"] }

[profile.bench]
debug = true
Expand Down
24 changes: 21 additions & 3 deletions benches/k_pke.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,13 @@ fn bench_kpke_dec_512(c: &mut Criterion) {
let (pk, sk) = k_pke.gen();
let cipher = k_pke.enc(&pk, i64::MAX);

c.bench_function("K-PKE dec 512", |b| b.iter(|| k_pke.dec(&sk, &cipher)));
c.bench_function("K-PKE dec 512", |b| {
b.iter_batched(
|| cipher.clone(),
|cipher| k_pke.dec(&sk, &cipher),
criterion::BatchSize::SmallInput,
)
});
}

/// Benchmark [kpke_cycle] with [KPKE::ml_kem_768].
Expand Down Expand Up @@ -88,7 +94,13 @@ fn bench_kpke_dec_768(c: &mut Criterion) {
let (pk, sk) = k_pke.gen();
let cipher = k_pke.enc(&pk, i64::MAX);

c.bench_function("K-PKE dec 768", |b| b.iter(|| k_pke.dec(&sk, &cipher)));
c.bench_function("K-PKE dec 768", |b| {
b.iter_batched(
|| cipher.clone(),
|cipher| k_pke.dec(&sk, &cipher),
criterion::BatchSize::SmallInput,
)
});
}

/// Benchmark [kpke_cycle] with [KPKE::ml_kem_1024].
Expand Down Expand Up @@ -125,7 +137,13 @@ fn bench_kpke_dec_1024(c: &mut Criterion) {
let (pk, sk) = k_pke.gen();
let cipher = k_pke.enc(&pk, i64::MAX);

c.bench_function("K-PKE dec 1024", |b| b.iter(|| k_pke.dec(&sk, &cipher)));
c.bench_function("K-PKE dec 1024", |b| {
b.iter_batched(
|| cipher.clone(),
|cipher| k_pke.dec(&sk, &cipher),
criterion::BatchSize::SmallInput,
)
});
}

criterion_group!(
Expand Down
48 changes: 34 additions & 14 deletions src/pk_encryption/k_pke.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,28 @@
//! used as foundation for ML-KEM.
//!
//! **WARNING:** This implementation is a toy implementation of the basics below
//! ML-KEM and mostly supposed to showcase the prototyping capabilities of the `qfall`-library.
//! ML-KEM and mostly supposed to showcase the prototyping capabilities of the `qFALL`-library.

use crate::pk_encryption::PKEncryptionScheme;
use qfall_math::{
integer::Z,
integer::{MatPolyOverZ, PolyOverZ, Z},
integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq, PolynomialRingZq},
};
use qfall_tools::utils::{
common_encodings::{
decode_z_bitwise_from_polynomialringzq, encode_z_bitwise_in_polynomialringzq,
use qfall_tools::{
compression::LossyCompressionFIPS203,
utils::{
common_encodings::{decode_value_from_polynomialringzq, encode_value_in_polynomialringzq},
common_moduli::new_anticyclic,
},
common_moduli::new_anticyclic,
};
use serde::{Deserialize, Serialize};

/// This is a naive toy-implementation of the [`PKEncryptionScheme`] used
/// as a basis for ML-KEM.
///
/// This implementation is not supposed to be an implementation of the FIPS 203 standard in [\[6\]](<index.html#:~:text=[6]>), but
/// is supposed to showcase the prototyping capabilities of `qfall` and does not cover compression algorithms
/// as specified in the FIPS 203 document or might deviate for the choice of matrix multiplication algorithms.
/// Especially, NTT-representation, sampling and multiplication are not part of this prototype.
/// is supposed to showcase the prototyping capabilities of `qFALL` and does not cover byte decomposition algorithms
/// as specified in the FIPS 203 document or NTT-multiplication.
///
/// Attributes:
/// - `q`: defines the modulus polynomial `(X^n + 1) mod p`
Expand Down Expand Up @@ -64,6 +64,8 @@ pub struct KPKE {
k: i64, // defines both dimensions of matrix A
eta_1: i64, // defines the binomial distribution of the secret and error drawn in `gen`
eta_2: i64, // defines the binomial distribution of the error drawn in `enc`
d_u: i64, // defines the number of kept upper-order bits per entry of vector `u`
d_v: i64, // defines the number of kept upper-order bits per entry of `v`
}

impl KPKE {
Expand All @@ -75,6 +77,8 @@ impl KPKE {
k: 2,
eta_1: 3,
eta_2: 2,
d_u: 10,
d_v: 4,
}
}

Expand All @@ -86,6 +90,8 @@ impl KPKE {
k: 3,
eta_1: 2,
eta_2: 2,
d_u: 10,
d_v: 4,
}
}

Expand All @@ -97,14 +103,16 @@ impl KPKE {
k: 4,
eta_1: 2,
eta_2: 2,
d_u: 11,
d_v: 5,
}
}
}

impl PKEncryptionScheme for KPKE {
type PublicKey = (MatPolynomialRingZq, MatPolynomialRingZq);
type SecretKey = MatPolynomialRingZq;
type Cipher = (MatPolynomialRingZq, PolynomialRingZq);
type Cipher = (MatPolyOverZ, PolyOverZ);

/// Generates a `(pk, sk)` pair by following these steps:
/// - A <- R_q^{k x k}
Expand Down Expand Up @@ -160,6 +168,7 @@ impl PKEncryptionScheme for KPKE {
/// - e_2 <- Bin(eta_2, 0.5) centered around 0
/// - u = A^T * y + e_1
/// - v = t^T * y + e_2 + 𝜇, where 𝜇 is the {q/2, 0} encoding of the bits of `message`
/// - Compress u and v
///
/// Then, ciphertext `(u, v)` is returned.
///
Expand Down Expand Up @@ -211,15 +220,21 @@ impl PKEncryptionScheme for KPKE {
let vec_u = &pk.0 * &vec_y + vec_e_1;

// 20 𝜇 ← Decompress_1(ByteDecode_1(𝑚))
let mu = encode_z_bitwise_in_polynomialringzq(&self.q, &message.into());
let mu = encode_value_in_polynomialringzq(message, 2, &self.q).unwrap();

// 21 𝑣 ← NTT^−1(𝐭^⊺ ∘ 𝐲) + 𝑒_2 + 𝜇
let v = pk.1.dot_product(&vec_y).unwrap() + e_2 + mu;

// 22: 𝑐_1 ← ByteEncode_{𝑑_𝑢}(Compress_{𝑑_𝑢}(𝐮))
let vec_u = vec_u.lossy_compress(self.d_u);
// 23: 𝑐_2 ← ByteEncode_{𝑑_𝑣}(Compress_{𝑑_𝑣}(𝑣))
let v = v.lossy_compress(self.d_v);

(vec_u, v)
}

/// Decrypts the provided `cipher` using the secret key `sk` by following these steps:
/// - Decompress u and v
/// - w = v - s^T * u
/// - returns the decoding of `w` with 1 and 0 set in the returned [`Z`] instance
/// if the corresponding coefficient was closer to q/2 or 0 respectively
Expand All @@ -242,11 +257,16 @@ impl PKEncryptionScheme for KPKE {
/// assert_eq!(1, m);
/// ```
fn dec(&self, sk: &Self::SecretKey, (u, v): &Self::Cipher) -> Z {
// 6 𝑤 ← 𝑣 − NTT^−1(𝐬^⊺ ∘ NTT(𝐮))
let w = v - sk.dot_product(u).unwrap();
// 3: 𝐮′ ← Decompress_{𝑑_𝑢}(ByteDecode_{𝑑_𝑢}(𝑐_1))
let u = MatPolynomialRingZq::lossy_decompress(u, self.d_u, &self.q);
// 4: 𝑣′ ← Decompress_{𝑑_𝑣}(ByteDecode_{𝑑_𝑣}(𝑐_2))
let v = PolynomialRingZq::lossy_decompress(v, self.d_v, &self.q);

// 6 𝑤 ← 𝑣′ − NTT^−1(𝐬^⊺ ∘ NTT(𝐮′))
let w = v - sk.dot_product(&u).unwrap();

// 7 𝑚 ← ByteEncode_1(Compress_1(𝑤))
decode_z_bitwise_from_polynomialringzq(self.q.get_q(), &w)
decode_value_from_polynomialringzq(&w, 2).unwrap()
}
}

Expand Down
8 changes: 3 additions & 5 deletions src/pk_encryption/ring_lpr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@ use qfall_math::{
traits::Pow,
};
use qfall_tools::utils::{
common_encodings::{
decode_z_bitwise_from_polynomialringzq, encode_z_bitwise_in_polynomialringzq,
},
common_encodings::{decode_value_from_polynomialringzq, encode_value_in_polynomialringzq},
common_moduli::new_anticyclic,
};
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -396,7 +394,7 @@ impl PKEncryptionScheme for RingLPR {
let message: Z = message.into().abs();
let mu = message % Z::from(2).pow(&self.n).unwrap();
// set mu_q_half to polynomial with n {0,1} coefficients
let mu_q_half = encode_z_bitwise_in_polynomialringzq(&self.q, &mu);
let mu_q_half = encode_value_in_polynomialringzq(mu, 2, &self.q).unwrap();

// r <- χ
let r = PolynomialRingZq::sample_discrete_gauss(&self.q, 0, &self.alpha * &self.q.get_q())
Expand Down Expand Up @@ -447,7 +445,7 @@ impl PKEncryptionScheme for RingLPR {
// res = v - s * u
let result = &cipher.1 - sk * &cipher.0;

decode_z_bitwise_from_polynomialringzq(self.q.get_q(), &result)
decode_value_from_polynomialringzq(&result, 2).unwrap()
}
}

Expand Down
Loading