Skip to content

Commit 12712ba

Browse files
author
Ahmed
committed
bug fixes and test
Signed-off-by: Ahmed <>
1 parent d94d7f4 commit 12712ba

File tree

5 files changed

+247
-5
lines changed

5 files changed

+247
-5
lines changed

ntru/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@ sha2 = "0.10.8"
1111
[dev-dependencies]
1212
aes="0.8.4"
1313
hex="0.4.3"
14+
hybrid-array = { path="../../hybrid-array", features = ["extra-sizes"] }
1415
itertools = "0.13.0"
1516
rayon="1.10.0"

ntru/src/encoded/streamlined.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,10 @@ fn rounded_encode<Params: NtruCommonUtils + StreamlinedNtru>(
4747
let mut M: Array<u16, Params::P> = Array::default();
4848
let mut out = Array::default();
4949
for i in 0..Params::P::USIZE {
50-
R[i] = ((*r.0[i] as u32 + Params::Q12 as u32).wrapping_mul(10923) >> 15) as u16;
50+
R[i] = ((*r.0[i] as u32)
51+
.wrapping_add(Params::Q12 as u32)
52+
.wrapping_mul(10923)
53+
>> 15) as u16;
5154
}
5255
for i in 0..Params::P::USIZE {
5356
M[i] = (Params::Q + 2) / 3;

ntru/src/kem.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@ pub struct CihpherText<Params: NtruCommonUtils> {
1818
}
1919

2020
impl<T: NtruCommonUtils> CihpherText<T> {
21-
#[must_use]pub fn to_bytes(&self) -> Vec<u8> {
21+
#[must_use]
22+
pub fn to_bytes(&self) -> Vec<u8> {
2223
let mut bytes = Vec::new();
2324
bytes.extend_from_slice(&self.c);
2425
bytes.extend_from_slice(&self.cache);
2526
bytes
2627
}
27-
#[must_use]pub fn from_bytes(bytes: &[u8]) -> Self {
28+
#[must_use]
29+
pub fn from_bytes(bytes: &[u8]) -> Self {
2830
let c = bytes[..T::CipherTextBytes::USIZE].try_into().unwrap();
2931
let cache = bytes[T::CipherTextBytes::USIZE..].try_into().unwrap();
3032
CihpherText { c, cache }

ntru/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ extern crate alloc;
2222
mod algebra;
2323
mod const_time;
2424
pub mod core;
25-
mod encoded;
26-
mod hashes;
25+
pub mod encoded;
26+
pub mod hashes;
2727
pub mod kem;
2828
pub mod params;

ntru/tests/nist.rs

Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
//! Checking that our NTRU-Prime is generating same output when compared to nist submission
2+
3+
use std::{
4+
fs::File,
5+
io::{BufRead, BufReader},
6+
};
7+
8+
use aes::{
9+
cipher::{generic_array::GenericArray, BlockEncrypt, KeyInit},
10+
Aes256,
11+
};
12+
use hybrid_array::sizes::{U1013, U1277, U16, U32, U653, U761, U857, U953};
13+
use itertools::{izip, Itertools};
14+
use ntru::{
15+
encoded::AsymEnc,
16+
hashes::HashOps,
17+
kem::{decap, encap, key_gen},
18+
params::{NtruCommonUtils, Streamlined},
19+
};
20+
use rand_core::{CryptoRng, RngCore, SeedableRng};
21+
22+
fn aes256_ecb(
23+
key: &GenericArray<u8, U32>,
24+
crt: &GenericArray<u8, U16>,
25+
buffer: &mut GenericArray<u8, U16>,
26+
) {
27+
let cipher = Aes256::new(key);
28+
cipher.encrypt_block_b2b(crt, buffer);
29+
}
30+
struct AesDrbg {
31+
key: GenericArray<u8, U32>,
32+
v: GenericArray<u8, U16>,
33+
}
34+
impl AesDrbg {
35+
fn update(&mut self, seed_material: Option<&[u8; 48]>) {
36+
let mut tmp: [GenericArray<u8, U16>; 3] = Default::default();
37+
for i in 0..3 {
38+
for j in (1..=15).rev() {
39+
if self.v[j] == 0xff {
40+
self.v[j] = 0x00;
41+
} else {
42+
self.v[j] += 1;
43+
break;
44+
}
45+
}
46+
aes256_ecb(&self.key, &self.v, &mut tmp[i]);
47+
}
48+
if let Some(seed) = seed_material {
49+
for i in 0..48 {
50+
tmp[i / 16][i % 16] ^= seed[i];
51+
}
52+
}
53+
self.key[..16].copy_from_slice(&tmp[0]);
54+
self.key[16..].copy_from_slice(&tmp[1]);
55+
self.v.copy_from_slice(&tmp[2]);
56+
}
57+
}
58+
impl CryptoRng for AesDrbg {}
59+
60+
struct U8L48([u8; 48]);
61+
62+
impl Default for U8L48 {
63+
fn default() -> Self {
64+
U8L48([0; 48])
65+
}
66+
}
67+
68+
impl AsMut<[u8]> for U8L48 {
69+
fn as_mut(&mut self) -> &mut [u8] {
70+
&mut self.0
71+
}
72+
}
73+
impl AsRef<[u8]> for U8L48 {
74+
fn as_ref(&self) -> &[u8] {
75+
&self.0
76+
}
77+
}
78+
79+
impl SeedableRng for AesDrbg {
80+
type Seed = U8L48;
81+
82+
fn from_seed(seed: Self::Seed) -> Self {
83+
let entropy_input = seed.0;
84+
let mut drbg = AesDrbg {
85+
key: GenericArray::default(),
86+
v: GenericArray::default(),
87+
};
88+
drbg.update(Some(&entropy_input));
89+
drbg
90+
}
91+
}
92+
93+
impl RngCore for AesDrbg {
94+
fn next_u32(&mut self) -> u32 {
95+
let mut bytes = [0u8; 4];
96+
self.fill_bytes(&mut bytes);
97+
u32::from_le_bytes(bytes)
98+
}
99+
100+
fn next_u64(&mut self) -> u64 {
101+
unimplemented!()
102+
}
103+
104+
fn fill_bytes(&mut self, dest: &mut [u8]) {
105+
let mut block = GenericArray::<u8, U16>::default();
106+
let mut i = 0;
107+
let mut xlen = dest.len();
108+
while xlen > 0 {
109+
for j in (1..=15).rev() {
110+
if self.v[j] == 0xff {
111+
self.v[j] = 0x00;
112+
} else {
113+
self.v[j] += 1;
114+
break;
115+
}
116+
}
117+
aes256_ecb(&self.key, &self.v, &mut block);
118+
if xlen > 15 {
119+
dest[i..i + 16].copy_from_slice(&block);
120+
i += 16;
121+
xlen -= 16;
122+
} else {
123+
dest[i..i + xlen].copy_from_slice(&block[..xlen]);
124+
xlen = 0;
125+
}
126+
}
127+
self.update(None)
128+
}
129+
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> {
130+
self.fill_bytes(dest);
131+
Ok(())
132+
}
133+
}
134+
135+
fn seed_builder(max: usize) -> Vec<U8L48> {
136+
let mut seeds = Vec::with_capacity(100);
137+
let mut entropy = [0u8; 48];
138+
for i in 0u8..48 {
139+
entropy[i as usize] = i;
140+
}
141+
let mut rng = AesDrbg::from_seed(U8L48(entropy));
142+
for _ in 0..max {
143+
let mut s = U8L48::default();
144+
rng.fill_bytes(&mut s.0);
145+
seeds.push(s)
146+
}
147+
seeds
148+
}
149+
150+
struct TestEntry {
151+
seed: Vec<u8>,
152+
pk: Vec<u8>,
153+
sk: Vec<u8>,
154+
ct: Vec<u8>,
155+
ss: Vec<u8>,
156+
}
157+
158+
impl TestEntry {
159+
fn from_file(path: &str) -> Vec<TestEntry> {
160+
let file = File::open(path).unwrap();
161+
let mut ret = Vec::with_capacity(100);
162+
for mut lines in &BufReader::new(file)
163+
.lines()
164+
.flatten()
165+
.filter(|x| !(x.is_empty() || x.starts_with('#')))
166+
.chunks(6)
167+
{
168+
lines.next(); // we ignore the count line
169+
let seed = hex::decode(lines.next().unwrap().split(" ").last().unwrap()).unwrap();
170+
let pk = hex::decode(lines.next().unwrap().split(" ").last().unwrap()).unwrap();
171+
let sk = hex::decode(lines.next().unwrap().split(" ").last().unwrap()).unwrap();
172+
let ct = hex::decode(lines.next().unwrap().split(" ").last().unwrap()).unwrap();
173+
let ss = hex::decode(lines.next().unwrap().split(" ").last().unwrap()).unwrap();
174+
ret.push(TestEntry {
175+
seed,
176+
pk,
177+
sk,
178+
ct,
179+
ss,
180+
});
181+
}
182+
assert_eq!(ret.len(), 100);
183+
ret
184+
}
185+
}
186+
187+
#[test]
188+
fn test_rng() {
189+
let seeds = seed_builder(100);
190+
let tests = TestEntry::from_file("test_data/ntrulpr653.rsp");
191+
for i in 0..100 {
192+
assert_eq!(seeds[i].as_ref(), &tests[i].seed)
193+
}
194+
}
195+
196+
fn test_config<T: NtruCommonUtils + AsymEnc + HashOps>(config: &str) {
197+
let seeds = seed_builder(100);
198+
let path = format!("test_data/{config}.rsp");
199+
let tests = TestEntry::from_file(&path);
200+
for (seed, test) in izip!(seeds, tests) {
201+
let mut rng = AesDrbg::from_seed(seed);
202+
let (sk, pk) = key_gen::<T>(&mut rng);
203+
assert_eq!(&pk.0 as &[u8], &test.pk);
204+
assert_eq!(sk.to_bytes(), test.sk);
205+
let (ct, ss) = encap(&mut rng, &pk);
206+
assert_eq!(ct.to_bytes(), test.ct);
207+
assert_eq!(&ss as &[u8], &test.ss);
208+
//let ss2: [u8; 32] = decap(&ct, &sk);
209+
//assert_eq!(&ss2 as &[u8], &test.ss);
210+
}
211+
}
212+
213+
#[test]
214+
fn test_sntrup1013() {
215+
test_config::<Streamlined<U1013>>("sntrup1013");
216+
}
217+
#[test]
218+
fn test_sntrup1277() {
219+
test_config::<Streamlined<U1277>>("sntrup1277");
220+
}
221+
#[test]
222+
fn test_sntrup653() {
223+
test_config::<Streamlined<U653>>("sntrup653");
224+
}
225+
#[test]
226+
fn test_sntrup761() {
227+
test_config::<Streamlined<U761>>("sntrup761");
228+
}
229+
#[test]
230+
fn test_sntrup857() {
231+
test_config::<Streamlined<U857>>("sntrup857");
232+
}
233+
#[test]
234+
fn test_sntrup953() {
235+
test_config::<Streamlined<U953>>("sntrup953");
236+
}

0 commit comments

Comments
 (0)