From 924a42d0401aaef9fffd8eb60e3ea363c4e1375f Mon Sep 17 00:00:00 2001 From: WilliamTakeshi Date: Wed, 4 Feb 2026 16:21:28 +0100 Subject: [PATCH 1/4] chore: remove Cargo.lock --- .gitignore | 1 + Cargo.lock | 457 ----------------------------------------------------- 2 files changed, 1 insertion(+), 457 deletions(-) delete mode 100644 Cargo.lock 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" From b2ee267d49c90be05c010560c7352f3c4a8fb9c3 Mon Sep 17 00:00:00 2001 From: WilliamTakeshi Date: Wed, 4 Feb 2026 16:21:41 +0100 Subject: [PATCH 2/4] feat: make testvector's lib no-std and add a couple more examples --- testvectors/src/lib.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) 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) { From 6b0530f598054e573dcf548c2c5cb50e6283e2e1 Mon Sep 17 00:00:00 2001 From: WilliamTakeshi Date: Fri, 6 Feb 2026 15:21:01 +0100 Subject: [PATCH 3/4] feat: stm32 example --- .github/workflows/build-and-test.yml | 2 +- Cargo.toml | 3 +- embedded-cal-stm32wba55/.cargo/config.toml | 17 ++ embedded-cal-stm32wba55/Cargo.toml | 30 ++ embedded-cal-stm32wba55/build.rs | 16 ++ embedded-cal-stm32wba55/device.x | 83 ++++++ embedded-cal-stm32wba55/memory.x | 5 + embedded-cal-stm32wba55/src/lib.rs | 284 +++++++++++++++++++ embedded-cal-stm32wba55/tests/integration.rs | 29 ++ 9 files changed, 467 insertions(+), 2 deletions(-) create mode 100644 embedded-cal-stm32wba55/.cargo/config.toml create mode 100644 embedded-cal-stm32wba55/Cargo.toml create mode 100644 embedded-cal-stm32wba55/build.rs create mode 100644 embedded-cal-stm32wba55/device.x create mode 100644 embedded-cal-stm32wba55/memory.x create mode 100644 embedded-cal-stm32wba55/src/lib.rs create mode 100644 embedded-cal-stm32wba55/tests/integration.rs 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/Cargo.toml b/Cargo.toml index 1c0d0a5..8a093a4 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", "embedded-cal-stm32wba55", "testvectors"] +default-members = ["embedded-cal", "embedded-cal-rustcrypto", "embedded-cal-software", "testvectors"] resolver = "3" [workspace.package] diff --git a/embedded-cal-stm32wba55/.cargo/config.toml b/embedded-cal-stm32wba55/.cargo/config.toml new file mode 100644 index 0000000..cbfcf55 --- /dev/null +++ b/embedded-cal-stm32wba55/.cargo/config.toml @@ -0,0 +1,17 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +runner = ["probe-rs", "run", "--chip", "STM32WBA55CG", "--log-format=oneline", "--allow-erase-all", "--verify"] + +[target.thumbv8m.main-none-eabihf] +rustflags = [ + "-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" + +[env] +DEFMT_LOG = "info" diff --git a/embedded-cal-stm32wba55/Cargo.toml b/embedded-cal-stm32wba55/Cargo.toml new file mode 100644 index 0000000..6e5a6d4 --- /dev/null +++ b/embedded-cal-stm32wba55/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "embedded-cal-stm32wba55" +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" +stm32-metapac = { version = "18.0", features = ["stm32wba55cg", "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" +defmt-test = "0.4" +panic-probe = { version = "1.0", features = ["print-defmt"] } diff --git a/embedded-cal-stm32wba55/build.rs b/embedded-cal-stm32wba55/build.rs new file mode 100644 index 0000000..3cc1248 --- /dev/null +++ b/embedded-cal-stm32wba55/build.rs @@ -0,0 +1,16 @@ +use std::{env, fs, path::PathBuf}; + +fn main() { + let out = PathBuf::from(env::var("OUT_DIR").unwrap()); + + // Per-chip memory and device files + fs::copy("memory.x", out.join("memory.x")).expect("could not copy memory.x"); + fs::copy("device.x", out.join("device.x")).expect("could not copy device.x"); + + // Make the linker search the OUT_DIR + println!("cargo:rustc-link-search={}", out.display()); + + // Rebuild if either file changes + println!("cargo:rerun-if-changed=memory.x"); + println!("cargo:rerun-if-changed=device.x"); +} diff --git a/embedded-cal-stm32wba55/device.x b/embedded-cal-stm32wba55/device.x new file mode 100644 index 0000000..6ac3e54 --- /dev/null +++ b/embedded-cal-stm32wba55/device.x @@ -0,0 +1,83 @@ +PROVIDE(WWDG = DefaultHandler); +PROVIDE(PDV = DefaultHandler); +PROVIDE(RTC = DefaultHandler); +PROVIDE(RTC_S = DefaultHandler); +PROVIDE(TAMP = DefaultHandler); +PROVIDE(RAMCFG = DefaultHandler); +PROVIDE(FLASH = DefaultHandler); +PROVIDE(RCC = DefaultHandler); +PROVIDE(RCC_S = DefaultHandler); +PROVIDE(EXTI0 = DefaultHandler); +PROVIDE(EXTI1 = DefaultHandler); +PROVIDE(EXTI2 = DefaultHandler); +PROVIDE(EXTI3 = DefaultHandler); +PROVIDE(EXTI4 = DefaultHandler); +PROVIDE(EXTI5 = DefaultHandler); +PROVIDE(EXTI6 = DefaultHandler); +PROVIDE(EXTI7 = DefaultHandler); +PROVIDE(EXTI8 = DefaultHandler); +PROVIDE(EXTI9 = DefaultHandler); +PROVIDE(EXTI10 = DefaultHandler); +PROVIDE(EXTI11 = DefaultHandler); +PROVIDE(EXTI12 = DefaultHandler); +PROVIDE(EXTI13 = DefaultHandler); +PROVIDE(EXTI14 = DefaultHandler); +PROVIDE(EXTI15 = DefaultHandler); +PROVIDE(SAES = DefaultHandler); +PROVIDE(GPDMA1_CH0 = DefaultHandler); +PROVIDE(GPDMA1_CH1 = DefaultHandler); +PROVIDE(GPDMA1_CH2 = DefaultHandler); +PROVIDE(GPDMA1_CH3 = DefaultHandler); +PROVIDE(GPDMA1_CH4 = DefaultHandler); +PROVIDE(GPDMA1_CH5 = DefaultHandler); +PROVIDE(GPDMA1_CH6 = DefaultHandler); +PROVIDE(GPDMA1_CH7 = DefaultHandler); +PROVIDE(TIM1_BRK_TERR_IERR = DefaultHandler); +PROVIDE(TIM1_UP = DefaultHandler); +PROVIDE(TIM1_TRG_COM_DIR_IDX = DefaultHandler); +PROVIDE(TIM1_CC = DefaultHandler); +PROVIDE(TIM2 = DefaultHandler); +PROVIDE(TIM3 = DefaultHandler); +PROVIDE(I2C1_EV = DefaultHandler); +PROVIDE(I2C1_ER = DefaultHandler); +PROVIDE(SPI1 = DefaultHandler); +PROVIDE(USART1 = DefaultHandler); +PROVIDE(USART2 = DefaultHandler); +PROVIDE(LPUART1 = DefaultHandler); +PROVIDE(LPTIM1 = DefaultHandler); +PROVIDE(LPTIM2 = DefaultHandler); +PROVIDE(TIM16 = DefaultHandler); +PROVIDE(TIM17 = DefaultHandler); +PROVIDE(I2C3_EV = DefaultHandler); +PROVIDE(I2C3_ER = DefaultHandler); +PROVIDE(TSC = DefaultHandler); +PROVIDE(AES = DefaultHandler); +PROVIDE(RNG = DefaultHandler); +PROVIDE(HASH = DefaultHandler); +PROVIDE(PKA = DefaultHandler); +PROVIDE(SPI3 = DefaultHandler); +PROVIDE(ICACHE = DefaultHandler); +PROVIDE(ADC4 = DefaultHandler); +PROVIDE(WKUP = DefaultHandler); +PROVIDE(HSEM = DefaultHandler); +PROVIDE(HSEM_S = DefaultHandler); +PROVIDE(PVD = DefaultHandler); +PROVIDE(FLASH_S = DefaultHandler); +PROVIDE(GTZC = DefaultHandler); +PROVIDE(IWDG = DefaultHandler); +PROVIDE(TIM1_BRK = DefaultHandler); +PROVIDE(TIM1_TRG_COM = DefaultHandler); +PROVIDE(COMP = DefaultHandler); +PROVIDE(SAI1 = DefaultHandler); +PROVIDE(FPU = DefaultHandler); +PROVIDE(RADIO = DefaultHandler); +PROVIDE(WKUP_S = DefaultHandler); +PROVIDE(RCC_AUDIOSYNC = DefaultHandler); +PROVIDE(GPDMA1_CHANNEL0 = DefaultHandler); +PROVIDE(GPDMA1_CHANNEL1 = DefaultHandler); +PROVIDE(GPDMA1_CHANNEL2 = DefaultHandler); +PROVIDE(GPDMA1_CHANNEL3 = DefaultHandler); +PROVIDE(GPDMA1_CHANNEL4 = DefaultHandler); +PROVIDE(GPDMA1_CHANNEL5 = DefaultHandler); +PROVIDE(GPDMA1_CHANNEL6 = DefaultHandler); +PROVIDE(GPDMA1_CHANNEL7 = DefaultHandler); diff --git a/embedded-cal-stm32wba55/memory.x b/embedded-cal-stm32wba55/memory.x new file mode 100644 index 0000000..1aa63d3 --- /dev/null +++ b/embedded-cal-stm32wba55/memory.x @@ -0,0 +1,5 @@ +MEMORY +{ + FLASH : ORIGIN = 0x08000000, LENGTH = 512K + RAM : ORIGIN = 0x20000000, LENGTH = 96K +} diff --git a/embedded-cal-stm32wba55/src/lib.rs b/embedded-cal-stm32wba55/src/lib.rs new file mode 100644 index 0000000..55bc87e --- /dev/null +++ b/embedded-cal-stm32wba55/src/lib.rs @@ -0,0 +1,284 @@ +#![no_std] + +use stm32_metapac::{hash, rcc}; + +const SHA256_BLOCK_SIZE: usize = 64; +const WORD_SIZE: usize = 4; +const CSR_REGS_LEN: usize = 54; + +pub struct Stm32wba55 { + hash: hash::Hash, +} + +impl Stm32wba55 { + pub fn new(hash: hash::Hash, rcc: &rcc::Rcc) -> Self { + // Enable HASH clock + rcc.ahb2enr().modify(|w| w.set_hashen(true)); + + Self { hash } + } +} + +#[derive(PartialEq, Eq, Debug, Clone, Copy)] +pub enum HashAlgorithm { + Sha256, +} + +impl embedded_cal::HashAlgorithm for HashAlgorithm { + fn len(&self) -> usize { + match self { + HashAlgorithm::Sha256 => 32, + } + } + + fn from_cose_number(number: impl Into) -> Option { + match number.into() { + -16 => Some(HashAlgorithm::Sha256), + _ => None, + } + } + + fn from_ni_id(number: u8) -> Option { + match number { + 1 => Some(HashAlgorithm::Sha256), + _ => None, + } + } + + fn from_ni_name(name: &str) -> Option { + match name { + "sha-256" => Some(HashAlgorithm::Sha256), + _ => None, + } + } +} + +pub struct HashState { + algorithm: HashAlgorithm, + + /// HASH context swap registers (HASH_CSR0 - HASH_CSR53) + csr: [u32; CSR_REGS_LEN], + /// HASH start register (HASH_STR) + str: hash::regs::Str, + /// HASH interrupt enable register (HASH_IMR) + imr: hash::regs::Imr, + /// HASH control register (HASH_CR) + cr: hash::regs::Cr, + + /// Buffer for pending input. SHA-256 requires feeding complete NBWE-sized + /// blocks to the hardware, so this stores leftover bytes when the caller + /// provides data that does not align to a full block. + block: [u8; SHA256_BLOCK_SIZE + WORD_SIZE], + + /// Number of bytes currently stored in `block`. + block_bytes_used: usize, + + /// Indicates whether the next block to process is the first SHA-256 block. + first_block: bool, +} + +pub enum HashResult { + Sha256([u8; 32]), +} + +impl AsRef<[u8]> for HashResult { + fn as_ref(&self) -> &[u8] { + match self { + HashResult::Sha256(r) => &r[..], + } + } +} + +impl embedded_cal::HashProvider for Stm32wba55 { + type Algorithm = HashAlgorithm; + type HashState = HashState; + type HashResult = HashResult; + + fn init(&mut self, algorithm: Self::Algorithm) -> Self::HashState { + Self::HashState { + algorithm: algorithm, + csr: [0; CSR_REGS_LEN], + str: hash::regs::Str(0), + imr: hash::regs::Imr(0), + cr: hash::regs::Cr(0), + block: [0; SHA256_BLOCK_SIZE + WORD_SIZE], + block_bytes_used: 0, + first_block: true, + } + } + + fn update(&mut self, instance: &mut HashState, data: &[u8]) { + // Reinitialize the HASH peripheral before processing new input + self.hash.cr().write(|w| w.set_init(true)); + while self.hash.cr().read().init() {} + self.configure_and_reset_context(instance.algorithm); + + // Restore the previously saved intermediate state for non-initial blocks. + if !instance.first_block { + self.restore_context(&instance); + } + + // Hardware can only pause hashing after exactly NBWE (Number of words expected) words have been written. + // For SHA-256 this corresponds to 17 words for the first block, and 16 words for all subsequent blocks. + // Equivalent value available at: self.hash.sr().read().nbwe().bits() + let block_size = SHA256_BLOCK_SIZE + if instance.first_block { WORD_SIZE } else { 0 }; + + // Case 1: the provided data fits entirely in the current partial block. + // Buffer it and return, leaving the block incomplete for later continuation. + if data.len() < (block_size - instance.block_bytes_used) { + instance.block[instance.block_bytes_used..instance.block_bytes_used + data.len()] + .copy_from_slice(data); + instance.block_bytes_used += data.len(); + + return; + } + + // Case 2: the incoming data exceeds the remaining space in the current block. + // First, fill the block + data until one full block. + let data_bytes_used = block_size - instance.block_bytes_used; + + instance.block[instance.block_bytes_used..block_size] + .copy_from_slice(&data[..data_bytes_used]); + + for chunk in instance.block[..block_size].chunks_exact(WORD_SIZE) { + let mut bytes = [0u8; WORD_SIZE]; + bytes.copy_from_slice(chunk); + let word = u32::from_be_bytes(bytes); + + self.hash.din().write_value(word); + } + + // Still on case 2, if data left doesn't fully fit on the block, + // continue feeding as many full SHA-256 blocks as possible. + let data_full_blocks = (data.len() - data_bytes_used) / SHA256_BLOCK_SIZE; + let data_words = data_full_blocks * SHA256_BLOCK_SIZE / WORD_SIZE; + + if data_full_blocks > 0 { + let bytes = &data[data_bytes_used..data_bytes_used + data_words * WORD_SIZE]; + + for chunk in bytes.chunks_exact(WORD_SIZE) { + let mut buf = [0u8; WORD_SIZE]; + buf.copy_from_slice(chunk); + let word = u32::from_be_bytes(buf); + + self.hash.din().write_value(word); + } + } + + // After consuming whole blocks, the remaining bytes will always fit within a single block. + // Buffer the remainder, update the internal state, and save the hardware context. + let data_bytes_used = data_bytes_used + data_full_blocks * SHA256_BLOCK_SIZE; + instance.block[..data.len() - data_bytes_used].copy_from_slice(&data[data_bytes_used..]); + instance.block_bytes_used = data.len() - data_bytes_used; + instance.first_block = false; + + self.save_context(instance); + } + + fn finalize(&mut self, instance: Self::HashState) -> Self::HashResult { + // Reset HASH state + self.hash.cr().write(|w| w.set_init(true)); + while self.hash.cr().read().init() {} + + // Configure SHA-256 + self.configure_and_reset_context(instance.algorithm); + + // Restore the previously saved intermediate state for non-initial blocks. + if !instance.first_block { + self.restore_context(&instance); + } + + for chunk in instance.block[..instance.block_bytes_used].chunks(WORD_SIZE) { + let mut bytes = [0u8; WORD_SIZE]; + bytes[..chunk.len()].copy_from_slice(chunk); + let word = u32::from_be_bytes(bytes); + + self.hash.din().write_value(word); + } + + let number_bytes_last_chunk = instance.block_bytes_used % WORD_SIZE; + + self.hash + .str() + .write(|w| w.set_nblw((number_bytes_last_chunk as u8) * 8)); + self.hash.str().write(|w| w.set_dcal(true)); + + self.wait_busy(); + let mut hash_res_words: [u32; 8] = [0; 8]; + self.read_digest(&mut hash_res_words); + + let mut hash_result = [0u8; 32]; + for (i, w) in hash_res_words.iter().enumerate() { + hash_result[i * WORD_SIZE..(i + 1) * WORD_SIZE].copy_from_slice(&w.to_be_bytes()); + } + + HashResult::Sha256(hash_result.into()) + } +} + +impl Stm32wba55 { + /// As documented in the HASH suspend/resume procedure. + /// Used to suspend processing of the current message. + /// https://www.st.com/resource/en/reference_manual/rm0493-multiprotocol-wireless-bluetooth-lowenergy-armbased-32bit-mcu-stmicroelectronics.pdf + fn save_context(&mut self, instance: &mut HashState) { + // BUSY must be 0 + while self.hash.sr().read().busy() {} + + // Save IMR + STR + CR registers + instance.imr = self.hash.imr().read(); + instance.str = self.hash.str().read(); + instance.cr = self.hash.cr().read(); + + // Save CSR registers (0..37 always; 38..53 only for HMAC) + for i in 0..CSR_REGS_LEN { + instance.csr[i] = self.hash.csr(i).read(); + } + } + + /// As documented in the HASH suspend/resume procedure. + /// Used to resume processing of an interrupted message. + /// https://www.st.com/resource/en/reference_manual/rm0493-multiprotocol-wireless-bluetooth-lowenergy-armbased-32bit-mcu-stmicroelectronics.pdf + fn restore_context(&mut self, ctx: &HashState) { + self.hash.cr().write(|w| w.set_init(false)); + // 1. Restore IMR, STR, CR (with INIT=0) + self.hash.imr().write_value(ctx.imr); + self.hash.str().write_value(ctx.str); + self.hash.cr().write(|w| { + w.set_mode(false); // hash mode + w.set_dmae(false); + w.set_algo(3); // SHA2-256 + w.set_datatype(0) + }); + + // 2. Set INIT to reload STR/CR context into hardware + self.hash.cr().modify(|w| w.set_init(true)); + while self.hash.cr().read().init() {} + + // 3. Restore CSR registers AFTER INIT has reinitialized the core + for i in 0..CSR_REGS_LEN { + self.hash.csr(i).write_value(ctx.csr[i]) + } + } + fn wait_busy(&mut self) { + while self.hash.sr().read().busy() {} + while !self.hash.sr().read().dcis() {} + } + + fn configure_and_reset_context(&mut self, algo: HashAlgorithm) { + match algo { + HashAlgorithm::Sha256 => self.hash.cr().write(|w| { + w.set_mode(false); // hash mode + w.set_dmae(false); + w.set_algo(3); // SHA2-256 + w.set_datatype(0); + w.set_init(true) + }), + }; + } + + fn read_digest(&mut self, out: &mut [u32; 8]) { + for i in 0..8 { + out[i] = self.hash.hr(i).read(); + } + } +} diff --git a/embedded-cal-stm32wba55/tests/integration.rs b/embedded-cal-stm32wba55/tests/integration.rs new file mode 100644 index 0000000..d79e960 --- /dev/null +++ b/embedded-cal-stm32wba55/tests/integration.rs @@ -0,0 +1,29 @@ +#![no_std] +#![no_main] + +use defmt_rtt as _; +use panic_probe as _; + +struct TestState { + cal: embedded_cal_stm32wba55::Stm32wba55, +} + +#[defmt_test::tests] +mod tests { + use embedded_cal_stm32wba55::Stm32wba55; + #[init] + fn init() -> super::TestState { + let cal = + embedded_cal_stm32wba55::Stm32wba55::new(stm32_metapac::HASH, &stm32_metapac::RCC); + + 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); + } +} From 67c511aa1d8cb22cfbecae2dcaa0ec55353af749 Mon Sep 17 00:00:00 2001 From: WilliamTakeshi Date: Fri, 6 Feb 2026 16:04:14 +0100 Subject: [PATCH 4/4] chore: first version working with the plumbing API --- embedded-cal-software/src/lib.rs | 8 +- embedded-cal-stm32wba55/Cargo.toml | 1 + embedded-cal-stm32wba55/src/lib.rs | 201 +++++++------------ embedded-cal-stm32wba55/tests/integration.rs | 18 +- 4 files changed, 93 insertions(+), 135 deletions(-) diff --git a/embedded-cal-software/src/lib.rs b/embedded-cal-software/src/lib.rs index 1157ad7..5a9d80c 100644 --- a/embedded-cal-software/src/lib.rs +++ b/embedded-cal-software/src/lib.rs @@ -10,12 +10,18 @@ use embedded_cal::{ plumbing::hash::{SHA2SHORT_BLOCK_SIZE, Sha2Short, Sha2ShortVariant}, }; -trait ExtenderConfig { +pub trait ExtenderConfig { const IMPLEMENT_SHA2SHORT: bool; type Base: Cal + Plumbing; } +impl Extender { + pub fn new(base: EC::Base) -> Self { + Self(base) + } +} + pub struct Extender(EC::Base); const HASH_WRAPPER_MAX_BLOCKSIZE: usize = 68; diff --git a/embedded-cal-stm32wba55/Cargo.toml b/embedded-cal-stm32wba55/Cargo.toml index 6e5a6d4..201a8e4 100644 --- a/embedded-cal-stm32wba55/Cargo.toml +++ b/embedded-cal-stm32wba55/Cargo.toml @@ -18,6 +18,7 @@ harness = false [dependencies] embedded-cal.path = "../embedded-cal" +embedded-cal-software.path = "../embedded-cal-software" testvectors.path = "../testvectors" stm32-metapac = { version = "18.0", features = ["stm32wba55cg", "rt"] } diff --git a/embedded-cal-stm32wba55/src/lib.rs b/embedded-cal-stm32wba55/src/lib.rs index 55bc87e..1862c2f 100644 --- a/embedded-cal-stm32wba55/src/lib.rs +++ b/embedded-cal-stm32wba55/src/lib.rs @@ -2,15 +2,16 @@ use stm32_metapac::{hash, rcc}; -const SHA256_BLOCK_SIZE: usize = 64; const WORD_SIZE: usize = 4; const CSR_REGS_LEN: usize = 54; -pub struct Stm32wba55 { +pub struct Stm32wba55Cal { hash: hash::Hash, } -impl Stm32wba55 { +impl embedded_cal::Cal for Stm32wba55Cal {} + +impl Stm32wba55Cal { pub fn new(hash: hash::Hash, rcc: &rcc::Rcc) -> Self { // Enable HASH clock rcc.ahb2enr().modify(|w| w.set_hashen(true)); @@ -24,86 +25,69 @@ pub enum HashAlgorithm { Sha256, } -impl embedded_cal::HashAlgorithm for HashAlgorithm { - fn len(&self) -> usize { - match self { - HashAlgorithm::Sha256 => 32, - } - } - - fn from_cose_number(number: impl Into) -> Option { - match number.into() { - -16 => Some(HashAlgorithm::Sha256), - _ => None, - } - } - - fn from_ni_id(number: u8) -> Option { - match number { - 1 => Some(HashAlgorithm::Sha256), - _ => None, - } - } - - fn from_ni_name(name: &str) -> Option { - match name { - "sha-256" => Some(HashAlgorithm::Sha256), - _ => None, - } - } -} - pub struct HashState { - algorithm: HashAlgorithm, + _variant: embedded_cal::plumbing::hash::Sha2ShortVariant, + context: Option, +} +struct Context { /// HASH context swap registers (HASH_CSR0 - HASH_CSR53) csr: [u32; CSR_REGS_LEN], /// HASH start register (HASH_STR) str: hash::regs::Str, /// HASH interrupt enable register (HASH_IMR) imr: hash::regs::Imr, - /// HASH control register (HASH_CR) - cr: hash::regs::Cr, - - /// Buffer for pending input. SHA-256 requires feeding complete NBWE-sized - /// blocks to the hardware, so this stores leftover bytes when the caller - /// provides data that does not align to a full block. - block: [u8; SHA256_BLOCK_SIZE + WORD_SIZE], - - /// Number of bytes currently stored in `block`. - block_bytes_used: usize, - - /// Indicates whether the next block to process is the first SHA-256 block. - first_block: bool, } -pub enum HashResult { - Sha256([u8; 32]), +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum NoFullAlgorithms {} + +impl embedded_cal::HashAlgorithm for NoFullAlgorithms { + fn len(&self) -> usize { + match *self {} + } } -impl AsRef<[u8]> for HashResult { +impl AsRef<[u8]> for NoFullAlgorithms { fn as_ref(&self) -> &[u8] { - match self { - HashResult::Sha256(r) => &r[..], - } + match *self {} } } -impl embedded_cal::HashProvider for Stm32wba55 { - type Algorithm = HashAlgorithm; - type HashState = HashState; - type HashResult = HashResult; +impl embedded_cal::HashProvider for Stm32wba55Cal { + type Algorithm = NoFullAlgorithms; + type HashState = NoFullAlgorithms; + type HashResult = NoFullAlgorithms; fn init(&mut self, algorithm: Self::Algorithm) -> Self::HashState { - Self::HashState { - algorithm: algorithm, - csr: [0; CSR_REGS_LEN], - str: hash::regs::Str(0), - imr: hash::regs::Imr(0), - cr: hash::regs::Cr(0), - block: [0; SHA256_BLOCK_SIZE + WORD_SIZE], - block_bytes_used: 0, - first_block: true, + 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 Stm32wba55Cal {} + +impl embedded_cal::plumbing::hash::Hash for Stm32wba55Cal {} + +impl embedded_cal::plumbing::hash::Sha2Short for Stm32wba55Cal { + const SUPPORTED: bool = true; + const SEND_PADDING: bool = false; + const FIRST_CHUNK_SIZE: usize = 68; + const UPDATE_MULTICHUNK: bool = true; + + type State = HashState; + + fn init(&mut self, variant: embedded_cal::plumbing::hash::Sha2ShortVariant) -> Self::State { + Self::State { + _variant: variant, + context: None, } } @@ -111,36 +95,17 @@ impl embedded_cal::HashProvider for Stm32wba55 { // Reinitialize the HASH peripheral before processing new input self.hash.cr().write(|w| w.set_init(true)); while self.hash.cr().read().init() {} - self.configure_and_reset_context(instance.algorithm); + self.configure_and_reset_context(HashAlgorithm::Sha256); // Restore the previously saved intermediate state for non-initial blocks. - if !instance.first_block { - self.restore_context(&instance); + if let Some(context) = &instance.context { + self.restore_context(context); } // Hardware can only pause hashing after exactly NBWE (Number of words expected) words have been written. // For SHA-256 this corresponds to 17 words for the first block, and 16 words for all subsequent blocks. // Equivalent value available at: self.hash.sr().read().nbwe().bits() - let block_size = SHA256_BLOCK_SIZE + if instance.first_block { WORD_SIZE } else { 0 }; - - // Case 1: the provided data fits entirely in the current partial block. - // Buffer it and return, leaving the block incomplete for later continuation. - if data.len() < (block_size - instance.block_bytes_used) { - instance.block[instance.block_bytes_used..instance.block_bytes_used + data.len()] - .copy_from_slice(data); - instance.block_bytes_used += data.len(); - - return; - } - - // Case 2: the incoming data exceeds the remaining space in the current block. - // First, fill the block + data until one full block. - let data_bytes_used = block_size - instance.block_bytes_used; - - instance.block[instance.block_bytes_used..block_size] - .copy_from_slice(&data[..data_bytes_used]); - - for chunk in instance.block[..block_size].chunks_exact(WORD_SIZE) { + for chunk in data.chunks_exact(WORD_SIZE) { let mut bytes = [0u8; WORD_SIZE]; bytes.copy_from_slice(chunk); let word = u32::from_be_bytes(bytes); @@ -148,47 +113,23 @@ impl embedded_cal::HashProvider for Stm32wba55 { self.hash.din().write_value(word); } - // Still on case 2, if data left doesn't fully fit on the block, - // continue feeding as many full SHA-256 blocks as possible. - let data_full_blocks = (data.len() - data_bytes_used) / SHA256_BLOCK_SIZE; - let data_words = data_full_blocks * SHA256_BLOCK_SIZE / WORD_SIZE; - - if data_full_blocks > 0 { - let bytes = &data[data_bytes_used..data_bytes_used + data_words * WORD_SIZE]; - - for chunk in bytes.chunks_exact(WORD_SIZE) { - let mut buf = [0u8; WORD_SIZE]; - buf.copy_from_slice(chunk); - let word = u32::from_be_bytes(buf); - - self.hash.din().write_value(word); - } - } - - // After consuming whole blocks, the remaining bytes will always fit within a single block. - // Buffer the remainder, update the internal state, and save the hardware context. - let data_bytes_used = data_bytes_used + data_full_blocks * SHA256_BLOCK_SIZE; - instance.block[..data.len() - data_bytes_used].copy_from_slice(&data[data_bytes_used..]); - instance.block_bytes_used = data.len() - data_bytes_used; - instance.first_block = false; - self.save_context(instance); } - fn finalize(&mut self, instance: Self::HashState) -> Self::HashResult { + fn finalize(&mut self, instance: Self::State, last_chunk: &[u8], target: &mut [u8]) { // Reset HASH state self.hash.cr().write(|w| w.set_init(true)); while self.hash.cr().read().init() {} // Configure SHA-256 - self.configure_and_reset_context(instance.algorithm); + self.configure_and_reset_context(HashAlgorithm::Sha256); // Restore the previously saved intermediate state for non-initial blocks. - if !instance.first_block { - self.restore_context(&instance); + if let Some(context) = &instance.context { + self.restore_context(context); } - for chunk in instance.block[..instance.block_bytes_used].chunks(WORD_SIZE) { + for chunk in last_chunk.chunks(WORD_SIZE) { let mut bytes = [0u8; WORD_SIZE]; bytes[..chunk.len()].copy_from_slice(chunk); let word = u32::from_be_bytes(bytes); @@ -196,7 +137,7 @@ impl embedded_cal::HashProvider for Stm32wba55 { self.hash.din().write_value(word); } - let number_bytes_last_chunk = instance.block_bytes_used % WORD_SIZE; + let number_bytes_last_chunk = last_chunk.len() % WORD_SIZE; self.hash .str() @@ -212,11 +153,11 @@ impl embedded_cal::HashProvider for Stm32wba55 { hash_result[i * WORD_SIZE..(i + 1) * WORD_SIZE].copy_from_slice(&w.to_be_bytes()); } - HashResult::Sha256(hash_result.into()) + target.copy_from_slice(&hash_result[..32]); } } -impl Stm32wba55 { +impl Stm32wba55Cal { /// As documented in the HASH suspend/resume procedure. /// Used to suspend processing of the current message. /// https://www.st.com/resource/en/reference_manual/rm0493-multiprotocol-wireless-bluetooth-lowenergy-armbased-32bit-mcu-stmicroelectronics.pdf @@ -224,23 +165,24 @@ impl Stm32wba55 { // BUSY must be 0 while self.hash.sr().read().busy() {} - // Save IMR + STR + CR registers - instance.imr = self.hash.imr().read(); - instance.str = self.hash.str().read(); - instance.cr = self.hash.cr().read(); + // Save IMR + STR registers + let imr = self.hash.imr().read(); + let str = self.hash.str().read(); // Save CSR registers (0..37 always; 38..53 only for HMAC) + let mut csr = [0u32; CSR_REGS_LEN]; for i in 0..CSR_REGS_LEN { - instance.csr[i] = self.hash.csr(i).read(); + csr[i] = self.hash.csr(i).read(); } + instance.context = Some(Context { csr, str, imr }); } /// As documented in the HASH suspend/resume procedure. /// Used to resume processing of an interrupted message. /// https://www.st.com/resource/en/reference_manual/rm0493-multiprotocol-wireless-bluetooth-lowenergy-armbased-32bit-mcu-stmicroelectronics.pdf - fn restore_context(&mut self, ctx: &HashState) { + fn restore_context(&mut self, ctx: &Context) { self.hash.cr().write(|w| w.set_init(false)); - // 1. Restore IMR, STR, CR (with INIT=0) + // Restore IMR, STR (with INIT=0) self.hash.imr().write_value(ctx.imr); self.hash.str().write_value(ctx.str); self.hash.cr().write(|w| { @@ -250,15 +192,16 @@ impl Stm32wba55 { w.set_datatype(0) }); - // 2. Set INIT to reload STR/CR context into hardware + // Set INIT to reload STR/CR context into hardware self.hash.cr().modify(|w| w.set_init(true)); while self.hash.cr().read().init() {} - // 3. Restore CSR registers AFTER INIT has reinitialized the core + // Restore CSR registers AFTER INIT has reinitialized the core for i in 0..CSR_REGS_LEN { self.hash.csr(i).write_value(ctx.csr[i]) } } + fn wait_busy(&mut self) { while self.hash.sr().read().busy() {} while !self.hash.sr().read().dcis() {} diff --git a/embedded-cal-stm32wba55/tests/integration.rs b/embedded-cal-stm32wba55/tests/integration.rs index d79e960..6bcf1b3 100644 --- a/embedded-cal-stm32wba55/tests/integration.rs +++ b/embedded-cal-stm32wba55/tests/integration.rs @@ -4,25 +4,33 @@ 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_stm32wba55::Stm32wba55Cal; +} + struct TestState { - cal: embedded_cal_stm32wba55::Stm32wba55, + cal: embedded_cal_software::Extender, } #[defmt_test::tests] mod tests { - use embedded_cal_stm32wba55::Stm32wba55; + use super::ImplementSha256Short; + use embedded_cal_stm32wba55::Stm32wba55Cal; #[init] fn init() -> super::TestState { - let cal = - embedded_cal_stm32wba55::Stm32wba55::new(stm32_metapac::HASH, &stm32_metapac::RCC); + let base = + embedded_cal_stm32wba55::Stm32wba55Cal::new(stm32_metapac::HASH, &stm32_metapac::RCC); + 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, + ::Algorithm, >(); testvectors::test_hash_algorithm_sha256(&mut state.cal); }