Skip to content

Commit 9bbbade

Browse files
Merge pull request #34 from sebastienrousseau/feat/kyberlib
v0.0.6
2 parents a8d3285 + 3987945 commit 9bbbade

File tree

7 files changed

+64
-32
lines changed

7 files changed

+64
-32
lines changed

Cargo.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ license = "MIT OR Apache-2.0"
3030
name = "kyberlib"
3131
readme = "README.md"
3232
repository = "https://github.com/sebastienrousseau/kyberlib"
33-
version = "0.0.5"
33+
version = "0.0.6"
3434

3535
[dependencies]
3636
# Dependencies for the library

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ To use the `kyberlib` library in your project, add the following to your
8787

8888
```toml
8989
[dependencies]
90-
kyberlib = "0.0.5"
90+
kyberlib = "0.0.6"
9191
```
9292

9393
Add the following to your `main.rs` file:
@@ -310,6 +310,6 @@ providing a lot of useful suggestions on how to improve this project.
310310
[codecov-badge]: https://img.shields.io/codecov/c/github/sebastienrousseau/kyberlib?style=for-the-badge&token=oEisyTucB5 'Codecov'
311311
[divider]: https://kura.pro/common/images/elements/divider.svg "divider"
312312
[docs-badge]: https://img.shields.io/docsrs/kyberlib.svg?style=for-the-badge 'Docs.rs'
313-
[libs-badge]: https://img.shields.io/badge/lib.rs-v0.0.5-orange.svg?style=for-the-badge 'Lib.rs'
313+
[libs-badge]: https://img.shields.io/badge/lib.rs-v0.0.6-orange.svg?style=for-the-badge 'Lib.rs'
314314
[license-badge]: https://img.shields.io/crates/l/kyberlib.svg?style=for-the-badge 'License'
315315
[made-with-rust]: https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust 'Made With Rust'

TEMPLATE.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ A Robust Rust Library for CRYSTALS-Kyber Post-Quantum Cryptography
5252
[crates-badge]: https://img.shields.io/crates/v/kyberlib.svg?style=for-the-badge 'Crates.io badge'
5353
[divider]: https://via.placeholder.com/1024x1.png/d8dee4/FFFFFF?text=− "kyberlib's divider"
5454
[docs-badge]: https://img.shields.io/docsrs/kyberlib.svg?style=for-the-badge 'Docs.rs badge'
55-
[libs-badge]: https://img.shields.io/badge/lib.rs-v0.0.5-orange.svg?style=for-the-badge 'Lib.rs badge'
55+
[libs-badge]: https://img.shields.io/badge/lib.rs-v0.0.6-orange.svg?style=for-the-badge 'Lib.rs badge'
5656
[license-badge]: https://img.shields.io/crates/l/kyberlib.svg?style=for-the-badge 'License badge'
5757
[made-with-rust-badge]: https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust 'Made With Rust badge'
5858

src/reference/poly.rs

+31-10
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,18 @@ pub(crate) fn poly_compress(r: &mut [u8], a: Poly) {
3333
let mut k = 0usize;
3434
let mut u: i16;
3535

36+
// Compress_q(x, d) = ⌈(2ᵈ/q)x⌋ mod⁺ 2ᵈ
37+
// = ⌊(2ᵈ/q)x+½⌋ mod⁺ 2ᵈ
38+
// = ⌊((x << d) + q/2) / q⌋ mod⁺ 2ᵈ
39+
// = DIV((x << d) + q/2, q) & ((1<<d) - 1)
40+
//
41+
// We approximate DIV(x, q) by computing (x*a)>>e, where a/(2^e) ≈ 1/q.
42+
// For d in {10,11} we use 20,642,678/2^36, which computes division by x/q
43+
// correctly for 0 ≤ x < 41,522,616, which fits (q << 11) + q/2 comfortably.
44+
// For d in {4,5} we use 315/2^20, which doesn't compute division by x/q
45+
// correctly for all inputs, but it's close enough that the end result
46+
// of the compression is correct. The advantage is that we do not need
47+
// to use a 64-bit intermediate value.
3648
match KYBER_POLY_COMPRESSED_BYTES {
3749
128 => {
3850
#[allow(clippy::needless_range_loop)]
@@ -41,9 +53,11 @@ pub(crate) fn poly_compress(r: &mut [u8], a: Poly) {
4153
// map to positive standard representatives
4254
u = a.coeffs[8 * i + j];
4355
u += (u >> 15) & KYBER_Q as i16;
44-
t[j] = (((((u as u16) << 4) + KYBER_Q as u16 / 2)
45-
/ KYBER_Q as u16)
46-
& 15) as u8;
56+
let mut tmp: u32 =
57+
(((u as u16) << 4) + KYBER_Q as u16 / 2) as u32;
58+
tmp *= 315;
59+
tmp >>= 20;
60+
t[j] = ((tmp as u16) & 15) as u8;
4761
}
4862
r[k] = t[0] | (t[1] << 4);
4963
r[k + 1] = t[2] | (t[3] << 4);
@@ -59,9 +73,11 @@ pub(crate) fn poly_compress(r: &mut [u8], a: Poly) {
5973
// map to positive standard representatives
6074
u = a.coeffs[8 * i + j];
6175
u += (u >> 15) & KYBER_Q as i16;
62-
t[j] = (((((u as u32) << 5) + KYBER_Q as u32 / 2)
63-
/ KYBER_Q as u32)
64-
& 31) as u8;
76+
let mut tmp: u32 =
77+
((u as u32) << 5) + KYBER_Q as u32 / 2;
78+
tmp *= 315;
79+
tmp >>= 20;
80+
t[j] = ((tmp as u16) & 31) as u8;
6581
}
6682
r[k] = t[0] | (t[1] << 5);
6783
r[k + 1] = (t[1] >> 3) | (t[2] << 2) | (t[3] << 7);
@@ -324,14 +340,19 @@ pub(crate) fn poly_frommsg(r: &mut Poly, msg: &[u8]) {
324340
/// Arguments: - [u8] msg: output message
325341
/// - const poly *a: input polynomial
326342
pub(crate) fn poly_tomsg(msg: &mut [u8], a: Poly) {
327-
let mut t;
343+
let mut t: u32;
328344
#[allow(clippy::needless_range_loop)]
329345
for i in 0..KYBER_N / 8 {
330346
msg[i] = 0;
331347
for j in 0..8 {
332-
t = a.coeffs[8 * i + j];
333-
t += (t >> 15) & KYBER_Q as i16;
334-
t = (((t << 1) + KYBER_Q as i16 / 2) / KYBER_Q as i16) & 1;
348+
t = a.coeffs[8 * i + j] as u32;
349+
350+
t <<= 1;
351+
t = t.wrapping_add(1665);
352+
t = t.wrapping_mul(80635);
353+
t >>= 28;
354+
t &= 1;
355+
335356
msg[i] |= (t << j) as u8;
336357
}
337358
}

src/reference/polyvec.rs

+19-17
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,17 @@ pub(crate) fn polyvec_compress(r: &mut [u8], a: Polyvec) {
2929
let mut idx = 0usize;
3030
for i in 0..KYBER_SECURITY_PARAMETER {
3131
for j in 0..KYBER_N / 8 {
32-
for k in 0..8 {
33-
t[k] = a.vec[i].coeffs[8 * j + k] as u16;
34-
t[k] = t[k].wrapping_add(
35-
(((t[k] as i16) >> 15) & KYBER_Q as i16) as u16,
32+
for (k, t_k) in t.iter_mut().enumerate() {
33+
*t_k = a.vec[i].coeffs[8 * j + k] as u16;
34+
*t_k = t_k.wrapping_add(
35+
((((*t_k as i16) >> 15) & KYBER_Q as i16)
36+
as u16),
3637
);
37-
t[k] = (((((t[k] as u32) << 11)
38-
+ KYBER_Q as u32 / 2)
39-
/ KYBER_Q as u32)
40-
& 0x7ff) as u16;
38+
let mut tmp: u64 =
39+
((*t_k as u64) << 11) + (KYBER_Q as u64 / 2);
40+
tmp *= 20642679;
41+
tmp >>= 36;
42+
*t_k = (tmp as u16) & 0x7ff;
4143
}
4244
r[idx] = (t[0]) as u8;
4345
r[idx + 1] = ((t[0] >> 8) | (t[1] << 3)) as u8;
@@ -61,16 +63,16 @@ pub(crate) fn polyvec_compress(r: &mut [u8], a: Polyvec) {
6163
let mut idx = 0usize;
6264
for i in 0..KYBER_SECURITY_PARAMETER {
6365
for j in 0..KYBER_N / 4 {
64-
for (k, item) in t.iter_mut().enumerate() {
65-
*item = a.vec[i].coeffs[4 * j + k] as u16;
66-
*item = item.wrapping_add(
67-
(((*item as i16) >> 15) & KYBER_Q as i16)
68-
as u16,
66+
for (k, t_k) in t.iter_mut().enumerate() {
67+
*t_k = a.vec[i].coeffs[4 * j + k] as u16;
68+
*t_k = t_k.wrapping_add(
69+
(((*t_k as i16) >> 15) & KYBER_Q as i16) as u16,
6970
);
70-
*item = (((((*item as u32) << 10)
71-
+ KYBER_Q as u32 / 2)
72-
/ KYBER_Q as u32)
73-
& 0x3ff) as u16;
71+
let mut tmp: u64 =
72+
((*t_k as u64) << 10) + (KYBER_Q as u64 / 2);
73+
tmp *= 20642679;
74+
tmp >>= 36;
75+
*t_k = (tmp as u16) & 0x3ff;
7476
}
7577
r[idx] = (t[0]) as u8;
7678
r[idx + 1] = ((t[0] >> 8) | (t[1] << 2)) as u8;

tests/test_error.rs

+9
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ fn test_kyber_lib_error_display() {
3434
error.to_string(),
3535
"The secret and public key given does not match."
3636
);
37+
let error = KyberLibError::InvalidLength;
38+
assert_eq!(
39+
error.to_string(),
40+
"The length of the input buffer is invalid."
41+
);
3742
}
3843

3944
#[test]
@@ -54,6 +59,10 @@ fn test_kyber_lib_error_partial_eq() {
5459
let error2 = KyberLibError::InvalidKey;
5560
assert_eq!(error1, error2);
5661

62+
let error1 = KyberLibError::InvalidLength;
63+
let error2 = KyberLibError::InvalidLength;
64+
assert_eq!(error1, error2);
65+
5766
let error1 = KyberLibError::InvalidInput;
5867
let error2 = KyberLibError::Decapsulation;
5968
assert_ne!(error1, error2);

0 commit comments

Comments
 (0)