diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 5f2622b..fdf72ba 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -27,7 +27,7 @@ jobs: - name: run `cargo doc` run: RUSTDOCFLAGS="-D warnings" cargo doc - name: run `cargo test` - run: cargo test --all + run: cargo test generate-fstar: runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index ea8c4bf..96ef6c0 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +Cargo.lock diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index cb24b94..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,457 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "autocfg" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bumpalo" -version = "3.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" - -[[package]] -name = "cfg-if" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" - -[[package]] -name = "cpufeatures" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - -[[package]] -name = "crypto-common" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", -] - -[[package]] -name = "embedded-cal" -version = "0.1.0" -dependencies = [ - "hax-lib", -] - -[[package]] -name = "embedded-cal-rustcrypto" -version = "0.1.0" -dependencies = [ - "digest", - "embedded-cal", - "sha2", - "testvectors", -] - -[[package]] -name = "embedded-cal-software" -version = "0.1.0" -dependencies = [ - "embedded-cal", - "testvectors", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" -dependencies = [ - "cfg-if", - "libc", - "r-efi", - "wasi", -] - -[[package]] -name = "hax-lib" -version = "0.3.5" -source = "git+https://github.com/hacspec/hax#bf9a7e4b6a24aebf015910d62477103d010fd643" -dependencies = [ - "hax-lib-macros", - "num-bigint", - "num-traits", -] - -[[package]] -name = "hax-lib-macros" -version = "0.3.5" -source = "git+https://github.com/hacspec/hax#bf9a7e4b6a24aebf015910d62477103d010fd643" -dependencies = [ - "hax-lib-macros-types", - "proc-macro-error2", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "hax-lib-macros-types" -version = "0.3.5" -source = "git+https://github.com/hacspec/hax#bf9a7e4b6a24aebf015910d62477103d010fd643" -dependencies = [ - "proc-macro2", - "quote", - "serde", - "serde_json", - "uuid", -] - -[[package]] -name = "hexlit" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b6e75c860d4216ac53f9ac88b25c99eaedba075b3a7b2ed31f2adc51a74fffd" - -[[package]] -name = "itoa" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" - -[[package]] -name = "js-sys" -version = "0.3.81" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" -dependencies = [ - "once_cell", - "wasm-bindgen", -] - -[[package]] -name = "libc" -version = "0.2.176" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" - -[[package]] -name = "log" -version = "0.4.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" - -[[package]] -name = "memchr" -version = "2.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" - -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "once_cell" -version = "1.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - -[[package]] -name = "proc-macro-error-attr2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" -dependencies = [ - "proc-macro2", - "quote", -] - -[[package]] -name = "proc-macro-error2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" -dependencies = [ - "proc-macro-error-attr2", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "proc-macro2" -version = "1.0.101" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "r-efi" -version = "5.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" - -[[package]] -name = "rustversion" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" - -[[package]] -name = "ryu" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" - -[[package]] -name = "serde" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -dependencies = [ - "serde_core", - "serde_derive", -] - -[[package]] -name = "serde_core" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.145" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", - "serde_core", -] - -[[package]] -name = "sha2" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "syn" -version = "2.0.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "testvectors" -version = "0.1.0" -dependencies = [ - "embedded-cal", - "hexlit", -] - -[[package]] -name = "typenum" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" - -[[package]] -name = "unicode-ident" -version = "1.0.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" - -[[package]] -name = "uuid" -version = "1.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" -dependencies = [ - "getrandom", - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "wasi" -version = "0.14.7+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" -dependencies = [ - "wasip2", -] - -[[package]] -name = "wasip2" -version = "1.0.1+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" -dependencies = [ - "wit-bindgen", -] - -[[package]] -name = "wasm-bindgen" -version = "0.2.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "wit-bindgen" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" diff --git a/Cargo.toml b/Cargo.toml index 1c0d0a5..3a241e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,6 @@ [workspace] -members = ["embedded-cal", "embedded-cal-rustcrypto", "embedded-cal-software", "testvectors"] +members = ["embedded-cal", "embedded-cal-rustcrypto", "embedded-cal-software", "testvectors", "embedded-cal-nrf54l15"] +default-members = ["embedded-cal", "embedded-cal-rustcrypto", "embedded-cal-software", "testvectors"] resolver = "3" [workspace.package] diff --git a/embedded-cal-nrf54l15/.cargo/config.toml b/embedded-cal-nrf54l15/.cargo/config.toml new file mode 100644 index 0000000..8a75197 --- /dev/null +++ b/embedded-cal-nrf54l15/.cargo/config.toml @@ -0,0 +1,14 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +runner = ["probe-rs", "run", "--chip", "nRF54L15", "--log-format=oneline", "--allow-erase-all", "--verify"] + +rustflags = [ + "-C", "linker=flip-link", + "-C", "link-arg=-Tlink.x", + "-C", "link-arg=-Tdefmt.x", + # This is needed if your flash or ram addresses are not aligned to 0x10000 in memory.x + # See https://github.com/rust-embedded/cortex-m-quickstart/pull/95 + "-C", "link-arg=--nmagic", +] + +[build] +target = "thumbv8m.main-none-eabihf" \ No newline at end of file diff --git a/embedded-cal-nrf54l15/Cargo.toml b/embedded-cal-nrf54l15/Cargo.toml new file mode 100644 index 0000000..32a78fa --- /dev/null +++ b/embedded-cal-nrf54l15/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "embedded-cal-nrf54l15" +edition.workspace = true +license.workspace = true +readme.workspace = true +repository.workspace = true +keywords.workspace = true +categories.workspace = true +version.workspace = true + +[lib] +test = false +doc = false + +[[test]] +name = "integration" +harness = false + +[dependencies] +embedded-cal.path = "../embedded-cal" +testvectors.path = "../testvectors" +embedded-cal-software.path = "../embedded-cal-software" +nrf-pac = { version = "0.2.0", features = ["nrf54l15-app", "rt"] } + +[dev-dependencies] +cortex-m = { version = "0.7", features = ["critical-section-single-core"] } +cortex-m-rt = { version = "0.7", features = ["device"] } +defmt = "1.0" +defmt-rtt = "1.0" +panic-probe = { version = "1.0", features = ["print-defmt"] } +defmt-test = "0.4" diff --git a/embedded-cal-nrf54l15/build.rs b/embedded-cal-nrf54l15/build.rs new file mode 100644 index 0000000..3614d4f --- /dev/null +++ b/embedded-cal-nrf54l15/build.rs @@ -0,0 +1,11 @@ +use std::{env, fs, path::PathBuf}; + +fn main() { + let out = PathBuf::from(env::var("OUT_DIR").unwrap()); + + // copy memory.x into OUT_DIR, so we can have a different memory.x for each chip + fs::copy("memory.x", out.join("memory.x")).expect("could not copy memory.x"); + + println!("cargo:rustc-link-search={}", out.display()); + println!("cargo:rerun-if-changed=memory.x"); +} diff --git a/embedded-cal-nrf54l15/memory.x b/embedded-cal-nrf54l15/memory.x new file mode 100644 index 0000000..3322008 --- /dev/null +++ b/embedded-cal-nrf54l15/memory.x @@ -0,0 +1,5 @@ +MEMORY +{ + FLASH : ORIGIN = 0x00000000, LENGTH = 1524K + RAM : ORIGIN = 0x20000000, LENGTH = 256K +} diff --git a/embedded-cal-nrf54l15/src/descriptor.rs b/embedded-cal-nrf54l15/src/descriptor.rs new file mode 100644 index 0000000..d8f8c19 --- /dev/null +++ b/embedded-cal-nrf54l15/src/descriptor.rs @@ -0,0 +1,127 @@ +/// Pointer to memory address 1. +/// It means that the descriptor chain is over +#[allow( + clippy::manual_dangling_ptr, + reason = "nRF54L15 uses 1 as last-descriptor sentinel" +)] +const LAST_DESC_PTR: *mut Descriptor = 1 as *mut Descriptor; +/// Single EasyDMA scatter-gather job entry. +/// +/// This structure maps directly to one hardware “job entry” consumed by the +/// EasyDMA engine when scatter-gather mode is enabled. Each descriptor describes +/// one contiguous memory region to be read from or written to by DMA. +/// `next` must either point to the next `Descriptor` in the chain or be the +#[repr(C)] +#[derive(Debug, Clone, Copy)] +struct Descriptor { + /// Start address of the memory region for this DMA job. + /// + /// Must be DMA-accessible memory. + addr: *mut u8, + /// Pointer to the next descriptor in the scatter-gather job list. + /// + /// Should be LAST_DESC_PTR in case of the last descriptor of the chain. + next: *mut Descriptor, + // FIXME: Improve documentation, explain the magic number 0x2000_0000 + /// Length, in bytes, of the memory region described by `addr`. + sz: u32, + // FIXME: Improve documentation, enum all possible tags. + /// DMA attribute / tag field. + dmatag: u32, +} + +impl Descriptor { + fn empty() -> Self { + Self { + addr: core::ptr::null_mut(), + next: core::ptr::null_mut(), + sz: 0, + dmatag: 0, + } + } + + fn new(addr: *mut u8, sz: u32, dmatag: u32) -> Self { + Self { + addr, + next: core::ptr::null_mut(), + sz, + dmatag, + } + } +} + +/// Fixed-capacity scatter-gather descriptor chain. +/// +/// This type owns a small array of `Descriptor`s and tracks how many entries +/// are currently in use. +/// +/// DescriptorChain also make sure they are linked like a linked-list +/// and the last Descriptor.next is always LAST_DESC_PTR +pub(crate) struct DescriptorChain { + descs: [Descriptor; N], + count: usize, +} + +impl DescriptorChain { + /// Creates an empty `DescriptorChain`. + /// + /// The chain is initialized with all descriptors zero-filled and contains + /// no active entries. + pub(crate) fn new() -> Self { + Self { + descs: [Descriptor::empty(); N], + count: 0, + } + } + + /// Appends a descriptor to the end of the chain. + /// + /// This method: + /// - Stores `desc` in the next free slot. + /// - Updates the `next` pointer of the previous descriptor to point to the + /// newly added one. + /// - Ensures the newly added descriptor’s `next` pointer is set to + /// `LAST_DESC_PTR`, marking it as the terminal job entry. + /// + /// # Panics + /// + /// Panics if the chain is already at full capacity. + /// + /// # Safety / Correctness requirements + /// + /// - The descriptor and all previously pushed descriptors must remain + /// valid and unmodified while a DMA transfer is in progress. + /// - All descriptors in the chain must describe DMA-accessible memory. + /// - The chain must not be mutated after being handed to the EasyDMA + /// hardware until the END or ERROR event is observed. + pub(crate) fn push(&mut self, addr: *mut u8, sz: u32, dmatag: u32) { + assert!(self.count < N); + let desc = Descriptor::new(addr, sz, dmatag); + + let idx = self.count; + self.descs[idx] = desc; + self.count += 1; + + // update links + if idx > 0 { + let prev = idx - 1; + self.descs[prev].next = &mut self.descs[idx]; + } + + self.descs[idx].next = LAST_DESC_PTR; + } + + /// Returns an address to the first descriptor in the chain. + /// + /// This pointer is intended to be written to the EasyDMA input/output pointer + /// register to start a scatter-gather transfer. + pub(crate) fn first(&mut self) -> u32 { + &mut self.descs[0] as *mut Descriptor as u32 + } +} + +pub(crate) fn sz(n: usize) -> u32 { + const DMA_REALIGN: usize = 0x2000_0000; + let group_end = (n.saturating_sub(1) / 4 + 1) * 4; + (group_end | DMA_REALIGN) as u32 +} diff --git a/embedded-cal-nrf54l15/src/lib.rs b/embedded-cal-nrf54l15/src/lib.rs new file mode 100644 index 0000000..ce3fc1b --- /dev/null +++ b/embedded-cal-nrf54l15/src/lib.rs @@ -0,0 +1,223 @@ +#![no_std] +mod descriptor; + +use descriptor::DescriptorChain; +use nrf_pac::{cracen, cracencore}; + +use crate::descriptor::sz; + +const MAX_DESCRIPTOR_CHAIN_LEN: usize = 4; +const INTERNAL_STATE_LEN: usize = 32; + +pub struct Nrf54l15Cal { + // FIXME: No need to enable and take ownership of everything + // it's possible to have a more granular ownership + cracen: cracen::Cracen, + cracen_core: cracencore::Cracencore, +} + +impl embedded_cal::Cal for Nrf54l15Cal {} + +impl Nrf54l15Cal { + pub fn new(cracen: cracen::Cracen, cracen_core: cracencore::Cracencore) -> Self { + // Enable cryptomaster + cracen.enable().write(|w| { + w.set_cryptomaster(true); + w.set_rng(true); + w.set_pkeikg(true) + }); + + Self { + cracen, + cracen_core, + } + } +} + +impl Drop for Nrf54l15Cal { + fn drop(&mut self) { + // Disable cryptomaster on drop + self.cracen.enable().write(|w| { + w.set_cryptomaster(false); + w.set_rng(false); + w.set_pkeikg(false) + }); + } +} + +pub struct HashState { + // FIXME: Use this when implement SHA2-224 + _variant: embedded_cal::plumbing::hash::Sha2ShortVariant, + state: Option<[u8; 32]>, + processed_bytes: usize, +} + +pub enum HashResult { + Sha256([u8; 32]), +} + +impl AsRef<[u8]> for HashResult { + fn as_ref(&self) -> &[u8] { + match self { + HashResult::Sha256(r) => &r[..], + } + } +} + +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum NoFullAlgorithms {} + +impl embedded_cal::HashAlgorithm for NoFullAlgorithms { + fn len(&self) -> usize { + match *self {} + } +} + +impl AsRef<[u8]> for NoFullAlgorithms { + fn as_ref(&self) -> &[u8] { + match *self {} + } +} + +impl embedded_cal::HashProvider for Nrf54l15Cal { + type Algorithm = NoFullAlgorithms; + type HashState = NoFullAlgorithms; + type HashResult = NoFullAlgorithms; + + fn init(&mut self, algorithm: Self::Algorithm) -> Self::HashState { + match algorithm {} + } + + fn update(&mut self, instance: &mut Self::HashState, _data: &[u8]) { + match *instance {} + } + + fn finalize(&mut self, instance: Self::HashState) -> Self::HashResult { + match instance {} + } +} + +impl embedded_cal::plumbing::Plumbing for Nrf54l15Cal {} + +impl embedded_cal::plumbing::hash::Hash for Nrf54l15Cal {} + +impl embedded_cal::plumbing::hash::Sha2Short for Nrf54l15Cal { + const SUPPORTED: bool = true; + const SEND_PADDING: bool = false; + const FIRST_CHUNK_SIZE: usize = 64; + const UPDATE_MULTICHUNK: bool = true; + + type State = HashState; + + fn init(&mut self, variant: embedded_cal::plumbing::hash::Sha2ShortVariant) -> Self::State { + Self::State { + _variant: variant, + state: None, + processed_bytes: 0, + } + } + + fn update(&mut self, instance: &mut Self::State, data: &[u8]) { + let mut new_state: [u8; 32] = [0x00; 32]; + + let header: [u8; 4] = [0x08, 0x00, 0x00, 0x00]; + + let state_len = INTERNAL_STATE_LEN; + + let mut output_descriptors = DescriptorChain::::new(); + output_descriptors.push(new_state.as_mut_ptr(), sz(state_len), 32); + + let mut input_descriptors = DescriptorChain::::new(); + + input_descriptors.push(header.as_ptr() as *mut u8, sz(4), 19); + + if let Some(state) = &instance.state { + input_descriptors.push(state.as_ptr() as *mut u8, sz(state_len), 99); + } + + input_descriptors.push( + data.as_ptr() as *mut u8, + 0x2000_0000 | data.len() as u32, + 35, + ); + + self.execute_cryptomaster_dma(&mut input_descriptors, &mut output_descriptors); + + instance.state = Some(new_state); + instance.processed_bytes += data.len(); + } + + fn finalize(&mut self, instance: Self::State, last_chunk: &[u8], target: &mut [u8]) { + let mut pad: [u8; 256] = [0x00; 256]; + + let padding_size = embedded_cal_software::sha256_padding( + instance.processed_bytes + last_chunk.len(), + &mut pad, + ); + + let algo_len = 32; + let state_len = INTERNAL_STATE_LEN; + + let mut out: [u8; 64] = [0x00; 64]; + + let mut output_descriptors = DescriptorChain::::new(); + output_descriptors.push(out.as_mut_ptr(), sz(algo_len), 32); + + let header: [u8; 4] = [0x08, 0x04, 0x00, 0x00]; + + let mut input_descriptors = DescriptorChain::::new(); + + input_descriptors.push(header.as_ptr() as *mut u8, sz(4), 19); + + if let Some(state) = &instance.state { + input_descriptors.push(state.as_ptr() as *mut u8, sz(state_len), 99); + } + + input_descriptors.push(last_chunk.as_ptr() as *mut u8, last_chunk.len() as u32, 3); + + input_descriptors.push( + pad.as_ptr() as *mut u8, + 0x2000_0000 | padding_size as u32, + 35, + ); + + self.execute_cryptomaster_dma(&mut input_descriptors, &mut output_descriptors); + + target.copy_from_slice(&out[..32]); + } +} + +impl Nrf54l15Cal { + fn execute_cryptomaster_dma( + &mut self, + input_descriptors: &mut DescriptorChain, + output_descriptors: &mut DescriptorChain, + ) -> () { + let dma = self.cracen_core.cryptmstrdma(); + // Configure DMA source + dma.fetchaddrlsb() + .write_value(input_descriptors.first() as u32); + + // Configure DMA sink + dma.pushaddrlsb() + .write_value(output_descriptors.first() as u32); + + dma.config().write(|w| { + w.set_fetchctrlindirect(true); + w.set_pushctrlindirect(true); + w.set_fetchstop(false); + w.set_pushstop(false); + w.set_softrst(false) + }); + + // Start DMA + dma.start().write(|w| { + w.set_startfetch(true); + w.set_startpush(true) + }); + + // Wait + while dma.status().read().fetchbusy() {} + while dma.status().read().pushbusy() {} + } +} diff --git a/embedded-cal-nrf54l15/tests/integration.rs b/embedded-cal-nrf54l15/tests/integration.rs new file mode 100644 index 0000000..5e017a5 --- /dev/null +++ b/embedded-cal-nrf54l15/tests/integration.rs @@ -0,0 +1,39 @@ +#![no_std] +#![no_main] + +use defmt_rtt as _; +use panic_probe as _; + +struct ImplementSha256Short; +impl embedded_cal_software::ExtenderConfig for ImplementSha256Short { + const IMPLEMENT_SHA2SHORT: bool = true; + type Base = embedded_cal_nrf54l15::Nrf54l15Cal; +} +struct TestState { + cal: embedded_cal_software::Extender, +} + +#[defmt_test::tests] +mod tests { + use super::ImplementSha256Short; + use embedded_cal_nrf54l15::Nrf54l15Cal; + + #[init] + fn init() -> super::TestState { + // FIXME: How to make sure there is a exclusive reference for CRACEN_S? + let base = + embedded_cal_nrf54l15::Nrf54l15Cal::new(nrf_pac::CRACEN_S, nrf_pac::CRACENCORE_S); + + let cal = embedded_cal_software::Extender::::new(base); + + super::TestState { cal } + } + + #[test] + fn test_hash_algorithm_sha256(state: &mut super::TestState) { + embedded_cal::test_hash_algorithm_sha256::< + ::Algorithm, + >(); + testvectors::test_hash_algorithm_sha256(&mut state.cal); + } +} diff --git a/embedded-cal-software/src/lib.rs b/embedded-cal-software/src/lib.rs index 1157ad7..fbae926 100644 --- a/embedded-cal-software/src/lib.rs +++ b/embedded-cal-software/src/lib.rs @@ -10,7 +10,7 @@ use embedded_cal::{ plumbing::hash::{SHA2SHORT_BLOCK_SIZE, Sha2Short, Sha2ShortVariant}, }; -trait ExtenderConfig { +pub trait ExtenderConfig { const IMPLEMENT_SHA2SHORT: bool; type Base: Cal + Plumbing; @@ -18,6 +18,12 @@ trait ExtenderConfig { pub struct Extender(EC::Base); +impl Extender { + pub fn new(base: EC::Base) -> Self { + Self(base) + } +} + const HASH_WRAPPER_MAX_BLOCKSIZE: usize = 68; impl embedded_cal::Cal for Extender {} @@ -263,7 +269,7 @@ impl AsRef<[u8]> for HashResult { // Remaining code is copied from https://github.com/lake-rs/embedded-cal/pull/9 -fn sha256_padding(msg_len: usize, out: &mut [u8; 256]) -> usize { +pub fn sha256_padding(msg_len: usize, out: &mut [u8; 256]) -> usize { sha2_padding(msg_len, 64, 56, 8, out) } diff --git a/embedded-cal/src/plumbing/hash/mod.rs b/embedded-cal/src/plumbing/hash/mod.rs index a3a2c4c..1e7390d 100644 --- a/embedded-cal/src/plumbing/hash/mod.rs +++ b/embedded-cal/src/plumbing/hash/mod.rs @@ -22,7 +22,8 @@ pub const SHA2SHORT_BLOCK_SIZE: usize = 64; /// field in their struct). They could avoid this by applying some clever tricks with putting the /// buffer in a possibly-zero-sized array if that is really an issue. pub const fn hash_buffer_requirements() -> usize { - let for_sha2 = if ::SUPPORTED { + // When more come, place the maximum here + if ::SUPPORTED { if T::FIRST_CHUNK_SIZE > SHA2SHORT_BLOCK_SIZE { T::FIRST_CHUNK_SIZE } else { @@ -30,7 +31,5 @@ pub const fn hash_buffer_requirements() -> usize { } } else { 0 - }; - // When more come, place the maximum here - for_sha2 + } } diff --git a/testvectors/src/lib.rs b/testvectors/src/lib.rs index 41ee867..986b759 100644 --- a/testvectors/src/lib.rs +++ b/testvectors/src/lib.rs @@ -1,3 +1,4 @@ +#![no_std] use hexlit::hex; pub const SHA256HASHES: &[(&[u8], [u8; 32])] = &[ @@ -9,6 +10,32 @@ pub const SHA256HASHES: &[(&[u8], [u8; 32])] = &[ b"hello world", hex!("b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"), ), + ( + &hex!("d3"), + hex!("28969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c1"), + ), + ( + &hex!("11af"), + hex!("5ca7133fa735326081558ac312c620eeca9970d1e70a4b95533d956f072d1f98"), + ), + ( + &hex!("b4190e"), + hex!("dff2e73091f6c05e528896c4c831b9448653dc2ff043528f6769437bc7b975c2"), + ), + ( + &hex!("74ba2521"), + hex!("b16aa56be3880d18cd41e68384cf1ec8c17680c45a02b1575dc1518923ae8b0e"), + ), + ( + &hex!("c299209682"), + hex!("f0887fe961c9cd3beab957e8222494abb969b1ce4c6557976df8b0f6d20e9166"), + ), + ( + &hex!( + "37ebe98ef52bfb240b9ad369153afe081bbcf9d7ae43e8ba336b8ac57e8a6da0a3365e3008072473bf9d6eac13e509c1619956e12a06fc696512da091a7d40232c675e737713fcf51aea6c0316c3bdbe196132b0943df2b013860105ce676fce7b88d0a167d7ec72c588b7b6465a83c9ea1d748d15713455e5d0e901c3cf646a38a09b0002dc5ab1687f350dca35c1a87cd404c0d529292082f77844203d86be0bb8a9d970a9af7baad8d050cbd9e024788eca91fbed39db930398180e393d949ad7e173d9c65498339a6ec670d049058653ad48af45cc4cbffd30c3b54cf1b290052b1864bcafd0accdf9b8e2a163134d2c982c1bba4a3dafec288e3cfd0ae1934a6f0e39122aebbd7a586e48d495167620708664d31c740bd868c1ccd5f0e94baf959e81502cb00da87330cbf149d5a8381e9eb519a8b97acad7a48c5b0c92623b861064ff1ce8455f32469381e6198c7b8abc341357d6a4c85f7fa517c4a47df728ac09a6645b0ca77df7c70cd4aacaf19c280949919132dde7993e9181e647e964ba99cd6bd10b893c8d90187a5009a23d295d43bfb4cc0e583b8052ac21651b23813bfc9912ea0c574e152f42d3f1975309588a4705196598ad93e1ab1d82954b4a18bc56e55039b6837fd893fa2bd7c70e21a5934dc2e990379ec6e8a2445dc55d57940a14e5164273f59cd58e5f6a8281e11c09536ea22821c98ac978537d7a02220d1d6552aee168a001715834596baabf7813e1c69949b23eb4b86658fd51819eadf8a13f067ca8a791cd1d53ab69d0e43f18bd72d5d93322cc1c36fbe33121f5ff01905328fc7c33d452a86468663c77fc80b0195ec1eca05a5daee339042b4f88a1f9371b472c6c5168c00e984937a134b282633dea25dde7e397b907b1e7d3d240a593e747007990782cf944fa078a7118fbfa793b2604fa15b82453209daa64475d0e95e2408319e8b5ce7460f4593a19e3831a9b363b1c5ddbcd273995fbc61ce7502b0233b1752223352e654837181d01a929f49faad422c65b8ae416ef81290b02b48e222c2b8c3ed57cf0494b928c1e11ad2da77baacd427785096aae1cd593cc356e551bc390cd5765ea41be30cf0266ae2e97d326c417c91e90d75f1f874555b88a14a7c5959a62f23976b77a4c754e35dfb7ddd1700df85f61a62b12a9eb4644caa7f8ba036b9f29c6315ff96c3f7148284ebe3239ecad50641f397ea24b46e21655352a4109b61479b9dd34972779f2f1a6a1d2887b8ff88289b2ebda2efe995668879bb93c4ebb3a585ab336f70b382205ac37c383475fa12ebddfb95b157172261597d2cb0f24f254feffaf75d224a3b407eb54cc7c8daa5483e4a79c347252d808a5f480a35987f6f09f6c6a73bd5cfbdb76a11ed78b86442b810cb703a5dec5874e8721af62e386591bd39d990b3521505e144100601b46de3f50752911ff37bb18f377de45ec4c60fc4ed8ea1717708d2d13fc9e1453a1c4a4db9e4fbe9b74cb8da14ad50c8c8f2ec944e10ee8e82ebb6a081959b0159f043a15fa1cb59bc5e035f7623fbfaa99ea0a1d81ae8692a4019e5a5edb3a4886c789675039fde87222975e86c2642eb0bd48408072fafb1a88507194c9bdd69f3418376a4d9e68c3b83b3f800605ff1dcf0917a6014b0dd77708b583ce3ea632746fee0e01a10500cba90016b4a9072847d809bb0481ae25f74f8ef290c7a087ae16f505fd0da670826a0b1174592d184e3a7e8622a5c84a30ab64aab75face50b96b217e8ea335c0605c638ed1c59370bb9ded004be428f49a79f74ec0fb296b3758f0b6b41930c7e029b55c8fa73cba7dc926151d4043c6bc8a716d7de9ae0cd3ef3ab2d19b0c813eaf12eacfb641d492b0001b2f0f699bd98e4581fd44c0c817646bdd77a71d8ed432f8d422812751a2f9178cf1800ee689ebf046cf9b161f9a7ef0a106cbe833398bf383288661b426fad8d4f570a8293629ee06856af295a58585a81f87f130e6e08f723234856e874bd0adbb2fc9e676deab6b9f22faacf12e875d1259ccea54f7294be02a16f34c427b51a33be8a0c460c4c07d51a2e7d5c0722a9fcfefd21c265d5aa2c57ae4fe95556b5e1388ea9756a6afb0856fb8fbe1d2bb1838be7a95049848fa9545b616badb753c453f266836eda3c92cd592bc0925690c42cd6667f866717827ebe91d0999f9de5f5fd6cf77f63737b65927aebcf6cefc7ca107fda8447e8bebf1f08a280d53a4b07f8e35904cc48cc08eda3c63a3475924bde1de6acebaa65fec5ee68ca22d3fe722bf33267de628c9db1ceda3c78cb2f9988682d641d068023f96aabde4e10071cdec2080f616ac30c2725ad3efe98a69a56873615a3a3161503a4f22621986def597b66641d07793d97cdc9a68f85fd3890a38928462b2fbe2bc5c509631438d2e344d1ced9e2b71748f1b6ddf33a3e597de3af03ce43d305b9f5acefdb2b71acc645d3b55fa3848484b7fa4cf25e71e766702f1003950bd2f45b304052861f6748a8f38175f1e96c91471f5a54999cc9937191b6adc9de0d2520d86590cd4aeab292ba9ae474edb5b8caad6ee095c9e74c0f5e5c9387559f946b2dc45da7fa1d4c2dae6973d5984841682af25ff7ff29d9721d6c7e76776e8965b6c681bc38e85da15954ecbcf20d7448204d9a6a477781c1564d363e4c634c36fbd3c3b50b332f1643c415d004ec999316e75694a8b98e2591678388dc6624058454ec3a7ce608b3f222b8bad5cef77095285e1d2ad746c557222dfc30605bfadaafc4f292e931a0f0d49b226d99d708247879aed5b9f2ca2fe6fb414f37373f844e13865524f206c54487aed53781834b3f6eefb248d95ba21bb60041d501f90a97a19dcd80920df7d84309148e3d0892e50687c86a45a1372926e00f200053f5f436e003e35bdc10fa99d9328853bf82d2091f1f087cc37678138ac0027e73cbcc99f7fe37939c98114fc7380c0ad1a26e3f5ec00bc7eae77045a55c62c18117879389c662837415852e7a2d01ac667a226fedb2596e3e137a83daec2712a65e8cec3e644e738d11bdfe9b19517fa593546373fddcb9e681fc97d1763bb9092a456cc0dfe1aa0e132387d105e3ccb7746ee199aa7af00bb96047310585fed40219dab43f057220a41e90c5f89fdac4a5d6b207c01d5ad4440c5ca29eed292c6f7000c58da111eb4b16e31efa6df3f3aff69e6447ac406aa96a9ece4b5b813bf8b3a499d09cd0969073468513355d6c19346c58480feaf470e0d45a13b74f2925488fd810e0f74afb9e82a24cdf61586bfae68dc92ea09b22d8c8f1ffe9db1e7e98892b5554ce2e15fd5f1cac5347df2eafd2a8d5f1aa8746b9403915da6d418c0b5a3aa8e09d6b65f9a49c3b7a5728e9baf95471404fdf64eb05da5f704dbad60ac9ac106cab2873fb1bc9023ad95c24852337a703d9cc04d6df7de594c3b2e4fb9f2996e0418ec8698a4c087c14a2687717f97e228e75afe295caae2f16513f47a45b4124a7c5ebacbacc562951233bf89f43ff85b703ec77f168c2278fbe6e57a0e7192125f4642d73f2f227d806287081bd30149b9d44fdb90029667622f9925b7826bd0343bc537c66e660f174b447860e1bb8846c3edcb639ebd213a4695f9cb471e188db7a859fcf3abae49569e676dec857b897627cb0bc1155ad6d45282d430176fde4262da2d5f41ff890ceb319d73dda804738456f30a3d68da41554d4cede62aa8549b24e211e76768e6b17379f842a24a449a0ba3ea73cfc72624b5afd118fd7e76a7c6b5bbfa7a6b6c97b97dea52decd51cf35a8e277140ffb2748777a1e3cc3211f3c12be099d0316f45023da6cd200339a718c72a5ca172903922e59648d08dc67f173788363c26e5df406391f107552925ba91b9e569f38101f5eef9a52d201288372abf6532beb4af19fa6d81eaf473d40896dbf4deac0f35c63bd1e129147c76e7aa8d0ef921631f55a7436411079f1bcc7b98714ac2c13b5e7326e60d918db1f05ffb19da767a95bb141a84c4b73664ccebf844f3601f7c853f009b21becba11af3106f1de5827b14e9fac84b2cbf16d18c045622acb260024768e8acc4c0ae2c0bd5f60a98023828cdec18ed8dc298a306c38d1ece01509f3265b5f8cbf441f0525097e8b48234bf69f65cf402c7540a023ed231ef95b222a900ea4bfaeec02c6d8b3b01648ad7a165237ca6b557b1ce287b0ea137f4ef54534070ee793695a9078ec89bcea389956878614ccbf917b61f8427b7cda870fdd92d2d297154262fc65f28ff1a54b2651afff12d6f36ee8c906107bbda399ce5e2cf0a430ad0dd86520841757126bad725bf1593c7959f16221894f5852ddad3172fef866b3321755491fd44fba009b42ec0b6c4fb9e901d7eb3b8acf70e94911f54c538bd0559c5740042b6df4a07c3e00bba0934d92a684b39592a576331e5a44672a227ccef3e595ffa1146ac1dcee0a70baa9acfd5c132b361b5ceb519984b0ee00cd2124aa8acb50c9e574fb19bd99c8fef5407faeedb28b796848bb372beb3f5bde55ed2cb140b60a53bba2df471f330208b09ffb8eda04315a06d693aa53d9bff8939ef6f3a68de6e1975f79f50b3d484665e4ee71124ed794be3a2baa7b5b918e62a095bc5d46e401a0979641fe465640e8d4d43eeba9d0cac76c7b86d22375123b988585e58f86566fd190d868eca08aa1e66932d6d3b14ecad3efd9f8cfcf2696ed42eadfa642324d941602cbaebb8639a00a17542afda32117051e4fbf243dfd255a559c49ac37c265827ba70b0bc618882336f43e1a6a729c57be478008cae6c74840bbe828c976ac628d7b6015bcb705612c277bac0727da645480a0e14fdc497956aef05c89d30f22c2c96c6dfc9dae30617e6206fbd957975b8ba0524f563289e1f5f09bdb6fd46fa6117e78e854f91d71699fcfcadfaa7d4db8fcb04bed08d68d11677b5085b295c1d414cb12456c84c669737af6c33992a5a9149fc7f9330bb291d38f6bed10318081dde8fd178f02eb0e8b7d022c8b63fdcc867546035775fcf7b32c8fee83df7cbb28372b23c71459b9566a7f64165da0a3d0e538a3dcc1b6a384f75f0263dc10e0924a0ef2ab459d0a52b7c112710c58cf72442253396b8a25d7644be166c3e7828aa62b1ca1f32f620ed969b021ec609fe926958a03cff21f08f7c8d3d3235b219fb0020a51b97b60f963ebb58f7a62a5b41104c0b28b58cfc81668825f87064e401c263421152b8790dbc99b3032c9615187f29fcc1a58e86364ad45524b5358fa2f0a3296729a3663a585e9aa922f534fefd16fb6f96cd9895709c5520cdcd24c8d107e387e520de055a3296544ef1c1ddd43b919a4ff139861f06ae5280d5aa5aaeb8f7d74ed6ea56093c2e697a30c29c4ac145aa99a372f1a03ae72495f52a40cfddedc12b6e9115aea5ea516c5a4223a8d0a0073c8b4abe3c6188fdd6d4ab627c9f4eab468fdc2a91945274ed18465a368f291a0050c9d638a31944091b35a8fd26a1ff65e2d17dfa32ef3ac412d8293b276849ad9af71fdf272363f771d0fa99996e24510e7bf731a7480cbbefff7801c0e5fd0a13dd8278162ec1687f85409a203e82d2bcdf7e7d1ae5509857c42fce80299fe06182e74a97c0c624ed5b6246e59781af9407fb28b34f7024f42d36eb92bb95f72cee379ed363daf2625b48e60d0489b23dfa57789c0dd2276b4575a01c2349171d2a58bcf29e659b868cdac1c30a02a160c078b6faa7e0696711d43447ea2108db3d34ec1bf9cfe802f601212d335445a4624829f8a600b18e9b3cf13a9787910f2fb27676fd809e7ea1a34c7306e766b2e7ae1bbb919cc888ea931d1eb2e27c6109b9a12c31e188a196a98bbe0b24cc315791d26ef01b77fe06c3011ac39a8f78d233b7651e586d14dcfc2636cb713ecabadb97374ce58498f8b2e557531793fd9207fe484a4e147f7b826502cd3785251973b23e2b62b7fdc74a10fce9c04f97511dbffe3f2c46887c25904b99df69e97b416bac18fadad67b71cc320eff8def185d41ae8558cbdae6ccee38b8cfb2bfe92d0aa99815b3ca1d115f21493b13adeeafce81a23c6b1bc15fc8f2b171284e6a1fd65c351b0c82b31112f022ddaa78dcfbac9f203eeef415c566a00c2c933f06ff18ee7674aba548592dc8214b1af8e929242f87c81b0cebe8106b5267ba39c5b51987e38858dce1d1f8d0cfee2bd61d217e5a5d41bb0c4aaf0e7b0a8c66e5b0291e4d05bfddcf8861bb31b32ea5ba80cb02472c11969b3b02a7f7bc025feace44726b6382012544f1bd1256744f4b1b0ff81f7b9f7462c5c92507f1316df228ec5c0786378b871e69479c3e26f232f5d6a709d3551d08f0ecced52f8158a2c40a234af448449c1cb1a1f6f5ae56171606582ebb9a5836c454eb86015ae7a4ac87105b371bf40d49b1134a037243a0878953b5bbd6ef944ae7c345ec24e4a0e8496b62d71a6381aa52e5bdeedc81784f45e0c75b72a8c9898ea0387a47153d7e3a7c895aab58a1497a5e794052d7457624478c24d44c7e8932c887322b422478418af64a389c152d12c7a6803e0fb0050dcf2b9d65a35a53b9845b9c3835fddd45dfd12e28f8845e03686b3707ef6003e7c1cd4f8d7406ee0d1cdc41d7b56fb630c1438fe33196e53389f1ec1540fe789c6599c0b589296214d831a86e89220ae97974f4d112f4c98c726027d0c9316d1303b87a43a86cb8b800835a677abfe1584e8be55a624612f56bdf71a054a2e834e35105a19a77f7dfdbf9dd2850ee44658ab0eae6e833c855bb9650eda7f8f4e74d8de73526f12773b2bcbb1bd35639f8730d8cdd6d64f496abae4e1f8cdc96148894aa691683515bcdf37ba6caa0cbf953c752a7b9819e9f834ff39ec8f6d8a3dd8dd5a431d47c7f74c7a633ff73ff507009c5ac9431cc588ba0c6d226edc17c94a0f14d3e8db0c7ef60c3293878dfe513f96b54c61c88a90aca4f246d6a5988f5f785ce0655f51b85e55af03e5772a083bfcf0816ebd97a4af416fa6414a9ad47b7198e51d55463807ef4f0d9b7c06a0a84762e4e46c8b39147a4bdd594b8d4d40b36f5e6b4d48726551890d040d229ee70ea3034d45b3c28eb80d686918fe6e219636b8f9b7e6fc08f4e3bed9bafc778aab274913e9cfd570732ab3fb434c9ba0928581232580495571e56f6705f2af05b56642c2b93df65c443a6caa5b167a4040d2438206d2cefd3114ab466eb3c9eaa5e66cf4447c89c493a2eee0b0ea6e7329b37c90ec2d0142bae7fef265ae3c9c053e44031c0a142bf9faa728e5170cdba59fa8da361d94d887d5d6f58b409bbc4bd4548990653a04dfb841fd784ac9cc4cfd34c88512de212074dfba30295badf22f1af2522c5fe1cd423bd8eae429d7a862bcd649ab61bf0d3b55daf4b6f0f390c503d7c1bdea453b5ef145bd8191802056bd9e0455a404b6afe5b25977f02f902caba46f988d91b2350ebe4091b5584d4f938a45803984a5291beadeeadda488dc7ed2dc4aae69ca8ae0bd4492f9b297c3fb257de986c1615d44dee59e1e14d34af9fd7852b13fdcb713dd1a03d341884a30ea1dc0104d63a31d291df035d317fea98ec44f5a86715014783172e667a748f162c5c26a8b34a0f133d89fb971bf6e0a01507efed010cc7f194b5e87a77d56a909d65efa0d5ccd6da9b5eb1d73422f97ffad8012af43a2905a98354b8362e9c459f0044336348eded53660d65a38a9efc42be13a6672790496d875a67e0078dfdd8340dab8547be140ca9f88891b635e195c20daa8359658785cbe3d09ce8a580f009324e6550b0196e305889262f28f49dead77e6f5a0e859c57d53c935a4c9590879b6528eb2bc3230217b0897cddfeff405a6a54b2f50c58311af1ede4ea0660b73037f9a097d9d0271b45e325bec666cc7cb65ae780e361639838d10fe79907a0da0efef85d2420a84e905bb33116789526a9a88319d460f539586762ab172e4a7f305f7ae36cb88c96d91aada0b4dda3418c670e27a5fdede39bd8659e477cbe08e645af927843dbdd67489b72693efeb3a7be0e121fdf5580474ca028f39a035e78d81dd212679d0a830c050ffd43af6642d60d410aaf34f7a5ea9cb2e12f21672e3f4e0c00ccdb05758e74df3893bd40a5d7921e2e149330fddbe0a2dae4210d50a3caa60b1b9db685f7704ae2d7302b18e8261052b779139747f462a6610a37252b170afbfce905fb6f7fb8c2b6100ee231507f403fee88ba5561580d4de4cdf600bf9e9816c9da1e1d2b91a1d966d04cdb98d3be55fb77af2daeeed750b8b60b494accaa12441d372afb3d47e7395b9e0e867595a1a6c8bff8638bcb138ddcac2f3efbf89762b68ebd77247c89929620f1a3cb8dcaf9632fde0996b33e6b2621da25924b4e2c8d6bff28ae0867786919ad763e6d79fc304a06277955795a7cb17186fb6bdfa98a16189544b228f3bcd3698737ff55b6185799459b796a63c6a61cea9d20f1e296d62f474c43750b77944e5f1c09072f019dbeeb64e9bc8dec4605d8e0322cdd97f56cc43084f5c983a584855654366fd5659ea23c6c15e1d7da51d82c683aa477b9f896563a5134c64e32814ea88b7f7af760f18bc91e656da92b72e98bc03f1c6bfb442830305529d681dc6bccae66da9b2e61b9c97e2397fdb92f7f6369b470529c570c2d3b329487981d148a462cdb992d792e34dd233e1c239657b8da0d59b804566cf81ad5f0a7a0ccb3a8fbda673887c153d2e56c484f9230d752be52c1e35bc9af5a7446237fc072afef777665c264c18e6a3c059fde2e8368f9bb898f1cc8393d1bf18b1757219670275f0bbc7deb0248c68af929111e19737479bcabab732d7e033aaeb277eac05e185e9e56b2450beaac784dd0308b7a5e8ca1f2fcd8852ddad9f7b7de264478e1891a391aa89964dae5ad0b7a829c2c9209db346ceb26c1b967cfac82ad574761443be3f0a910968239d23b11507ab978b3ce89e22b7d7283736b9786544ab4460f" + ), + hex!("33b6229592ca719e4e46f35b287617fedadd3b7c38be3c8c1c9f446d2d9085b3"), + ), ]; pub fn test_hash_algorithm_sha256(cal: &mut Cal) {