mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-14 08:03:34 +00:00
a bunch of lines are shorter or different length now which triggers a mandatory reformat. this patch cleans that up, so that going forward the manual rework patches are clearer and not tied up with formatting patches.
616 lines
27 KiB
Rust
616 lines
27 KiB
Rust
use core::sync::atomic::{AtomicU32, Ordering};
|
|
|
|
#[cfg(feature = "engine-ll")]
|
|
use engine_25519::*;
|
|
use num_traits::*;
|
|
use String;
|
|
|
|
use crate::{CommonEnv, ShellCmdApi};
|
|
static CB_ID: AtomicU32 = AtomicU32::new(0);
|
|
|
|
// these vectors come from running `cargo test field::test::make_vectors` inside
|
|
// https://github.com/betrusted-io/curve25519-dalek. The output file is originally called `test_vectors.bin`.
|
|
// a portion of this vector set involves random numbers in addition to deterministic corner cases,
|
|
// therefore, every invocation will create a slightly different set of vectors
|
|
#[export_name = "engine_vectors"]
|
|
pub static ENGINE_VECTORS: &[u8; 15652] = include_bytes!("engine25519_vectors.bin");
|
|
|
|
#[derive(num_derive::FromPrimitive, num_derive::ToPrimitive, Debug)]
|
|
pub(crate) enum BenchOp {
|
|
StartEngine,
|
|
StartDh,
|
|
Quit,
|
|
}
|
|
|
|
#[derive(num_derive::FromPrimitive, num_derive::ToPrimitive, Debug)]
|
|
pub(crate) enum BenchResult {
|
|
EngineDone,
|
|
DhDone,
|
|
}
|
|
|
|
const TEST_ITERS: usize = 10;
|
|
const TEST_ITERS_DH: usize = 200;
|
|
|
|
fn vector_read(word_offset: usize) -> u32 {
|
|
let mut bytes: [u8; 4] = [0; 4];
|
|
for i in 0..4 {
|
|
bytes[i] = ENGINE_VECTORS[word_offset * 4 + i];
|
|
}
|
|
u32::from_le_bytes(bytes)
|
|
}
|
|
|
|
fn run_vectors() -> (usize, usize) {
|
|
use curve25519_dalek::backend::serial::u32e::*;
|
|
while ensure_engine().is_err() {
|
|
xous::yield_slice();
|
|
}
|
|
// safety: it's safe because it's after ensure_engine()
|
|
let ucode_hw = unsafe { get_ucode() };
|
|
let rf_hw = unsafe { get_rf() };
|
|
|
|
let mut test_offset: usize = 0x0;
|
|
let mut passes: usize = 0;
|
|
let mut fails: usize = 0;
|
|
loop {
|
|
let magic_number = vector_read(test_offset);
|
|
if magic_number != 0x5645_4354 {
|
|
break;
|
|
}
|
|
log::debug!("test suite at 0x{:x}", test_offset);
|
|
test_offset += 1;
|
|
|
|
let load_addr = (vector_read(test_offset) >> 16) & 0xFFFF;
|
|
let code_len = vector_read(test_offset) & 0xFFFF;
|
|
test_offset += 1;
|
|
let num_args = (vector_read(test_offset) >> 27) & 0x1F;
|
|
let window = (vector_read(test_offset) >> 23) & 0xF;
|
|
let num_vectors = (vector_read(test_offset) >> 0) & 0x3F_FFFF;
|
|
test_offset += 1;
|
|
|
|
let mut mcode = Vec::<i32>::new();
|
|
for _i in load_addr as usize..(load_addr + code_len) as usize {
|
|
mcode.push(vector_read(test_offset) as i32);
|
|
test_offset += 1;
|
|
}
|
|
|
|
test_offset = test_offset + (8 - (test_offset % 8)); // skip over padding
|
|
|
|
// copy in the arguments
|
|
for vector in 0..num_vectors {
|
|
// a test suite can have numerous vectors against a common code base
|
|
for argcnt in 0..num_args {
|
|
for word in 0..8 {
|
|
rf_hw[(window * 32 * 8 + argcnt * 8 + word) as usize] = vector_read(test_offset);
|
|
test_offset += 1;
|
|
}
|
|
}
|
|
|
|
let mut passed = true;
|
|
log::trace!("spawning job");
|
|
run_job(ucode_hw, rf_hw, &mcode, window as usize);
|
|
for word in 0..8 {
|
|
let expect = vector_read(test_offset);
|
|
test_offset += 1;
|
|
let actual = rf_hw[(window * 32 * 8 + 31 * 8 + word) as usize];
|
|
if expect != actual {
|
|
log::error!("e/a {:08x}/{:08x}", expect, actual);
|
|
passed = false;
|
|
}
|
|
}
|
|
|
|
if passed {
|
|
passes += 1;
|
|
} else {
|
|
log::error!(
|
|
"arithmetic or system error in running test vector: {}/0x{:x}",
|
|
vector,
|
|
test_offset
|
|
);
|
|
fails += 1;
|
|
}
|
|
}
|
|
}
|
|
curve25519_dalek::backend::serial::u32e::free_engine();
|
|
(passes, fails)
|
|
}
|
|
/*
|
|
benchmark notes:
|
|
|
|
+59mA +/-1mA current draw off fully charged battery when running the benchmark
|
|
1246-1261ms/check vector iteration (10 iters total, 1450 vectors total)
|
|
|
|
With new curve25519 api:
|
|
53.6ms/check vector iteration (10 iters total, 1450 vectors total) with engine retained
|
|
56.5ms/check with auto-free
|
|
*/
|
|
pub fn benchmark_thread(sid0: usize, sid1: usize, sid2: usize, sid3: usize) {
|
|
let sid = xous::SID::from_u32(sid0 as u32, sid1 as u32, sid2 as u32, sid3 as u32);
|
|
let xns = xous_names::XousNames::new().unwrap();
|
|
let callback_conn = xns.request_connection_blocking(crate::SERVER_NAME_SHELLCHAT).unwrap();
|
|
|
|
let mut trng = trng::Trng::new(&xns).unwrap();
|
|
|
|
loop {
|
|
let msg = xous::receive_message(sid).unwrap();
|
|
log::debug!("benchmark got msg {:?}", msg);
|
|
match FromPrimitive::from_usize(msg.body.id()) {
|
|
Some(BenchOp::StartEngine) => {
|
|
let mut passes = 0;
|
|
let mut fails = 0;
|
|
for _ in 0..TEST_ITERS {
|
|
let (p, f) = run_vectors();
|
|
passes += p;
|
|
fails += f;
|
|
}
|
|
|
|
xous::send_message(
|
|
callback_conn,
|
|
xous::Message::new_scalar(
|
|
CB_ID.load(Ordering::Relaxed) as usize,
|
|
passes as usize,
|
|
fails as usize,
|
|
BenchResult::EngineDone.to_usize().unwrap(),
|
|
TEST_ITERS as usize,
|
|
),
|
|
)
|
|
.unwrap();
|
|
}
|
|
/*
|
|
2xop => each iteration has 2x DH ops in it (one for alice, one for bob)
|
|
202ms/2xop (10 x 10 iters - sw)
|
|
40.5ms/2xop (10 x 10 iters - hw)
|
|
33ms/2xop (200 iters - hw) - affine done in software
|
|
190ms/2xop (200 iters - sw)
|
|
26ms/2xop (200 iters -hw) -- affine done in hardware
|
|
|
|
13.54ms/2xop (200 iters -hw) -- microcode pre-loaded, minimal registers transferred using MontgomeryJob call
|
|
12.2ms/2xop (200 iters -hw) -- with L2 cache on (128k)
|
|
12.29ms/2xop (200 iters -hw) -- with L2 cache on (64k)
|
|
|
|
8.37ms/2xop (200 iters - hw) - with new curve25519 lib and engine retained after every loop
|
|
33.04ms/2xop (200 iters - hw) - with new curve25519 lib and auto-free engine after every loop
|
|
*/
|
|
Some(BenchOp::StartDh) => {
|
|
let mut passes = 0;
|
|
let mut fails = 0;
|
|
|
|
use x25519_dalek::{PublicKey, StaticSecret};
|
|
let alice_secret = StaticSecret::random_from_rng(&mut trng);
|
|
let alice_public = PublicKey::from(&alice_secret);
|
|
let bob_secret = StaticSecret::random_from_rng(&mut trng);
|
|
let bob_public = PublicKey::from(&bob_secret);
|
|
for _ in 0..TEST_ITERS_DH {
|
|
let alice_shared_secret = alice_secret.diffie_hellman(&bob_public);
|
|
let bob_shared_secret = bob_secret.diffie_hellman(&alice_public);
|
|
let mut pass = true;
|
|
for (&alice, &bob) in
|
|
alice_shared_secret.as_bytes().iter().zip(bob_shared_secret.as_bytes().iter())
|
|
{
|
|
if alice != bob {
|
|
pass = false;
|
|
}
|
|
}
|
|
if pass {
|
|
passes += 2; // 2 diffie_hellman ops / iter
|
|
} else {
|
|
fails += 2;
|
|
}
|
|
}
|
|
xous::send_message(
|
|
callback_conn,
|
|
xous::Message::new_scalar(
|
|
CB_ID.load(Ordering::Relaxed) as usize,
|
|
passes as usize,
|
|
fails as usize,
|
|
BenchResult::DhDone.to_usize().unwrap(),
|
|
TEST_ITERS_DH as usize,
|
|
),
|
|
)
|
|
.unwrap();
|
|
}
|
|
Some(BenchOp::Quit) => {
|
|
log::info!("quitting benchmark thread");
|
|
break;
|
|
}
|
|
None => {
|
|
log::error!("received unknown opcode");
|
|
}
|
|
}
|
|
}
|
|
xous::destroy_server(sid).unwrap();
|
|
}
|
|
|
|
mod wycheproof {
|
|
pub const WYCHEPROOF_NO_TEST_CASES: usize = 518;
|
|
pub const WHYCHEPROOF_TEST_CASE_SIZE: usize = 96;
|
|
|
|
#[export_name = "wycheproof_vectors"]
|
|
pub static WYCHEPROOF_VECTORS: &[u8; WYCHEPROOF_NO_TEST_CASES * WHYCHEPROOF_TEST_CASE_SIZE] =
|
|
include_bytes!("x25519_test.bin");
|
|
|
|
pub struct WycheproofTestCase {
|
|
// inferred from the index; not read from the binary data
|
|
public: [u8; 32],
|
|
id: usize,
|
|
private: [u8; 32],
|
|
shared: [u8; 32],
|
|
}
|
|
|
|
impl WycheproofTestCase {
|
|
pub fn read(test_index: usize) -> Self {
|
|
use std::io::Read;
|
|
let test_offset = test_index * WHYCHEPROOF_TEST_CASE_SIZE;
|
|
let mut public = [0u8; 32];
|
|
(&WYCHEPROOF_VECTORS[test_offset..test_offset + 32]).read_exact(&mut public).unwrap();
|
|
let mut private = [0u8; 32];
|
|
(&WYCHEPROOF_VECTORS[test_offset + 32..test_offset + 64]).read_exact(&mut private).unwrap();
|
|
let mut shared = [0u8; 32];
|
|
(&WYCHEPROOF_VECTORS[test_offset + 64..test_offset + 96]).read_exact(&mut shared).unwrap();
|
|
|
|
WycheproofTestCase { id: test_index + 1, public, private, shared }
|
|
}
|
|
|
|
pub fn run(&self) -> Option<TestCaseError> {
|
|
use x25519_dalek::{PublicKey, StaticSecret};
|
|
let private = StaticSecret::from(self.private);
|
|
let public = PublicKey::from(self.public);
|
|
let shared = private.diffie_hellman(&public).to_bytes();
|
|
if shared != self.shared {
|
|
Some(TestCaseError { test_id: self.id, expected: self.shared, actual: shared })
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct TestCaseError {
|
|
pub(crate) test_id: usize,
|
|
pub(crate) expected: [u8; 32],
|
|
pub(crate) actual: [u8; 32],
|
|
}
|
|
}
|
|
#[derive(Debug)]
|
|
pub struct Engine {
|
|
susres: susres::Susres,
|
|
benchmark_cid: xous::CID,
|
|
start_time: Option<u64>,
|
|
}
|
|
|
|
impl Engine {
|
|
pub fn new(xns: &xous_names::XousNames, env: &mut CommonEnv) -> Self {
|
|
let sid = xous::create_server().unwrap();
|
|
let sid_tuple = sid.to_u32();
|
|
|
|
let cb_id = env.register_handler(String::from("engine"));
|
|
CB_ID.store(cb_id, Ordering::Relaxed);
|
|
|
|
xous::create_thread_4(
|
|
benchmark_thread,
|
|
sid_tuple.0 as usize,
|
|
sid_tuple.1 as usize,
|
|
sid_tuple.2 as usize,
|
|
sid_tuple.3 as usize,
|
|
)
|
|
.unwrap();
|
|
Engine {
|
|
susres: susres::Susres::new_without_hook(&xns).unwrap(),
|
|
// this is a dummy and hangs if engine-ll is not an active feature
|
|
benchmark_cid: xous::connect(sid).unwrap(),
|
|
start_time: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> ShellCmdApi<'a> for Engine {
|
|
cmd_api!(engine);
|
|
|
|
// inserts boilerplate for command API
|
|
|
|
fn process(&mut self, args: String, env: &mut CommonEnv) -> Result<Option<String>, xous::Error> {
|
|
use core::fmt::Write;
|
|
let mut ret = String::new();
|
|
#[cfg(feature = "engine-ll")]
|
|
let helpstring = "engine [check] [bench] [benchdh] [susres] [dh] [ed] [wycheproof]";
|
|
#[cfg(not(feature = "engine-ll"))]
|
|
let helpstring = "engine [susres] [dh] [ed] [wycheproof]";
|
|
|
|
let mut tokens = &args.split(' ');
|
|
|
|
if let Some(sub_cmd) = tokens.next() {
|
|
match sub_cmd {
|
|
"check" => {
|
|
log::debug!("running vectors");
|
|
let (passes, fails) = run_vectors();
|
|
|
|
write!(ret, "Engine passed {} vectors, failed {} vectors", passes, fails).unwrap();
|
|
}
|
|
"bench" => {
|
|
let start = env.ticktimer.elapsed_ms();
|
|
self.start_time = Some(start);
|
|
xous::send_message(
|
|
self.benchmark_cid,
|
|
xous::Message::new_scalar(BenchOp::StartEngine.to_usize().unwrap(), 0, 0, 0, 0),
|
|
)
|
|
.unwrap();
|
|
write!(ret, "Starting Engine hardware benchmark with {} iters", TEST_ITERS).unwrap();
|
|
}
|
|
"benchdh" => {
|
|
let start = env.ticktimer.elapsed_ms();
|
|
self.start_time = Some(start);
|
|
xous::send_message(
|
|
self.benchmark_cid,
|
|
xous::Message::new_scalar(BenchOp::StartDh.to_usize().unwrap(), 0, 0, 0, 0),
|
|
)
|
|
.unwrap();
|
|
write!(ret, "Starting DH hardware benchmark").unwrap();
|
|
}
|
|
"susres" => {
|
|
let start = env.ticktimer.elapsed_ms();
|
|
self.start_time = Some(start);
|
|
xous::send_message(
|
|
self.benchmark_cid,
|
|
xous::Message::new_scalar(BenchOp::StartEngine.to_usize().unwrap(), 0, 0, 0, 0),
|
|
)
|
|
.unwrap();
|
|
let wait_time = (env.trng.get_u32().unwrap() % 2000) + 500; // at least half a second wait, up to 2 seconds
|
|
env.ticktimer.sleep_ms(wait_time as _).unwrap();
|
|
self.susres.initiate_suspend().unwrap();
|
|
write!(ret, "Interrupted Engine hardware benchmark with a suspend/resume").unwrap();
|
|
}
|
|
"dh" => {
|
|
log::info!("starting DH test");
|
|
use x25519_dalek::{EphemeralSecret, PublicKey};
|
|
let alice_secret = EphemeralSecret::random_from_rng(&mut env.trng);
|
|
log::info!("1");
|
|
let alice_public = PublicKey::from(&alice_secret);
|
|
let bob_secret = EphemeralSecret::random_from_rng(&mut env.trng);
|
|
let bob_public = PublicKey::from(&bob_secret);
|
|
log::info!("2");
|
|
let alice_shared_secret = alice_secret.diffie_hellman(&bob_public);
|
|
log::info!("3");
|
|
let bob_shared_secret = bob_secret.diffie_hellman(&alice_public);
|
|
log::info!("4");
|
|
let mut pass = true;
|
|
for (&alice, &bob) in
|
|
alice_shared_secret.as_bytes().iter().zip(bob_shared_secret.as_bytes().iter())
|
|
{
|
|
if alice != bob {
|
|
pass = false;
|
|
}
|
|
}
|
|
log::info!("alice: {:02x?}", alice_shared_secret.as_bytes());
|
|
log::info!("bob: {:02x?}", bob_shared_secret.as_bytes());
|
|
if pass {
|
|
write!(ret, "x25519 key exchange pass").unwrap();
|
|
} else {
|
|
write!(ret, "x25519 key exchange fail").unwrap();
|
|
}
|
|
|
|
/////////////////////// fixed vectors from x25519-dalek tests
|
|
use curve25519_dalek::montgomery::MontgomeryPoint;
|
|
/// The bare, byte-oriented x25519 function, exactly as specified in RFC7748.
|
|
///
|
|
/// This can be used with [`X25519_BASEPOINT_BYTES`] for people who
|
|
/// cannot use the better, safer, and faster DH API.
|
|
fn x25519(k: [u8; 32], u: [u8; 32]) -> [u8; 32] {
|
|
MontgomeryPoint(u).mul_clamped(k).to_bytes()
|
|
}
|
|
{
|
|
let input_scalar: [u8; 32] = [
|
|
0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, 0x3b, 0x16, 0x15, 0x4b, 0x82,
|
|
0x46, 0x5e, 0xdd, 0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc, 0x5a, 0x18, 0x50, 0x6a,
|
|
0x22, 0x44, 0xba, 0x44, 0x9a, 0xc4,
|
|
];
|
|
let input_point: [u8; 32] = [
|
|
0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb, 0x35, 0x94, 0xc1, 0xa4, 0x24,
|
|
0xb1, 0x5f, 0x7c, 0x72, 0x66, 0x24, 0xec, 0x26, 0xb3, 0x35, 0x3b, 0x10, 0xa9,
|
|
0x03, 0xa6, 0xd0, 0xab, 0x1c, 0x4c,
|
|
];
|
|
let expected: [u8; 32] = [
|
|
0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90, 0x8e, 0x94, 0xea, 0x4d, 0xf2,
|
|
0x8d, 0x08, 0x4f, 0x32, 0xec, 0xcf, 0x03, 0x49, 0x1c, 0x71, 0xf7, 0x54, 0xb4,
|
|
0x07, 0x55, 0x77, 0xa2, 0x85, 0x52,
|
|
];
|
|
let result = x25519(input_scalar, input_point);
|
|
if result != expected {
|
|
write!(ret, "x25519 vector 1 failed!\n").unwrap();
|
|
log::error!("result: {:x?}", result);
|
|
log::error!("expected: {:x?}", expected);
|
|
} else {
|
|
write!(ret, "x25519 vector 1 passed\n").unwrap();
|
|
}
|
|
}
|
|
{
|
|
let input_scalar: [u8; 32] = [
|
|
0x4b, 0x66, 0xe9, 0xd4, 0xd1, 0xb4, 0x67, 0x3c, 0x5a, 0xd2, 0x26, 0x91, 0x95,
|
|
0x7d, 0x6a, 0xf5, 0xc1, 0x1b, 0x64, 0x21, 0xe0, 0xea, 0x01, 0xd4, 0x2c, 0xa4,
|
|
0x16, 0x9e, 0x79, 0x18, 0xba, 0x0d,
|
|
];
|
|
let input_point: [u8; 32] = [
|
|
0xe5, 0x21, 0x0f, 0x12, 0x78, 0x68, 0x11, 0xd3, 0xf4, 0xb7, 0x95, 0x9d, 0x05,
|
|
0x38, 0xae, 0x2c, 0x31, 0xdb, 0xe7, 0x10, 0x6f, 0xc0, 0x3c, 0x3e, 0xfc, 0x4c,
|
|
0xd5, 0x49, 0xc7, 0x15, 0xa4, 0x93,
|
|
];
|
|
let expected: [u8; 32] = [
|
|
0x95, 0xcb, 0xde, 0x94, 0x76, 0xe8, 0x90, 0x7d, 0x7a, 0xad, 0xe4, 0x5c, 0xb4,
|
|
0xb8, 0x73, 0xf8, 0x8b, 0x59, 0x5a, 0x68, 0x79, 0x9f, 0xa1, 0x52, 0xe6, 0xf8,
|
|
0xf7, 0x64, 0x7a, 0xac, 0x79, 0x57,
|
|
];
|
|
let result = x25519(input_scalar, input_point);
|
|
if result != expected {
|
|
write!(ret, "x25519 vector 2 failed!\n").unwrap();
|
|
log::error!("result: {:x?}", result);
|
|
log::error!("expected: {:x?}", expected);
|
|
} else {
|
|
write!(ret, "x25519 vector 2 passed\n").unwrap();
|
|
}
|
|
}
|
|
}
|
|
"ed2" => {
|
|
use ed25519_dalek::{Signer, SigningKey};
|
|
let good: &[u8] = "test message".as_bytes();
|
|
let bad: &[u8] = "wrong message".as_bytes();
|
|
|
|
let signingkey = SigningKey::generate(&mut env.trng);
|
|
let good_sig = signingkey.sign(&good);
|
|
let bad_sig = signingkey.sign(&bad);
|
|
|
|
if signingkey.verify(&good, &good_sig).is_ok() {
|
|
write!(ret, "Verification of valid signtaure passed!\n").unwrap();
|
|
} else {
|
|
write!(ret, "Verification of valid signtaure failed!\n").unwrap();
|
|
}
|
|
if signingkey.verify(&good, &bad_sig).is_err() {
|
|
write!(
|
|
ret,
|
|
"Verification of a signature on a different message failed, as expected.\n"
|
|
)
|
|
.unwrap();
|
|
} else {
|
|
write!(ret, "Verification of a signature on a different message passed (this is unexpected)!\n").unwrap();
|
|
}
|
|
if signingkey.verify(&bad, &good_sig).is_err() {
|
|
write!(
|
|
ret,
|
|
"Verification of a signature on a different message failed, as expected.\n"
|
|
)
|
|
.unwrap();
|
|
} else {
|
|
write!(ret, "Verification of a signature on a different message passed (this is unexpected)!\n").unwrap();
|
|
}
|
|
}
|
|
"ed" => {
|
|
use ed25519_dalek::*;
|
|
// use ed25519::signature::Signature as _;
|
|
use hex::FromHex;
|
|
let signing_key: &[u8] =
|
|
b"833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42";
|
|
let public_key: &[u8] =
|
|
b"ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf";
|
|
let message: &[u8] = b"616263";
|
|
let signature: &[u8] = b"98a70222f0b8121aa9d30f813d683f809e462b469c7ff87639499bb94e6dae4131f85042463c2a355a2003d062adf5aaa10b8c61e636062aaad11c2a26083406";
|
|
let msg_bytes = <[u8; 3]>::from_hex(message).unwrap();
|
|
|
|
let signing_key_bytes = <[u8; SECRET_KEY_LENGTH]>::from_hex(signing_key).unwrap();
|
|
let public_key_bytes = <[u8; PUBLIC_KEY_LENGTH]>::from_hex(public_key).unwrap();
|
|
let signature_bytes = <[u8; SIGNATURE_LENGTH]>::from_hex(signature).unwrap();
|
|
|
|
let signingkey: SigningKey = SigningKey::from_bytes(&signing_key_bytes);
|
|
let expected_verifying_key = VerifyingKey::from_bytes(&public_key_bytes).unwrap();
|
|
assert_eq!(expected_verifying_key, signingkey.verifying_key());
|
|
let sig1: Signature = Signature::from_bytes(&signature_bytes);
|
|
|
|
//let mut prehash_for_signing = engine_sha512::Sha512::default(); // this defaults to Hw
|
|
// then Sw strategy let mut prehash_for_verifying =
|
|
// engine_sha512::Sha512::default();
|
|
let mut prehash_for_signing = sha2::Sha512::default(); // this defaults to Hw then Sw strategy
|
|
let mut prehash_for_verifying = sha2::Sha512::default();
|
|
|
|
prehash_for_signing.update(&msg_bytes[..]);
|
|
prehash_for_verifying.update(&msg_bytes[..]);
|
|
|
|
let sig2: Signature = signingkey.sign_prehashed(prehash_for_signing, None).unwrap();
|
|
|
|
log::info!("original: {:02x?}", sig1);
|
|
log::info!("produced: {:02x?}", sig2);
|
|
let mut pass = true;
|
|
if sig1 != sig2 {
|
|
pass = false;
|
|
write!(
|
|
ret,
|
|
"Original signature from test vectors doesn't equal signature produced:\
|
|
\noriginal:\n{:?}\nproduced:\n{:?}",
|
|
sig1, sig2
|
|
)
|
|
.unwrap();
|
|
}
|
|
if signingkey.verify_prehashed(prehash_for_verifying, None, &sig2).is_err() {
|
|
pass = false;
|
|
write!(ret, "Could not verify ed25519ph signature!").unwrap();
|
|
}
|
|
if pass {
|
|
write!(ret, "Passed ed25519 simple check").unwrap();
|
|
}
|
|
}
|
|
"wycheproof" => {
|
|
use hex::ToHex;
|
|
use wycheproof::*;
|
|
let failures: Vec<TestCaseError> = (0..WYCHEPROOF_NO_TEST_CASES)
|
|
.filter_map(|test_index| WycheproofTestCase::read(test_index).run())
|
|
.collect();
|
|
write!(ret, "Ran {} tests. {} failures.", WYCHEPROOF_NO_TEST_CASES, failures.len())
|
|
.unwrap();
|
|
let num_failures = failures.len();
|
|
if failures.len() > 0 {
|
|
write!(
|
|
ret,
|
|
"\nFailed tests: {:?}",
|
|
failures.iter().map(|tc| tc.test_id).collect::<Vec<usize>>()
|
|
)
|
|
.unwrap();
|
|
for failure in failures {
|
|
log::error!("wycheproof test #{} failed:", failure.test_id);
|
|
log::error!("expected: {}", failure.expected.encode_hex::<std::string::String>());
|
|
log::error!("actual: {}", failure.actual.encode_hex::<std::string::String>());
|
|
}
|
|
log::info!(
|
|
"{}BENCH,WYCHEPROOF,FAIL,{},{}",
|
|
xous::BOOKEND_START,
|
|
num_failures,
|
|
xous::BOOKEND_END
|
|
);
|
|
} else {
|
|
log::info!("{}BENCH,WYCHEPROOF,PASS,{}", xous::BOOKEND_START, xous::BOOKEND_END);
|
|
}
|
|
}
|
|
_ => {
|
|
write!(ret, "{}", helpstring).unwrap();
|
|
}
|
|
}
|
|
} else {
|
|
write!(ret, "{}", helpstring).unwrap();
|
|
}
|
|
// de-allocate the engine at the end of the test, so other processes can grab it
|
|
curve25519_dalek::backend::serial::u32e::free_engine();
|
|
Ok(Some(ret))
|
|
}
|
|
|
|
fn callback(
|
|
&mut self,
|
|
msg: &xous::MessageEnvelope,
|
|
env: &mut CommonEnv,
|
|
) -> Result<Option<String>, xous::Error> {
|
|
use core::fmt::Write;
|
|
|
|
log::debug!("benchmark callback");
|
|
let mut ret = String::new();
|
|
|
|
xous::msg_scalar_unpack!(msg, passes, fails, result_type, iters, {
|
|
let end = env.ticktimer.elapsed_ms();
|
|
let elapsed: f32 = ((end - self.start_time.unwrap()) as f32) / iters as f32;
|
|
match FromPrimitive::from_usize(result_type) {
|
|
Some(BenchResult::EngineDone) => {
|
|
write!(
|
|
ret,
|
|
"{}ms/check_iter; In total, Engine passed {} vectors, failed {} vectors",
|
|
elapsed, passes, fails
|
|
)
|
|
.unwrap();
|
|
}
|
|
Some(BenchResult::DhDone) => {
|
|
write!(ret, "{}ms/DH_iter; Passed {} ops, failed {} ops", elapsed, passes, fails)
|
|
.unwrap();
|
|
if fails == 0 {
|
|
log::info!("{}BENCH,DH,PASS,{}", xous::BOOKEND_START, xous::BOOKEND_END);
|
|
} else {
|
|
log::info!("{}BENCH,DH,FAIL,{}", xous::BOOKEND_START, xous::BOOKEND_END);
|
|
}
|
|
}
|
|
_ => {
|
|
write!(ret, "Engine bench callback with unknown bench type").unwrap();
|
|
}
|
|
}
|
|
});
|
|
Ok(Some(ret))
|
|
}
|
|
}
|