dilithium, hybrid, ctap implementation, experiments
This commit is contained in:
@@ -17,27 +17,42 @@
|
||||
extern crate alloc;
|
||||
extern crate lang_items;
|
||||
|
||||
use alloc::format;
|
||||
use alloc::vec::Vec;
|
||||
use core::fmt::Write;
|
||||
use crypto::{aes256, cbc, ecdsa, sha256, Hash256};
|
||||
use crypto::sha256::Sha256;
|
||||
use crypto::{ecdsa, hybrid};
|
||||
use libtock_drivers::console::Console;
|
||||
use libtock_drivers::result::FlexUnwrap;
|
||||
use libtock_drivers::timer;
|
||||
use libtock_drivers::timer::{Timer, Timestamp};
|
||||
use rng256::TockRng256;
|
||||
use rng256::Rng256;
|
||||
// use ctap2::env::tock::{take_storage, TockStorage};
|
||||
// use persistent_store::Store;
|
||||
|
||||
libtock_core::stack_size! {0x800}
|
||||
libtock_core::stack_size! {0x11800}
|
||||
|
||||
/*fn boot_store(mut storage: TockStorage, erase: bool) -> Store<TockStorage> {
|
||||
use persistent_store::Storage;
|
||||
let num_pages = storage.num_pages();
|
||||
if erase {
|
||||
for page in 0..num_pages {
|
||||
storage.erase_page(page).unwrap();
|
||||
}
|
||||
}
|
||||
Store::new(storage).ok().unwrap()
|
||||
}*/
|
||||
|
||||
fn main() {
|
||||
// Fix to be faster.
|
||||
//let storage = take_storage().unwrap();
|
||||
//let mut _store = boot_store(storage, true);
|
||||
|
||||
let mut console = Console::new();
|
||||
let mut rng = rng256::TockRng256 {};
|
||||
// Setup the timer with a dummy callback (we only care about reading the current time, but the
|
||||
// API forces us to set an alarm callback too).
|
||||
let mut with_callback = timer::with_callback(|_, _| {});
|
||||
let timer = with_callback.init().flex_unwrap();
|
||||
|
||||
let mut rng = TockRng256 {};
|
||||
|
||||
writeln!(console, "****************************************").unwrap();
|
||||
writeln!(
|
||||
console,
|
||||
@@ -46,136 +61,133 @@ fn main() {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// AES
|
||||
bench(&mut console, &timer, "aes256::EncryptionKey::new", || {
|
||||
aes256::EncryptionKey::new(&[0; 32]);
|
||||
});
|
||||
let ek = aes256::EncryptionKey::new(&[0; 32]);
|
||||
bench(&mut console, &timer, "aes256::DecryptionKey::new", || {
|
||||
aes256::DecryptionKey::new(&ek);
|
||||
});
|
||||
let dk = aes256::DecryptionKey::new(&ek);
|
||||
|
||||
bench(
|
||||
custom_bench(
|
||||
&mut console,
|
||||
&timer,
|
||||
"aes256::EncryptionKey::encrypt_block",
|
||||
|| {
|
||||
ek.encrypt_block(&mut [0; 16]);
|
||||
},
|
||||
);
|
||||
bench(
|
||||
&mut console,
|
||||
&timer,
|
||||
"aes256::DecryptionKey::decrypt_block",
|
||||
|| {
|
||||
dk.decrypt_block(&mut [0; 16]);
|
||||
"ECDSA keygen",
|
||||
1000,
|
||||
|| {},
|
||||
|()| {
|
||||
let k = ecdsa::SecKey::gensk(&mut rng);
|
||||
k.genpk();
|
||||
},
|
||||
);
|
||||
|
||||
// CBC
|
||||
let mut blocks = Vec::new();
|
||||
for i in 0..8 {
|
||||
blocks.resize(1 << (i + 4), 0);
|
||||
bench(
|
||||
&mut console,
|
||||
&timer,
|
||||
&format!("cbc::cbc_encrypt({} bytes)", blocks.len()),
|
||||
|| {
|
||||
cbc::cbc_encrypt(&ek, [0; 16], &mut blocks);
|
||||
},
|
||||
);
|
||||
}
|
||||
drop(blocks);
|
||||
|
||||
let mut blocks = Vec::new();
|
||||
for i in 0..8 {
|
||||
blocks.resize(1 << (i + 4), 0);
|
||||
bench(
|
||||
&mut console,
|
||||
&timer,
|
||||
&format!("cbc::cbc_decrypt({} bytes)", blocks.len()),
|
||||
|| {
|
||||
cbc::cbc_decrypt(&dk, [0; 16], &mut blocks);
|
||||
},
|
||||
);
|
||||
}
|
||||
drop(blocks);
|
||||
|
||||
// SHA-256
|
||||
let mut contents = Vec::new();
|
||||
for i in 0..8 {
|
||||
contents.resize(16 << i, 0);
|
||||
bench(
|
||||
&mut console,
|
||||
&timer,
|
||||
&format!("sha256::Sha256::update({} bytes)", contents.len()),
|
||||
|| {
|
||||
let mut sha = sha256::Sha256::new();
|
||||
sha.update(&contents);
|
||||
sha.finalize();
|
||||
},
|
||||
);
|
||||
}
|
||||
drop(contents);
|
||||
|
||||
// ECDSA
|
||||
bench(&mut console, &timer, "ecdsa::SecKey::gensk", || {
|
||||
ecdsa::SecKey::gensk(&mut rng);
|
||||
});
|
||||
let k = ecdsa::SecKey::gensk(&mut rng);
|
||||
bench(&mut console, &timer, "ecdsa::SecKey::genpk", || {
|
||||
k.genpk();
|
||||
});
|
||||
bench(
|
||||
custom_bench(
|
||||
&mut console,
|
||||
&timer,
|
||||
"ecdsa::SecKey::sign_rng::<sha256::Sha256, _>",
|
||||
"ECDSA sign",
|
||||
1000,
|
||||
|| {
|
||||
k.sign_rng::<sha256::Sha256, _>(&[], &mut rng);
|
||||
let k = ecdsa::SecKey::gensk(&mut rng);
|
||||
let mut m = [0; 64];
|
||||
rng.fill_bytes(&mut m);
|
||||
(k, m)
|
||||
},
|
||||
);
|
||||
bench(
|
||||
&mut console,
|
||||
&timer,
|
||||
"ecdsa::SecKey::sign_rfc6979::<sha256::Sha256>",
|
||||
|| {
|
||||
k.sign_rfc6979::<sha256::Sha256>(&[]);
|
||||
|(k, m)| {
|
||||
k.sign_rfc6979::<Sha256>(&m);
|
||||
},
|
||||
);
|
||||
|
||||
writeln!(console, "****************************************").unwrap();
|
||||
writeln!(console, "All the benchmarks are done.\nHave a nice day!").unwrap();
|
||||
writeln!(console, "****************************************").unwrap();
|
||||
custom_bench(
|
||||
&mut console,
|
||||
&timer,
|
||||
"dilithium::SecKey::gensk_with_pk",
|
||||
1000,
|
||||
|| {},
|
||||
|()| {
|
||||
dilithium::sign::SecKey::gensk_with_pk(&mut rng);
|
||||
},
|
||||
);
|
||||
|
||||
custom_bench(
|
||||
&mut console,
|
||||
&timer,
|
||||
"dilithium::SecKey::sign",
|
||||
1000,
|
||||
|| {
|
||||
let sk = dilithium::sign::SecKey::gensk(&mut rng);
|
||||
let mut m = [0; 64];
|
||||
rng.fill_bytes(&mut m);
|
||||
(sk, m)
|
||||
},
|
||||
|(sk, m)| {
|
||||
sk.sign(&m);
|
||||
},
|
||||
);
|
||||
|
||||
custom_bench(
|
||||
&mut console,
|
||||
&timer,
|
||||
"hybrid::SecKey::gensk_with_pk",
|
||||
1000,
|
||||
|| {},
|
||||
|()| {
|
||||
hybrid::SecKey::gensk_with_pk(&mut rng);
|
||||
},
|
||||
);
|
||||
|
||||
custom_bench(
|
||||
&mut console,
|
||||
&timer,
|
||||
"hybrid::SecKey::sign",
|
||||
1000,
|
||||
|| {
|
||||
let sk = hybrid::SecKey::gensk(&mut rng);
|
||||
let mut m = [0; 64];
|
||||
rng.fill_bytes(&mut m);
|
||||
(sk, m)
|
||||
},
|
||||
|(sk, m)| {
|
||||
sk.sign_rfc6979::<Sha256>(&m).to_asn1_der();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn bench<F>(console: &mut Console, timer: &Timer, title: &str, mut f: F)
|
||||
where
|
||||
F: FnMut(),
|
||||
fn custom_bench<I, O, F, S>(
|
||||
console: &mut Console,
|
||||
timer: &Timer,
|
||||
title: &str,
|
||||
iter_count: usize,
|
||||
mut setup: S,
|
||||
mut f: F,
|
||||
) where
|
||||
S: FnMut() -> I,
|
||||
F: FnMut(I) -> O,
|
||||
{
|
||||
writeln!(console, "****************************************").unwrap();
|
||||
writeln!(console, "Benchmarking: {}", title).unwrap();
|
||||
writeln!(console, "----------------------------------------").unwrap();
|
||||
let mut count = 1;
|
||||
for _ in 0..30 {
|
||||
|
||||
let mut elapsed = 0.0;
|
||||
|
||||
for _ in 1..(iter_count + 1) {
|
||||
let inputs = setup();
|
||||
let start = Timestamp::<f64>::from_clock_value(timer.get_current_clock().flex_unwrap());
|
||||
for _ in 0..count {
|
||||
f();
|
||||
}
|
||||
f(inputs);
|
||||
let end = Timestamp::<f64>::from_clock_value(timer.get_current_clock().flex_unwrap());
|
||||
let elapsed = (end - start).ms();
|
||||
writeln!(
|
||||
console,
|
||||
"{} ms elapsed for {} iterations ({} ms/iter)",
|
||||
elapsed,
|
||||
count,
|
||||
elapsed / (count as f64)
|
||||
)
|
||||
.unwrap();
|
||||
console.flush();
|
||||
if elapsed > 1000.0 {
|
||||
break;
|
||||
|
||||
let mut run_duration = (end - start).ms();
|
||||
|
||||
// After 512 seconds, we get a negative difference between the start
|
||||
// time and the end time.
|
||||
if run_duration < 0.0 {
|
||||
run_duration += 512.0 * 1000.0;
|
||||
}
|
||||
count <<= 1;
|
||||
|
||||
elapsed += run_duration;
|
||||
|
||||
writeln!(console, "{},", run_duration).unwrap();
|
||||
console.flush();
|
||||
}
|
||||
|
||||
writeln!(
|
||||
console,
|
||||
"Total: {} ms elapsed for {} iterations ({} ms/iter)",
|
||||
elapsed,
|
||||
iter_count,
|
||||
elapsed / (iter_count as f64)
|
||||
)
|
||||
.unwrap();
|
||||
console.flush();
|
||||
}
|
||||
|
||||
184
examples/measure_stack.rs
Normal file
184
examples/measure_stack.rs
Normal file
@@ -0,0 +1,184 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#![no_std]
|
||||
#![feature(asm)]
|
||||
#![feature(llvm_asm)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
extern crate alloc;
|
||||
extern crate lang_items;
|
||||
|
||||
use core::fmt::Write;
|
||||
use core::ptr;
|
||||
use crypto::sha256::Sha256;
|
||||
use crypto::{ecdsa, hybrid, sha256};
|
||||
use libtock_drivers::console::Console;
|
||||
|
||||
libtock_core::stack_size! {0x11800}
|
||||
|
||||
#[inline(never)]
|
||||
fn read_stack_pointer() -> u32 {
|
||||
let x = 1u32;
|
||||
let address = &x as *const u32;
|
||||
address as u32
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn print_stack_pointer(console: &mut Console) {
|
||||
let x = 1u32;
|
||||
writeln!(console, "Stack pointer: {:?}", &x as *const u32).unwrap();
|
||||
}
|
||||
|
||||
/// Writes a byte pattern to a memory range.
|
||||
///
|
||||
/// Since the stack grows to lower addresses, end < start.
|
||||
/// Addresses after start must be unused, i.e. start must be at least the current stack pointer.
|
||||
/// Addresses until end should be within the stack area.
|
||||
unsafe fn paint_memory(start: u32, end: u32) {
|
||||
for address in (end..start).step_by(4) {
|
||||
let p = address as *const u32;
|
||||
ptr::write(p as *mut u32, 0xCDCDCDCD);
|
||||
}
|
||||
}
|
||||
|
||||
/// Find the lowest address that does not have the 0xCD pattern.
|
||||
unsafe fn find_border(start: u32, end: u32) -> u32 {
|
||||
for address in (end..start).step_by(4) {
|
||||
let p = address as *const u32;
|
||||
if ptr::read(p) != 0xCDCDCDCD {
|
||||
return address;
|
||||
}
|
||||
}
|
||||
start
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
pub fn black_box<T>(dummy: T) -> T {
|
||||
unsafe { llvm_asm!("" : : "r"(&dummy)) }
|
||||
dummy
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn keygen_ecdsa(rng: &mut rng256::TockRng256) {
|
||||
let sk = ecdsa::SecKey::gensk(rng);
|
||||
black_box(sk);
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn keygen_dilithium(rng: &mut rng256::TockRng256) {
|
||||
let sk = dilithium::sign::SecKey::gensk(rng);
|
||||
black_box(sk);
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn keygen_hybrid(rng: &mut rng256::TockRng256) {
|
||||
let sk = hybrid::SecKey::gensk_with_pk(rng);
|
||||
black_box(sk);
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn sign_ecdsa(rng: &mut rng256::TockRng256, sk: &ecdsa::SecKey) {
|
||||
let sig = sk.sign_rng::<sha256::Sha256, _>(&[], rng);
|
||||
black_box(sig);
|
||||
}
|
||||
|
||||
fn sign_dilithium(sk: &dilithium::sign::SecKey) {
|
||||
let sig = sk.sign(&[]);
|
||||
black_box(sig);
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn sign_hybrid(sk: &hybrid::SecKey) {
|
||||
let sig = sk.sign_rfc6979::<Sha256>(&[]);
|
||||
black_box(sig);
|
||||
}
|
||||
|
||||
// Measure the stack usage of the method itself, plus a u32.
|
||||
#[inline(never)]
|
||||
fn dummy_test() {
|
||||
let x = 1u32;
|
||||
black_box(x);
|
||||
}
|
||||
|
||||
// Tests whether input parameters are correctly ignored in the measurement.
|
||||
#[inline(never)]
|
||||
fn param_test(big_param: &mut [u8; 0x1000]) {
|
||||
let x = 0x01;
|
||||
big_param[0] = x;
|
||||
black_box(x);
|
||||
}
|
||||
|
||||
fn write_result(console: &mut Console, text: &str, size: u32) {
|
||||
writeln!(console, "{} size: 0x{:08X}", text, size).unwrap();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut console = Console::new();
|
||||
|
||||
let x = 1u32;
|
||||
let sp = &x as *const u32;
|
||||
// Should be safe to write from here.
|
||||
let start = sp as u32 - 0x100u32;
|
||||
writeln!(console, "Search start address: 0x{:08X}", start).unwrap();
|
||||
print_stack_pointer(&mut console);
|
||||
|
||||
let mut rng = rng256::TockRng256 {};
|
||||
|
||||
unsafe { paint_memory(start, 0x20020000) };
|
||||
keygen_ecdsa(&mut rng);
|
||||
let min_address1 = unsafe { find_border(start, 0x20020000) };
|
||||
|
||||
unsafe { paint_memory(start, 0x20020000) };
|
||||
keygen_dilithium(&mut rng);
|
||||
let min_address2 = unsafe { find_border(start, 0x20020000) };
|
||||
|
||||
unsafe { paint_memory(start, 0x20020000) };
|
||||
keygen_hybrid(&mut rng);
|
||||
let min_address3 = unsafe { find_border(start, 0x20020000) };
|
||||
|
||||
let sk = ecdsa::SecKey::gensk(&mut rng);
|
||||
unsafe { paint_memory(start, 0x20020000) };
|
||||
sign_ecdsa(&mut rng, &sk);
|
||||
let min_address4 = unsafe { find_border(start, 0x20020000) };
|
||||
|
||||
let sk = dilithium::sign::SecKey::gensk(&mut rng);
|
||||
unsafe { paint_memory(start, 0x20020000) };
|
||||
sign_dilithium(&sk);
|
||||
let min_address5 = unsafe { find_border(start, 0x20020000) };
|
||||
|
||||
let sk = hybrid::SecKey::gensk(&mut rng);
|
||||
unsafe { paint_memory(start, 0x20020000) };
|
||||
sign_hybrid(&sk);
|
||||
let min_address6 = unsafe { find_border(start, 0x20020000) };
|
||||
|
||||
let mut param = [0; 0x1000];
|
||||
unsafe { paint_memory(start, 0x20020000) };
|
||||
param_test(&mut param);
|
||||
let min_address7 = unsafe { find_border(start, 0x20020000) };
|
||||
|
||||
unsafe { paint_memory(start, 0x20020000) };
|
||||
dummy_test();
|
||||
let min_address8 = unsafe { find_border(start, 0x20020000) };
|
||||
|
||||
let main_end = read_stack_pointer();
|
||||
write_result(&mut console, " keygen_ecdsa", main_end - min_address1);
|
||||
write_result(&mut console, "keygen_dilithium", main_end - min_address2);
|
||||
write_result(&mut console, " keygen_hybrid", main_end - min_address3);
|
||||
write_result(&mut console, " sign_ecdsa", main_end - min_address4);
|
||||
write_result(&mut console, " sign_dilithium", main_end - min_address5);
|
||||
write_result(&mut console, " sign_hybrid", main_end - min_address6);
|
||||
write_result(&mut console, " test dummy", main_end - min_address7);
|
||||
write_result(&mut console, " test input", main_end - min_address8);
|
||||
}
|
||||
@@ -132,49 +132,49 @@ mod example {
|
||||
match buf[0] {
|
||||
0xe0 /* RATS */=> {
|
||||
let mut answer_to_select = [0x05, 0x78, 0x80, 0xB1, 0x00];
|
||||
return_code = bench_transmit(&mut console, &timer, "TX: ATS", &mut answer_to_select);
|
||||
return_code = bench_transmit(&mut console, timer, "TX: ATS", &mut answer_to_select);
|
||||
}
|
||||
0xc2 /* DESELECT */ => {
|
||||
// Ignore the request
|
||||
let mut command_error = [0x6A, 0x81];
|
||||
return_code = bench_transmit(&mut console, &timer, "TX: DESELECT", &mut command_error);
|
||||
return_code = bench_transmit(&mut console, timer, "TX: DESELECT", &mut command_error);
|
||||
}
|
||||
0x02 | 0x03 /* APDU Prefix */ => match buf[2] {
|
||||
// If the received packet is applet selection command (FIDO 2)
|
||||
0xa4 /* SELECT */ => if buf[3] == 0x04 && buf[5] == 0x08 && buf[6] == 0xa0 {
|
||||
// Vesion: "FIDO_2_0"
|
||||
let mut reply = [buf[0], 0x46, 0x49, 0x44, 0x4f, 0x5f, 0x32, 0x5f, 0x30, 0x90, 0x00,];
|
||||
return_code = bench_transmit(&mut console, &timer, "TX: Version Str", &mut reply);
|
||||
return_code = bench_transmit(&mut console, timer, "TX: Version Str", &mut reply);
|
||||
} else if (buf[6] == 0xd2 && buf[7] == 0x76) || (buf[6] == 0xe1 && (buf[7] == 0x03 || buf[7] == 0x04)){
|
||||
let mut reply = [buf[0], 0x90, 0x00];
|
||||
return_code = bench_transmit(&mut console, &timer, "TX: 0x9000", &mut reply);
|
||||
return_code = bench_transmit(&mut console, timer, "TX: 0x9000", &mut reply);
|
||||
} else /* Unknown file */ {
|
||||
let mut reply = [buf[0], 0x6a, 0x82];
|
||||
return_code = bench_transmit(&mut console, &timer, "TX: 0x6A82", &mut reply);
|
||||
return_code = bench_transmit(&mut console, timer, "TX: 0x6A82", &mut reply);
|
||||
}
|
||||
0xb0 /* READ */ => match buf[5] {
|
||||
0x02 => {
|
||||
let mut reply = [buf[0], 0x12, 0x90, 0x00,];
|
||||
return_code = bench_transmit(&mut console, &timer, "TX: File Size", &mut reply);
|
||||
return_code = bench_transmit(&mut console, timer, "TX: File Size", &mut reply);
|
||||
}
|
||||
0x12 => {
|
||||
let mut reply = [buf[0], 0xd1, 0x01, 0x0e, 0x55, 0x77, 0x77, 0x77, 0x2e, 0x6f, 0x70, 0x65,
|
||||
0x6e, 0x73, 0x6b, 0x2e, 0x64, 0x65, 0x76, 0x90, 0x00,];
|
||||
return_code = bench_transmit(&mut console, &timer, "TX: NDEF", &mut reply);
|
||||
return_code = bench_transmit(&mut console, timer, "TX: NDEF", &mut reply);
|
||||
}
|
||||
0x0f => {
|
||||
let mut reply = [buf[0], 0x00, 0x0f, 0x20, 0x00, 0x7f, 0x00, 0x7f, 0x04, 0x06, 0xe1, 0x04,
|
||||
0x00, 0x7f, 0x00, 0x00, 0x90, 0x00,];
|
||||
return_code = bench_transmit(&mut console, &timer, "TX: CC", &mut reply);
|
||||
return_code = bench_transmit(&mut console, timer, "TX: CC", &mut reply);
|
||||
}
|
||||
_ => {
|
||||
let mut reply = [buf[0], 0x90, 0x00];
|
||||
return_code = bench_transmit(&mut console, &timer, "TX: 0x9000", &mut reply);
|
||||
return_code = bench_transmit(&mut console, timer, "TX: 0x9000", &mut reply);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let mut reply = [buf[0], 0x90, 0x00];
|
||||
return_code = bench_transmit(&mut console, &timer, "TX: 0x9000", &mut reply);
|
||||
return_code = bench_transmit(&mut console, timer, "TX: 0x9000", &mut reply);
|
||||
}
|
||||
}
|
||||
0x26 | 0x52 | 0x50 /* REQA | WUPA | Halt */ => {
|
||||
|
||||
Reference in New Issue
Block a user