1
1
mirror of https://github.com/henrydcase/pqc.git synced 2024-11-22 07:35:38 +00:00

[cavptool] update

This commit is contained in:
Henry Case 2022-03-09 14:09:28 +00:00
parent b01ea397e2
commit 18a0140f44
4 changed files with 135 additions and 25 deletions

View File

@ -83,9 +83,9 @@ jobs:
- name: Run KAT tests - name: Run KAT tests
run: | run: |
cd test/katrunner && cd test/katrunner &&
curl http://amongbytes.com/~flowher/permalinks/kat.zip --output kat.zip curl http://nice.pqsh.net/files/kat.zip --output kat.zip
unzip kat.zip unzip kat.zip
cargo run --release -- --katdir KAT cargo run --release -- --katdir kat
MEMSAN: MEMSAN:
name: Memory Sanitizer build name: Memory Sanitizer build
runs-on: [ubuntu-20.04] runs-on: [ubuntu-20.04]

View File

@ -14,7 +14,7 @@ extern "C" {
#include "kem/kyber/kyber512/avx2/ntt.h" #include "kem/kyber/kyber512/avx2/ntt.h"
} }
auto cpucycle = [](benchmark::State &st, int64_t cycles) { static auto cpucycle = [](benchmark::State &st, int64_t cycles) {
st.counters["CPU cycles: mean"] = benchmark::Counter( st.counters["CPU cycles: mean"] = benchmark::Counter(
cycles, benchmark::Counter::kAvgIterations | benchmark::Counter::kResultNoFormat); cycles, benchmark::Counter::kAvgIterations | benchmark::Counter::kResultNoFormat);
}; };

View File

@ -11,7 +11,7 @@
#define ARRAY_LEN(X) sizeof(X)/sizeof(X[0]) #define ARRAY_LEN(X) sizeof(X)/sizeof(X[0])
auto cpucycle = [](benchmark::State &st, int64_t cycles) { static auto cpucycle = [](benchmark::State &st, int64_t cycles) {
st.counters["CPU cycles: mean"] = benchmark::Counter( st.counters["CPU cycles: mean"] = benchmark::Counter(
cycles, benchmark::Counter::kAvgIterations | benchmark::Counter::kResultNoFormat); cycles, benchmark::Counter::kAvgIterations | benchmark::Counter::kResultNoFormat);
}; };

View File

@ -5,12 +5,20 @@ use std::env;
use std::path::Path; use std::path::Path;
use threadpool::ThreadPool; use threadpool::ThreadPool;
use std::convert::TryInto; use std::convert::TryInto;
use aes_ctr_drbg::DrbgCtx; use aes_ctr_drbg::DrbgCtx as AesCtrDrbgCtx;
use std::collections::HashMap; use std::collections::HashMap;
use std::thread; use std::thread;
use std::sync::Mutex; use std::sync::Mutex;
use lazy_static::lazy_static; use lazy_static::lazy_static;
#[derive(PartialEq)]
enum TestStatus {
Processed,
// For now this variant is not used
#[allow(dead_code)]
Skipped,
}
// Used for signature algorithm registration // Used for signature algorithm registration
macro_rules! REG_SIGN { macro_rules! REG_SIGN {
($ID:expr,$F:expr) => { ($ID:expr,$F:expr) => {
@ -33,13 +41,88 @@ macro_rules! REG_KEM {
execfn: test_kem_vector} execfn: test_kem_vector}
} }
} }
// Needed to implement get_rng.
trait Rng {
fn init(&mut self, entropy: &[u8], diversifier: Vec<u8>);
fn get_random(&mut self, data: &mut [u8]);
}
// DummyDrbg just returns value of self.data. Useful
// in testing functions that are non-deterministic.
struct DummyDrbgContext{
data: Vec<u8>,
}
impl Rng for DummyDrbgContext {
fn init(&mut self, entropy: &[u8], _diversifier: Vec<u8>) {
self.data = entropy.to_vec();
}
fn get_random(&mut self, data: &mut [u8]) {
for i in 0..std::cmp::min(data.len(), self.data.len()) {
data[i] = self.data[i];
}
}
}
// DrbgCtx uses AES-CTR to generate random byte-string.
impl Rng for AesCtrDrbgCtx {
fn init(&mut self, entropy: &[u8], diversifier: Vec<u8>) {
self.init(entropy, diversifier);
}
fn get_random(&mut self, data: &mut [u8]) {
self.get_random(data);
}
}
// Allows to use some custom Drbg that implements
// Rng trait. In Current implementation if `use_aes`
// is set then AesCtrDrbgCtx is used (default), otherwise
// DummyDrbg is used.
struct CustomizableDrbgCtx{
aes_drbg: AesCtrDrbgCtx,
dummy: DummyDrbgContext,
use_aes: bool,
}
impl CustomizableDrbgCtx{
pub const fn new() -> Self {
Self {
use_aes: true,
aes_drbg: AesCtrDrbgCtx::new(),
dummy: DummyDrbgContext{
data: Vec::new(),
},
}
}
// TODO: possibily to be done with Box<> or something
fn get_rng(&mut self) -> &mut dyn Rng {
if self.use_aes {
return &mut self.aes_drbg;
} else {
return &mut self.dummy;
}
}
pub fn init(&mut self, entropy: &[u8], diversifier: Vec<u8>, is_fixed: bool) {
if is_fixed {
self.use_aes = false;
}
self.get_rng().init(entropy, diversifier);
}
pub fn get_random(&mut self, data: &mut [u8]) {
self.get_rng().get_random(data);
}
}
// Stores one DRBG context per execution thread. DRBG // Stores one DRBG context per execution thread. DRBG
// is inserted in this map, just after thread starts // is inserted in this map, just after thread starts
// and removed after thread is finished. Operation // and removed after thread is finished. Operation
// is synchronized. // is synchronized.
lazy_static! { lazy_static! {
static ref DRBGV: Mutex<HashMap<thread::ThreadId, DrbgCtx>> = Mutex::new(HashMap::new()); static ref DRBGV: Mutex<
HashMap<thread::ThreadId, CustomizableDrbgCtx>> = Mutex::new(HashMap::new());
} }
// We have to provide the implementation for randombytes // We have to provide the implementation for randombytes
@ -53,22 +136,21 @@ unsafe extern "C" fn randombytes(
if let Some(drbg) = DRBGV.lock().unwrap().get_mut(&thread::current().id()) { if let Some(drbg) = DRBGV.lock().unwrap().get_mut(&thread::current().id()) {
drbg.get_random(&mut slice); drbg.get_random(&mut slice);
} }
} }
type ExecFn = fn(&TestVector); type ExecFn = fn(&TestVector) -> TestStatus;
struct Register { struct Register {
kat: katwalk::reader::Kat, kat: katwalk::reader::Kat,
execfn: ExecFn, execfn: ExecFn,
} }
fn test_sign_vector(el: &TestVector) { fn test_sign_vector(el: &TestVector) -> TestStatus {
let mut pk = Vec::new(); let mut pk = Vec::new();
let mut sk = Vec::new(); let mut sk = Vec::new();
let mut sm = Vec::new(); let mut sm = Vec::new();
if let Some(drbg) = DRBGV.lock().unwrap().get_mut(&thread::current().id()) { if let Some(drbg) = DRBGV.lock().unwrap().get_mut(&thread::current().id()) {
drbg.init(el.sig.seed.as_slice(), Vec::new()); drbg.init(el.sig.seed.as_slice(), Vec::new(), false);
} }
unsafe { unsafe {
@ -114,17 +196,18 @@ fn test_sign_vector(el: &TestVector) {
el.sig.msg.as_ptr(), el.sig.msg.len() as u64, el.sig.msg.as_ptr(), el.sig.msg.len() as u64,
el.sig.pk.as_ptr()), el.sig.pk.as_ptr()),
true); true);
return TestStatus::Processed;
} }
} }
fn test_kem_vector(el: &TestVector) { fn test_kem_vector(el: &TestVector) -> TestStatus {
let mut pk = Vec::new(); let mut pk = Vec::new();
let mut sk = Vec::new(); let mut sk = Vec::new();
let mut ct = Vec::new(); let mut ct = Vec::new();
let mut ss = Vec::new(); let mut ss = Vec::new();
if let Some(drbg) = DRBGV.lock().unwrap().get_mut(&thread::current().id()) { if let Some(drbg) = DRBGV.lock().unwrap().get_mut(&thread::current().id()) {
drbg.init(el.kem.seed.as_slice(), Vec::new()); drbg.init(el.kem.seed.as_slice(), Vec::new(), false);
} }
unsafe { unsafe {
@ -161,6 +244,7 @@ fn test_kem_vector(el: &TestVector) {
true); true);
assert_eq!(ss, el.kem.ss); assert_eq!(ss, el.kem.ss);
} }
return TestStatus::Processed;
} }
// KAT test register // KAT test register
@ -221,30 +305,50 @@ const KATS: &'static[Register] = &[
REG_KEM!(PQC_ALG_KEM_SIKE434, "round3/sike/PQCkemKAT_374.rsp"), REG_KEM!(PQC_ALG_KEM_SIKE434, "round3/sike/PQCkemKAT_374.rsp"),
]; ];
fn execute(kat_dir: String, thc: usize, file_filter: &str) { // Main loop
fn execute(kat_dir: String, thc: usize, file_filter: &str) -> u8 {
// Can't do multi-threads as DRBG context is global // Can't do multi-threads as DRBG context is global
let pool = ThreadPool::new(thc); let pool = ThreadPool::new(thc);
let path = Path::new(&kat_dir);
let mut code: u8 = 0;
for k in KATS.iter() { for k in KATS.iter() {
let tmp = kat_dir.clone();
if !file_filter.is_empty() && !k.kat.kat_file.contains(file_filter) { if !file_filter.is_empty() && !k.kat.kat_file.contains(file_filter) {
continue; continue;
} }
// Check if file exists
let filepath = path.join(k.kat.kat_file);
let fhandle = match File::open(filepath) {
Ok(fhandle) => fhandle,
Err(_) => {
eprintln!("File {:?} doesn't exist", k.kat.kat_file);
code |= 1;
continue;
}
};
let buf = BufReader::new(fhandle);
pool.execute(move || { pool.execute(move || {
DRBGV.lock().unwrap() DRBGV.lock().unwrap()
.insert(thread::current().id(), DrbgCtx::new()); .insert(thread::current().id(), CustomizableDrbgCtx::new());
let f = Path::new(&tmp.to_string()).join(k.kat.kat_file); let proc = KatReader::new(buf, k.kat.scheme_type, k.kat.scheme_id);
let file = File::open(format!("{}", f.to_str().unwrap())); let iter = proc.into_iter();
println!("Processing file: {}", Path::new(k.kat.kat_file).to_str().unwrap()); let mut processed = 0;
let b = BufReader::new(file.unwrap()); let mut skipped = 0;
for el in iter {
for el in KatReader::new(b, k.kat.scheme_type, k.kat.scheme_id) { let status = (k.execfn)(&el);
(k.execfn)(&el); match status {
TestStatus::Processed => processed += 1,
TestStatus::Skipped => skipped += 1,
}
} }
DRBGV.lock().unwrap() println!("{:60} KAT# : {:10}{:10}", k.kat.kat_file, processed,skipped);
.remove(&thread::current().id()); DRBGV.lock().unwrap().remove(&thread::current().id());
}); });
} }
pool.join(); pool.join();
return code;
} }
fn main() { fn main() {
@ -259,6 +363,7 @@ fn main() {
argmap.insert(&args[i], &args[i+1]); argmap.insert(&args[i], &args[i+1]);
} }
// Number of threads to be used
let thread_number: usize = match argmap.get(&"--threads".to_string()) { let thread_number: usize = match argmap.get(&"--threads".to_string()) {
Some(n) => n.to_string().parse::<usize>().unwrap(), Some(n) => n.to_string().parse::<usize>().unwrap(),
None => 4 /* by default 4 threads */, None => 4 /* by default 4 threads */,
@ -270,8 +375,13 @@ fn main() {
None => "" None => ""
}; };
// Header for the results
println!("Test file{:60}Processed Skipped", "");
println!("------------------------------------------------------------------------------------------");
match argmap.get(&"--katdir".to_string()) { match argmap.get(&"--katdir".to_string()) {
Some(kat_dir) => execute(kat_dir.to_string(), thread_number, file_filter), Some(kat_dir) =>
std::process::exit(
execute(kat_dir.to_string(), thread_number, file_filter).into()),
None => panic!("--katdir required") None => panic!("--katdir required")
}; };