Compare commits

...

60 commits

Author SHA1 Message Date
3493bd2024
chore: add LICENSE 2025-08-21 15:20:18 +02:00
cfc851d3fe
chore: upload raw measurement files 2025-08-11 13:57:44 +02:00
21e77c65a9
chore: bump version to v0.2.0 2025-08-11 13:57:22 +02:00
63c45edba1
fix: small bugfixes and adding n_times c functions 2025-08-11 13:57:22 +02:00
55a1ff9445
chore: winflash
this hacky script lets me ignore the fact that im coding on a windows
machine better
2025-08-11 13:56:58 +02:00
f944cce39d
refactor: remove the software timing measures since they are not reliable 2025-08-06 09:43:04 +02:00
f162fe8734
docs: update readme 2025-07-31 16:53:01 +02:00
92cdf6af78
fix(algc): threads.h was included in sha2.c for some reason 2025-07-31 16:48:01 +02:00
cf3bc785ab
docs: set author in Cargo.toml 2025-07-31 16:46:36 +02:00
d4e405cf07
docs: rewrite readme 2025-07-31 16:35:10 +02:00
ba9ba5aa09
refactor: clean up scripts 2025-07-31 16:25:37 +02:00
416dd1660d
refactor: build.rs is more concise 2025-07-31 16:21:25 +02:00
368d790c63
chore(algc): dont show internals by default 2025-07-22 16:45:25 +02:00
078e55ef4a
feat(alg): crc32sum 2025-07-22 14:10:34 +02:00
32643ad085
refactor(algc): understand digest memory layout better 2025-07-22 13:51:19 +02:00
347e752e37
refactor(alg): smaller alg changes for testing and qol 2025-07-22 13:26:57 +02:00
1e827d6b8a
feat(alg): host benches for hash 2025-07-22 11:12:56 +02:00
e78dc4a628
fix(alg): sha2-256 sigma functions were wrong 2025-07-22 11:04:46 +02:00
bb81a7dd49
feat(alg): impl sha2 2025-07-18 15:05:56 +02:00
11677d8fe0
refactor(alg): remove sha generics 2025-07-18 12:08:49 +02:00
afff4c8aa4
feat(alg): sha2 with generics 2025-07-18 12:06:19 +02:00
1b582ba202
feat(alg): ffi for sha2 of algc 2025-07-18 10:32:11 +02:00
3331e89179
fix(alg): build.rs complications 2025-07-18 09:27:43 +02:00
00ced8e548
fix(alg): ffi crc adjustment 2025-07-18 09:21:03 +02:00
96eee72756
fix(algc): trace.h was not correctly imported 2025-07-18 09:20:52 +02:00
a0a277b80d
refactor(algc): use uint8_t* for data pointers 2025-07-18 09:16:08 +02:00
7ef66ead56
refactor: hide debug info 2025-07-17 18:16:55 +02:00
a3f77b4f45
fix: sha2 works 2025-07-17 18:00:53 +02:00
0fd29467a3
refactor: remove unused function 2025-07-17 17:28:17 +02:00
65690e7f43
feat: half working sha2 2025-07-17 17:14:11 +02:00
009ed1fb50
feat: delays in bench.rs 2025-07-16 12:15:31 +02:00
1c4ffa19a6
chore: adjust config.toml 2025-07-16 12:14:59 +02:00
6132a2ea61
feat: something resembling a benchmark runs 2025-07-15 12:57:30 +02:00
cb53f81662
refactor: move exception handler to new module 2025-07-14 15:52:11 +02:00
0f3a5f6b32
docs: why it didnt work without -march 2025-07-14 15:52:00 +02:00
6bf1b1beb7
refactor: make c project file smaller 2025-07-14 15:48:38 +02:00
7808fb55e3
fix: can't call C code from the stm32
chore: vscode debug stuff
2025-07-14 15:48:26 +02:00
aaab15e72d
chore: it works and flashing is possible, even on windows 2025-07-14 10:41:09 +02:00
f57aa91880
perf: optimize algorithm-c release builds -O3 2025-07-11 15:19:10 +02:00
0316298825
fix: flexible build.rs for algorithms (support both host and stm32) 2025-07-11 12:03:03 +02:00
727800ba2f
test: test algorithms-c 2025-07-11 11:16:51 +02:00
bad5730a8d
feat: ceedling cross compile 2025-07-11 10:39:53 +02:00
e8d26dd1a4
chore: better build shellscripts 2025-07-11 09:27:37 +02:00
28611efedb
feat: try to integrate algorithms into the stm32 main code to calc crc's 2025-07-10 17:54:07 +02:00
84a7fc294b
refactor: integrate algorithms-c with rust crate 2025-07-10 17:42:00 +02:00
d2476c2cd6
refactor: use ceedling as c build system
I love ceedling
2025-07-10 17:31:22 +02:00
4aef6894e5
refactor: organize c code better 2025-07-10 16:49:17 +02:00
d1120ba806
refactor!: this repo is supposed to runn all benches 2025-07-10 16:48:56 +02:00
7595ba6c52
chore: copy to svn script 2025-07-10 16:48:44 +02:00
ece5923ed8
feat(crc): add c ffi stuff 2025-07-10 14:06:59 +02:00
83ff767c5f
feat(crc): add iai bench 2025-07-09 17:29:40 +02:00
c77927711d
feat(crc): criterion benchmark for crc32 2025-07-09 17:22:19 +02:00
e0b79b5a22
feat(crc): add checksum associated function to Crc trait for convenience 2025-07-09 17:15:50 +02:00
84698796d1
refactor: remove unused dependencies from crc crate 2025-07-09 17:10:40 +02:00
ca49202052
feat: CRC-32 implemented 2025-07-09 17:10:08 +02:00
8afd71ebe3
docs: truncate readme, since this is a hard fork 2025-07-09 15:12:32 +02:00
e2bc777410
chore: build and test shenanigans 2025-07-09 15:12:10 +02:00
b3ca9eeabf
feat: create crc crate 2025-07-09 15:02:17 +02:00
e83167634a
fix!: remove unused dependencies and set optional = false 2025-07-09 14:10:31 +02:00
a9a1fc40db
refactor!: logging is no longer a feature 2025-07-09 14:05:57 +02:00
61 changed files with 2867 additions and 165 deletions

View file

@ -1,11 +1,16 @@
[build]
target = "thumbv6m-none-eabi"
[target.thumbv6m-none-eabi]
runner = 'probe-rs run --chip STM32L053R8'
# [build]
# target = "thumbv6m-none-eabi"
[alias]
arun = "run --target thumbv6m-none-eabi"
abuild = "build --target thumbv6m-none-eabi"
atest = "test --target x86_64-unknown-linux-gnu"
abench = "bench --target x86_64-unknown-linux-gnu"
acheck = "check --target thumbv6m-none-eabi"
aclippy = "clippy --target thumbv6m-none-eabi"
cflash = "flash --chip STM32L053R8"
[env]

3
.gitignore vendored
View file

@ -1 +1,4 @@
/target
/.git
scripts/copy_to_svn.sh
scripts/copy_to_win.sh

20
.vscode/launch.json vendored Executable file
View file

@ -0,0 +1,20 @@
{
"version": "0.2.0",
"configurations": [
{
"preLaunchTask": "${defaultBuildTask}",
"type": "probe-rs-debug",
"request": "launch",
"name": "probe_rs Run and Debug",
"flashingConfig": {
"flashingEnabled": true,
},
"chip": "STM32L053R8",
"coreConfigs": [
{
"programBinary": "${workspaceFolder}/target/thumbv6m-none-eabi/debug/nucleo-l053r8-benches",
}
]
}
]
}

25
.vscode/tasks.json vendored Executable file
View file

@ -0,0 +1,25 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "cargo run",
"type": "shell",
"command": "cargo arun",
"problemMatcher": [
"$rustc"
],
},
{
"label": "cargo build",
"type": "shell",
"command": "cargo build --target thumbv6m-none-eabi",
"problemMatcher": [
"$rustc"
],
"group": {
"kind": "build",
"isDefault": true
}
}
]
}

641
Cargo.lock generated
View file

@ -2,6 +2,25 @@
# It is not intended for manual editing.
version = 4
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]]
name = "algorithms"
version = "0.2.0"
dependencies = [
"assert_hex",
"criterion",
"iai",
"pretty_assertions",
]
[[package]]
name = "as-slice"
version = "0.2.1"
@ -12,10 +31,27 @@ dependencies = [
]
[[package]]
name = "autocfg"
version = "1.4.0"
name = "assert_hex"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
checksum = "f7010f1430f0fc8ca80bdb5e5d074db68776a2e268ec6cf80b53712d3ea4bca7"
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "autocfg"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "bare-metal"
@ -23,7 +59,7 @@ version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3"
dependencies = [
"rustc_version 0.2.3",
"rustc_version",
]
[[package]]
@ -45,10 +81,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "byteorder"
version = "1.5.0"
name = "bumpalo"
version = "3.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
[[package]]
name = "cast"
@ -56,6 +92,12 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]]
name = "cfg-if"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
[[package]]
name = "chrono"
version = "0.4.41"
@ -66,16 +108,14 @@ dependencies = [
]
[[package]]
name = "compile-time"
version = "0.2.0"
source = "git+https://github.com/cscherrNT/compile-time-rs#085aecbf1d9fd593b112fcf1b218ec8a6841d1df"
name = "clap"
version = "2.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
dependencies = [
"once_cell",
"proc-macro2",
"quote",
"rustc_version 0.4.1",
"semver 1.0.26",
"time",
"bitflags",
"textwrap",
"unicode-width",
]
[[package]]
@ -111,12 +151,94 @@ dependencies = [
"syn",
]
[[package]]
name = "criterion"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f"
dependencies = [
"atty",
"cast",
"clap",
"criterion-plot",
"csv",
"itertools",
"lazy_static",
"num-traits",
"oorandom",
"plotters",
"rayon",
"regex",
"serde",
"serde_cbor",
"serde_derive",
"serde_json",
"tinytemplate",
"walkdir",
]
[[package]]
name = "criterion-plot"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876"
dependencies = [
"cast",
"itertools",
]
[[package]]
name = "critical-section"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
[[package]]
name = "crossbeam-deque"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
dependencies = [
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
[[package]]
name = "csv"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf"
dependencies = [
"csv-core",
"itoa",
"ryu",
"serde",
]
[[package]]
name = "csv-core"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d02f3b0da4c6504f86e9cd789d8dbafab48c2321be74e9987593de5a894d93d"
dependencies = [
"memchr",
]
[[package]]
name = "defmt"
version = "0.3.100"
@ -169,13 +291,16 @@ dependencies = [
]
[[package]]
name = "deranged"
version = "0.4.0"
name = "diff"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e"
dependencies = [
"powerfmt",
]
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
[[package]]
name = "either"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
[[package]]
name = "embedded-hal"
@ -197,31 +322,33 @@ dependencies = [
]
[[package]]
name = "hash32"
version = "0.3.1"
name = "half"
version = "1.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606"
checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403"
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"byteorder",
"libc",
]
[[package]]
name = "hd44780-driver"
version = "0.4.0"
name = "iai"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aab2b13fdeaed7dde9133a57c28b2cbde4a8fc8c3196b5631428aad114857d3a"
dependencies = [
"embedded-hal",
]
checksum = "71a816c97c42258aa5834d07590b718b4c9a598944cd39a52dc25b351185d678"
[[package]]
name = "heapless"
version = "0.8.0"
name = "itertools"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad"
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
dependencies = [
"hash32",
"stable_deref_trait",
"either",
]
[[package]]
@ -231,10 +358,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]]
name = "libc"
version = "0.2.172"
name = "js-sys"
version = "0.3.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
dependencies = [
"once_cell",
"wasm-bindgen",
]
[[package]]
name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.174"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
[[package]]
name = "log"
version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
[[package]]
name = "memchr"
version = "2.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
[[package]]
name = "nb"
@ -252,18 +407,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d"
[[package]]
name = "nucleo-l053r8-crcbench"
version = "0.1.0"
name = "nucleo-l053r8-benches"
version = "0.2.0"
dependencies = [
"chrono",
"compile-time",
"algorithms",
"cortex-m",
"cortex-m-rt",
"defmt 1.0.1",
"defmt-rtt",
"hd44780-driver",
"heapless",
"panic-halt",
"panic-probe",
"stm32l0xx-hal",
]
@ -290,12 +441,6 @@ dependencies = [
"num-traits",
]
[[package]]
name = "num-conv"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
[[package]]
name = "num-integer"
version = "0.1.46"
@ -336,15 +481,6 @@ dependencies = [
"autocfg",
]
[[package]]
name = "num_threads"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9"
dependencies = [
"libc",
]
[[package]]
name = "once_cell"
version = "1.21.3"
@ -352,10 +488,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
name = "panic-halt"
version = "1.0.0"
name = "oorandom"
version = "11.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a513e167849a384b7f9b746e517604398518590a9142f4846a32e3c2a4de7b11"
checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e"
[[package]]
name = "panic-probe"
@ -368,10 +504,42 @@ dependencies = [
]
[[package]]
name = "powerfmt"
version = "0.2.0"
name = "plotters"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747"
dependencies = [
"num-traits",
"plotters-backend",
"plotters-svg",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "plotters-backend"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a"
[[package]]
name = "plotters-svg"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670"
dependencies = [
"plotters-backend",
]
[[package]]
name = "pretty_assertions"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d"
dependencies = [
"diff",
"yansi",
]
[[package]]
name = "proc-macro-error-attr2"
@ -413,6 +581,55 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "rayon"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
dependencies = [
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
dependencies = [
"crossbeam-deque",
"crossbeam-utils",
]
[[package]]
name = "regex"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "rtcc"
version = "0.3.2"
@ -428,16 +645,28 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
dependencies = [
"semver 0.9.0",
"semver",
]
[[package]]
name = "rustc_version"
version = "0.4.1"
name = "rustversion"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
[[package]]
name = "ryu"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"semver 1.0.26",
"winapi-util",
]
[[package]]
@ -449,12 +678,6 @@ dependencies = [
"semver-parser",
]
[[package]]
name = "semver"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0"
[[package]]
name = "semver-parser"
version = "0.7.0"
@ -470,6 +693,16 @@ dependencies = [
"serde_derive",
]
[[package]]
name = "serde_cbor"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5"
dependencies = [
"half",
"serde",
]
[[package]]
name = "serde_derive"
version = "1.0.219"
@ -481,6 +714,18 @@ dependencies = [
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.140"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
dependencies = [
"itoa",
"memchr",
"ryu",
"serde",
]
[[package]]
name = "stable_deref_trait"
version = "1.2.0"
@ -519,15 +764,24 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.100"
version = "2.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "textwrap"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
dependencies = [
"unicode-width",
]
[[package]]
name = "thiserror"
version = "2.0.12"
@ -549,36 +803,13 @@ dependencies = [
]
[[package]]
name = "time"
version = "0.3.41"
name = "tinytemplate"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40"
checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
dependencies = [
"deranged",
"itoa",
"libc",
"num-conv",
"num_threads",
"powerfmt",
"serde",
"time-core",
"time-macros",
]
[[package]]
name = "time-core"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c"
[[package]]
name = "time-macros"
version = "0.2.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49"
dependencies = [
"num-conv",
"time-core",
"serde_json",
]
[[package]]
@ -587,6 +818,12 @@ version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "unicode-width"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
[[package]]
name = "vcell"
version = "0.1.3"
@ -607,3 +844,191 @@ checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc"
dependencies = [
"vcell",
]
[[package]]
name = "walkdir"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [
"same-file",
"winapi-util",
]
[[package]]
name = "wasm-bindgen"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
dependencies = [
"cfg-if",
"once_cell",
"rustversion",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
dependencies = [
"bumpalo",
"log",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
dependencies = [
"unicode-ident",
]
[[package]]
name = "web-sys"
version = "0.3.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
"windows-sys",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "yansi"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"

View file

@ -1,7 +1,9 @@
[package]
name = "nucleo-l053r8-crcbench"
version = "0.1.0"
name = "nucleo-l053r8-benches"
version = "0.2.0"
edition = "2024"
authors = ["Christoph J. Scherr <software@cscherr.de>"]
license = "MIT"
[dependencies]
@ -11,18 +13,17 @@ hal = { package = "stm32l0xx-hal", version = "0.10.0", features = [
] }
cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] }
cortex-m-rt = "0.7.5"
panic-halt = "1.0.0"
hd44780-driver = "0.4.0"
heapless = "0.8.0"
defmt = { version = "1.0.1", optional = true }
defmt-rtt = { version = "1.0.0", optional = true }
panic-probe = { version = "0.3", features = ["print-defmt"], optional = true }
compile-time = { git = "https://github.com/cscherrNT/compile-time-rs" }
chrono = { version = "0.4.41", default-features = false }
defmt = { version = "1.0.1" }
defmt-rtt = { version = "1.0.0" }
panic-probe = { version = "0.3", features = ["print-defmt"] }
algorithms = { path = "./crates/algorithms" }
[features]
default = ["buildscript"]
buildscript = [] # runs build.rs
[profile.release]
debug = "full" # those are not on the board
[features]
default = ["logging"]
logging = ["dep:defmt", "dep:defmt-rtt", "dep:panic-probe"]
[workspace]
members = ["", "crates/algorithms"]

22
LICENSE Normal file
View file

@ -0,0 +1,22 @@
MIT License
Copyright (c) 2025 Christoph Johannes Scherr
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -1,16 +1,58 @@
# Example Codes for the STM32 NUCLEO-L053R8
# NUCLEO L053R8 Benches
This repository contains many example programs that are written to run on the
NUCLEO-L053R8 Board.
This repository contains code to measure the performance of embedded C and
Rust code for an STM32 Microcontroller, specifically the `STM32L053R` on a
`NUCLEO-L053R` evaluation board.
## Running
It implements a variety of algorithms in both C and Rust
(`crate/algorithms`). These Algorithm programs are then executed by the
executable program written in Rust. C code is called using Rust's FFI with
manually implemented bindings. To measure the actual runtime of the algorithms,
you need to attach an oscilluscope to the configured port of the board while
the prgrams are running.
Some programs require additional libraries for logging/formatting that would
make the more basic ones not compile (or rather link) correctly. For those,
enable the `logging` feature.
## Building
See [build.sh](./scripts/build.sh).
## Flashing
See [flash.sh](./scripts/flash.sh).
## Host-Benchmarks
The algorithms have benchmarks that can run on regular consumer laptops, so that
you can see the implementation difference on a bigger architecture like
`x86_64`.
See [bench_algorithms.sh](./scripts/bench_algorithms.sh).
### Dependencies
This program requires Rust to be installed. I made it with `Rust 1.88.0`, but
the theoretical MSRV is `Rust 1.85.1` (according to `cargo-msrv`).
In addition to some crates from crates.io, this project requires the following
to be installed to compile and link to the algorithms-c implementations.
```bash
cargo run --example=blinky
cargo run --example=rtc-log --features=logging
# etc
```
# on debian bookworm
# compiler for your architecture if you want to run the unit tests
apt install gcc
# compiler for the target architecture
apt install binutils-arm-none-eabi gcc-arm-none-eabi
# ceedling is the used build system for algorithms-c, and needs to be installed with gem, the ruby package manager
apt install ruby
gem install ceedling
```
To actually flash the program onto an STM32, you also need
[probe-rs](https://probe.rs/docs/getting-started/installation/). I used
`probe-rs 0.29.1`.
## Acknowledgements
For implementing the SHA-2-256 Algorithm, [this](https://sha256algorithm.com/)
website was very helpful.
The algorithms themselves are mostly reference implementation of various RFCs.

View file

@ -1,8 +1,8 @@
fn main() {
println!("cargo::rerun-if-changed=Cargo.toml");
println!("cargo::rustc-link-arg=-Tlink.x");
#[cfg(feature = "logging")]
#[cfg(feature = "buildscript")]
{
println!("cargo::rerun-if-changed=Cargo.toml");
println!("cargo::rustc-link-arg=-Tlink.x");
println!("cargo::rustc-link-arg=-Tdefmt.x");
}
}

1
crates/algorithms/.gitignore vendored Executable file
View file

@ -0,0 +1 @@
/target

36
crates/algorithms/Cargo.toml Executable file
View file

@ -0,0 +1,36 @@
[package]
name = "algorithms"
version = "0.2.0"
edition = "2024"
license = "MIT"
[dependencies]
[dev-dependencies]
assert_hex = "0.4.1"
criterion = "0.3"
iai = "0.1.1"
pretty_assertions = "1.4.1"
[[bench]]
name = "crc32bench"
harness = false
[[bench]]
name = "crc32bench_iai"
harness = false
[features]
default = []
std = []
show_internals = ["std"]
[[bin]]
path = "src/bin/crc32sum.rs"
name = "crc32sum"
required-features = ["std"]
[[bin]]
path = "src/bin/sha256sum.rs"
name = "algsha256sum"
required-features = ["std"]

View file

@ -0,0 +1,5 @@
SemanticTokens:
DisabledKinds: [InactiveCode]
CompileFlags: # Tweak the parse settings, example directory given to show format
Add:
- "-Wall"

1
crates/algorithms/algorithms-c/.gitignore vendored Executable file
View file

@ -0,0 +1 @@
build*

View file

@ -0,0 +1,27 @@
# Algorithms-c
This subproject contains all C Code for the benchmarking. It is built with
[ceedling](https://www.throwtheswitch.org/ceedling), a more modern build tool
for C projects that also integrates well with the Unity framework.
## Compiler
To compile for STM32, you need to crosscompile
```
# apt install binutils-arm-none-eabi gcc-arm-none-eabi
```
Then, use your tool with an `arm-none-eabi-` prefix: `arm-none-eabi-gcc`. This
project has been configured to use the compiler specified in `$CC` to compile modules and `$AR` to
"link" the object files (this should be `ar` for a static library like this)
. You can and should also give extra compiler flags in `$CC_FLAGS`.
```bash
# cross-compile for STM32
CC=arm-none-eabi-gcc AR=arm-none-eabi-ar CC_FLAGS="-march=armv6-m" ceedling release
# compile for this computer
CC=gcc AR=ar ceedling release
```
It is critically important to define the `-march=ARCH` option when using `arm-none-eabi-gcc`, since the compiler will otherwise just assume a target architecture. In this case, it needs to be set to `armv6-m`, since the MPU is a `cortex-M0+`. This MPU does only support the thumb instruction-set, not the ARM32 set.

View file

@ -0,0 +1,12 @@
-I
./build/vendor/unity/src/
-I
./build/vendor/cmock/src/
-I
./src/crc/
-I
./src/hash/
-I
./src/
-I
./test/support/

View file

@ -0,0 +1,112 @@
:project:
:which_ceedling: gem
:ceedling_version: 1.0.1
:use_mocks: FALSE
:use_backtrace: :gdb # options are :none, :simple, or :gdb
:use_decorators: :auto # decorate Ceedling's output text. options are :auto, :all, or :none
:build_root: build
:test_file_prefix: test_
:default_tasks:
- release
- test:all
:test_threads: 8
:compile_threads: 8
:release_build: TRUE
:version: 0.2.0
:test_build:
:use_assembly: FALSE
:release_build:
:output: libalgorithms.a
:use_assembly: FALSE
:artifacts: []
:plugins:
:load_paths: []
:enabled:
#- beep # beeps when finished, so you don't waste time waiting for ceedling
- module_generator # handy for quickly creating source, header, and test templates
#- gcov # test coverage using gcov. Requires gcc, gcov, and a coverage analyzer like gcovr
#- bullseye # test coverage using bullseye. Requires bullseye for your platform
#- command_hooks # write custom actions to be called at different points during the build process
#- compile_commands_json_db # generate a compile_commands.json file
#- dependencies # automatically fetch 3rd party libraries, etc.
#- subprojects # managing builds and test for static libraries
#- fake_function_framework # use FFF instead of CMock
# Report options (You'll want to choose one stdout option, but may choose multiple stored options if desired)
- report_build_warnings_log
#- report_tests_gtestlike_stdout
#- report_tests_ide_stdout
#- report_tests_log_factory
- report_tests_pretty_stdout
#- report_tests_raw_output_log
#- report_tests_teamcity_stdout
# Specify which reports you'd like from the log factory
:report_tests_log_factory:
:reports:
- json
- junit
- cppunit
- html
# override the default extensions for your system and toolchain
:extension:
#:header: .h
#:source: .c
#:assembly: .s
#:dependencies: .d
#:object: .o
:executable: .out
#:testpass: .pass
#:testfail: .fail
#:subprojects: .a
:paths:
:test:
- +:test/**
- -:test/support
:source:
- src/**
:include:
- src/** # In simple projects, this entry often duplicates :source
:support:
- test/support
:libraries: []
:defines:
:test:
- TEST # Simple list option to add symbol 'TEST' to compilation of all files in all test executables
:release: []
# Enable to inject name of a test as a unique compilation symbol into its respective executable build.
:use_test_definition: FALSE
:flags:
:release:
:compile:
- -Wall # all warnings on
- -O3 # optimizations
- -g # debug info
# NOTE: This is essential! It tells the compiler which target architecture to compile for!!!
# Currently, this is set by build.rs with the CC_FLAGS env var
# - -march=armv6-m
:unity:
:defines:
- UNITY_EXCLUDE_FLOAT
:libraries:
:placement: :end
:flag: "-l${1}"
:path_flag: "-L ${1}"
:system: []
:test: []
:release: []
:tools:
:release_compiler:
:executable: "#{ENV['CC']}"
:arguments:
- "-c"
- "${1}"
- "-o"
- "${2}"
- "#{ENV['CC_FLAGS']}"
:optional: FALSE
:release_linker:
:executable: "#{ENV['AR']}"
:arguments:
- "-rcs"
- "${2}"
- "${1}"
:optional: FALSE

View file

@ -0,0 +1,3 @@
#include "algorithms.h"
int algorithms_c_is_loaded() { return 1; }

View file

@ -0,0 +1,12 @@
#ifndef ALGORITHMS_H
#define ALGORITHMS_H
#include "crc/crc.h"
#include "hash/hash.h"
#include "stdbool.h"
extern int algorithms_c_is_loaded();
#endif // ALGORITHMS_H

View file

@ -0,0 +1,2 @@
#include "crc.h"

View file

@ -0,0 +1,6 @@
#ifndef CRC_H
#define CRC_H
#include "crc32.h"
#endif // CRC_H

View file

@ -0,0 +1,80 @@
#include "crc32.h"
#include <stdint.h>
const uint32_t CRC32_INIT = 0xffffffff;
const uint32_t CRC32_TABLE[256] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
};
Crc32 crc32_new() {
Crc32 crc32;
crc32.buf = 0;
return crc32;
}
void crc32_process(const uint8_t *data, size_t len, Crc32 *crc32) {
#define chksum crc32->buf
chksum = CRC32_INIT;
for (uint32_t i = 0; i < len; i++) {
chksum ^= data[i];
chksum = (chksum >> 8) ^ CRC32_TABLE[(chksum & 0xff)];
}
chksum ^= CRC32_INIT;
return;
}
ChecksumCrc32 crc32_checksum(const uint8_t *data, uint32_t len) {
Crc32 crc32 = crc32_new();
crc32_process(data, len, &crc32);
return crc32.buf;
}
ChecksumCrc32 crc32_checksum_n_times(uint32_t n, const uint8_t *data,
uint32_t len) {
ChecksumCrc32 buf;
for (uint32_t i = 0; i < n; i++) {
buf = crc32_checksum(data, len);
}
return buf;
}

View file

@ -0,0 +1,25 @@
#ifndef CRC32_H
#define CRC32_H
#include <stddef.h>
#include <stdint.h>
// it needs to be declared but not implemented, otherwise, multiple definitions
// will occur
extern const uint32_t CRC32_INIT;
extern const uint32_t CRC32_TABLE[256];
typedef uint32_t ChecksumCrc32;
typedef struct Crc32 {
ChecksumCrc32 buf;
} Crc32;
Crc32 crc32_new();
void crc32_process(const uint8_t *data, size_t len, Crc32 *crc32);
ChecksumCrc32 crc32_checksum(const uint8_t *data, uint32_t len);
ChecksumCrc32 crc32_checksum_n_times(uint32_t n, const uint8_t *data,
uint32_t len);
#endif // CRC32_H

View file

@ -0,0 +1,10 @@
#include "hash.h"
#include <stdio.h>
void print_digest(const SHA2Digest digest) {
for (size_t i = 0; i < SHA2_256_HashParts; i++) {
fprintf(stderr, "%08x", digest[i]);
}
fprintf(stderr, "\n");
}

View file

@ -0,0 +1,8 @@
#ifndef HASH_H
#define HASH_H
#include "sha2.h"
extern void print_digest(const SHA2Digest);
#endif // HASH_H

View file

@ -0,0 +1,421 @@
#include "sha2.h"
#include "../trace.h"
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#ifdef TEST
// if you want to get the internals of sha2 printed, uncomment the line below
// #define SHOW_INTERNALS
#endif // TEST
#ifdef SHOW_INTERNALS
#define sha2_256_show_internal_state(context) \
TRACE("Internal State:\n\tcorrupted: %d\n\tintermediate_hash: ", \
context->corrupted); \
dump_hash(context); \
TRACE("\tmessage_block_index: %d\n\tmessage_block: ", \
context->message_block_index); \
dump_data((uint8_t *)context->message_block, SHA2_256_BlockSize); \
TRACE("\tcorrupted: %d\n\tcomputed: %d\n", context->corrupted, \
context->computed);
#else
#define sha2_256_show_internal_state(context)
#endif // SHOW_INTERNALS
#define err_handler(RES) \
if (RES) { \
return RES; \
}
static uint32_t addTemp = 0;
#define sha2_256_add_length(context, length) \
(addTemp = (context)->length_low, \
(context)->corrupted = (((context)->length_low += (length)) < addTemp) && \
(++(context)->length_high == 0) \
? shaInputTooLong \
: (context)->corrupted)
#define dump_hash(context) \
for (int o = 0; o < SHA2_256_HashParts; o++) { \
TRACE("%08x", context->intermediate_hash[o]); \
} \
TRACELN("")
/* Define the SHA shift, rotate left, and rotate right macros */
#define SHA256_SHR(bits, word) ((word) >> (bits))
#define SHA256_ROTL(bits, word) (((word) << (bits)) | ((word) >> (32 - (bits))))
#define SHA256_ROTR(bits, word) (((word) >> (bits)) | ((word) << (32 - (bits))))
/* Define the SHA SIGMA and sigma macros, yes these have the same name and are
* different */
#define SHA256_SIGMA0(word) \
(SHA256_ROTR(2, word) ^ SHA256_ROTR(13, word) ^ SHA256_ROTR(22, word))
#define SHA256_SIGMA1(word) \
(SHA256_ROTR(6, word) ^ SHA256_ROTR(11, word) ^ SHA256_ROTR(25, word))
#define SHA256_sigma0(word) \
(SHA256_ROTR(7, word) ^ SHA256_ROTR(18, word) ^ SHA256_SHR(3, word))
#define SHA256_sigma1(word) \
(SHA256_ROTR(17, word) ^ SHA256_ROTR(19, word) ^ SHA256_SHR(10, word))
#define SHA_Ch(x, y, z) (((x) & ((y) ^ (z))) ^ (z))
#define SHA_Maj(x, y, z) (((x) & ((y) | (z))) | ((y) & (z)))
static const uint32_t H[SHA2_256_HashParts] = {
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
static const uint32_t K[SHA2_256_BlockSize] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2};
/*
* Description:
* This helper function will process the next 512 bits of the
* message stored in the message_block array.
*
* Parameters:
* context: [in/out]
* The SHA context to update.
*
* Returns:
* Nothing.
*
* Comments:
* Many of the variable names in this code, especially the
* single character names, were used because those were the
* names used in the Secure Hash Standard.
*/
static void sha2_256_process_message_block(SHA2Context *context) {
#define dump_letter(X) TRACE("%s: %08x ", STR(X), X)
#define dump_alphabet \
dump_letter(A) dump_letter(B) dump_letter(C) dump_letter(D) dump_letter(E) \
dump_letter(F) dump_letter(G) dump_letter(H) TRACELN("")
#define dump_w \
TRACELN("Dumping W:"); \
for (int o = 0; o < SHA2_256_BlockSize; o++) { \
TRACE("\tW[%d]: %032b\n", o, W[o]) \
}
#ifdef SHOW_INTERNALS
TRACELN("before process message block");
sha2_256_show_internal_state(context);
#endif // SHOW_INTERNALS
uint8_t t, t4; /* Loop counter */
uint32_t temp1, temp2; /* Temporary word value */
uint32_t W[SHA2_256_BlockSize]; /* Word sequence */
uint32_t A, B, C, D, E, F, G, H; /* Word buffers */
/*
* Initialize the first 16 words in the array W
*/
for (t = t4 = 0; t < 16; t++, t4 += 4) {
W[t] = (((uint32_t)context->message_block[t4]) << 24) |
(((uint32_t)context->message_block[t4 + 1]) << 16) |
(((uint32_t)context->message_block[t4 + 2]) << 8) |
(((uint32_t)context->message_block[t4 + 3]));
}
#ifdef SHOW_INTERNALS
dump_w;
#endif // SHOW_INTERNALS
for (t = 16; t < SHA2_256_BlockSize; t++) {
W[t] = SHA256_sigma1(W[t - 2]) + W[t - 7] + SHA256_sigma0(W[t - 15]) +
W[t - 16];
}
#ifdef SHOW_INTERNALS
dump_w;
#endif // SHOW_INTERNALS
A = context->intermediate_hash[0];
B = context->intermediate_hash[1];
C = context->intermediate_hash[2];
D = context->intermediate_hash[3];
E = context->intermediate_hash[4];
F = context->intermediate_hash[5];
G = context->intermediate_hash[6];
H = context->intermediate_hash[7];
for (t = 0; t < SHA2_256_BlockSize; t++) {
#ifdef SHOW_INTERNALS
TRACE("Iter: %d\t", t);
dump_alphabet;
#endif // SHOW_INTERNALS
temp1 = H + SHA256_SIGMA1(E) + SHA_Ch(E, F, G) + K[t] + W[t];
temp2 = SHA256_SIGMA0(A) + SHA_Maj(A, B, C);
H = G;
G = F;
F = E;
E = D + temp1;
D = C;
C = B;
B = A;
A = temp1 + temp2;
}
#ifdef SHOW_INTERNALS
TRACE("DONE:\t")
dump_alphabet;
TRACE("Intermediate hash before we add the working variables:\n");
for (int o = 0; o < SHA2_256_HashParts; o++) {
TRACE("\t%d:\t%032b\n", o, context->intermediate_hash[o]);
}
#endif // SHOW_INTERNALS
context->intermediate_hash[0] += A;
context->intermediate_hash[1] += B;
context->intermediate_hash[2] += C;
context->intermediate_hash[3] += D;
context->intermediate_hash[4] += E;
context->intermediate_hash[5] += F;
context->intermediate_hash[6] += G;
context->intermediate_hash[7] += H;
context->message_block_index = 0;
#ifdef SHOW_INTERNALS
TRACE("Hash data if we finish now: ");
dump_hash(context);
TRACELN("\nafter process message block");
sha2_256_show_internal_state(context);
#endif // SHOW_INTERNALS
}
/*
* Description:
* According to the standard, the message must be padded to the next
* even multiple of 512 bits. The first padding bit must be a '1'.
* The last 64 bits represent the length of the original message.
* All bits in between should be 0. This helper function will pad
* the message according to those rules by filling the
* Message_Block array accordingly. When it returns, it can be
* assumed that the message digest has been computed.
*
* Parameters:
* context: [in/out]
* The context to pad.
* Pad_Byte: [in]
* The last byte to add to the message block before the 0-padding
* and length. This will contain the last bits of the message
* followed by another single bit. If the message was an
* exact multiple of 8-bits long, Pad_Byte will be 0x80.
*
* Returns:
* Nothing.
*/
static void sha2_256_pad_message(SHA2Context *context, uint8_t pad_byte) {
/*
* Check to see if the current message block is too small to hold
* the initial padding bits and length. If so, we will pad the
* block, process it, and then continue padding into a second
* block.
*/
if (context->message_block_index >= (SHA2_256_BlockSize - 8)) {
context->message_block[context->message_block_index++] = pad_byte;
while (context->message_block_index < SHA2_256_BlockSize)
context->message_block[context->message_block_index++] = 0;
sha2_256_process_message_block(context);
} else
context->message_block[context->message_block_index++] = pad_byte;
while (context->message_block_index < (SHA2_256_BlockSize - 8))
context->message_block[context->message_block_index++] = 0;
/*
* store the message length as the last 8 octets
*/
context->message_block[56] = (uint8_t)(context->length_high >> 24);
context->message_block[57] = (uint8_t)(context->length_high >> 16);
context->message_block[58] = (uint8_t)(context->length_high >> 8);
context->message_block[59] = (uint8_t)(context->length_high);
context->message_block[60] = (uint8_t)(context->length_low >> 24);
context->message_block[61] = (uint8_t)(context->length_low >> 16);
context->message_block[62] = (uint8_t)(context->length_low >> 8);
context->message_block[63] = (uint8_t)(context->length_low);
sha2_256_process_message_block(context);
sha2_256_show_internal_state(context);
}
static void sha2_256_finalize(SHA2Context *context, uint8_t pad_byte) {
sha2_256_pad_message(context, pad_byte);
}
/*
* sha2_reset
*
* Description:
* This function will initialize the SHA2Context in preparation
* for computing a new SHA2 message digest.
*
* Parameters:
* context: [in/out]
* The context to reset.
*
* Returns:
* SHA2 Error Code.
*
*/
SHA2Result sha2_256_reset(SHA2Context *context) {
size_t i;
if (!context) {
return shaNull;
}
context->length_low = 0;
context->length_high = 0;
context->message_block_index = 0;
for (i = 0; i < SHA2_256_BlockSize; i++) {
context->message_block[i] = 0;
}
for (i = 0; i < SHA2_256_HashParts; i++) {
context->intermediate_hash[i] = H[i];
}
context->corrupted = 0;
context->computed = 0;
return shaSuccess;
}
/*
* sha2_input
*
* Description:
* This function accepts an array of bytes as the next portion
* of the message.
*
* Parameters:
* context: [in/out]
* The SHA context to update
* data: [in]
* An array of characters representing the next portion of
* the message.
* length: [in]
* The length of the message in message_array
*
* Returns:
* sha Error Code.
*
*/
SHA2Result sha2_256_input(SHA2Context *context, const uint8_t data[],
size_t len) {
sha2_256_show_internal_state(context);
if (!context) {
TRACELN("Context was NULL");
return shaNull;
}
if (!len)
return shaSuccess;
if (!data) {
TRACELN("Data was NULL");
return shaNull;
}
if (context->computed) {
TRACELN("context was already computed");
context->corrupted = shaStateError;
}
if (context->corrupted) {
TRACELN("context is corrupted");
return context->corrupted;
}
while (len--) {
context->message_block[context->message_block_index++] = *data;
if ((sha2_256_add_length(context, 8) == shaSuccess) &&
(context->message_block_index == SHA2_256_BlockSize)) {
TRACELN("processing the message block after inputting")
sha2_256_process_message_block(context);
}
data++;
}
return context->corrupted;
}
/*
* sha2_result
*
* Description:
* This function will return the 256-bit message digest
* into the digest array provided by the caller.
* NOTE:
* The first octet of hash is stored in the element with index 0,
* the last octet of hash in the element with index 31.
*
* Parameters:
* context: [in/out]
* The context to use to calculate the SHA hash.
* digest: [out]
* Where the digest is returned.
*
* Returns:
* sha Error Code.
*
*/
SHA2Result sha2_256_result(SHA2Context *context, SHA2Digest digest) {
size_t i;
if (!context)
return shaNull;
if (!digest)
return shaNull;
if (context->corrupted)
return context->corrupted;
if (!context->computed) {
sha2_256_finalize(context, 0x80);
}
for (i = 0; i < SHA2_256_HashParts; i++)
digest[i] = context->intermediate_hash[i];
return shaSuccess;
}
SHA2Result sha2_256_oneshot(const uint8_t data[], const size_t len,
SHA2Digest digest) {
SHA2Context context;
SHA2Result res;
res = sha2_256_reset(&context);
err_handler(res);
sha2_256_show_internal_state((&context));
res = sha2_256_input(&context, data, len);
err_handler(res);
sha2_256_show_internal_state((&context));
res = sha2_256_result(&context, digest);
err_handler(res);
sha2_256_show_internal_state((&context));
return res;
}
void sha2_256_oneshot_n_times(uint32_t n, const uint8_t data[],
const size_t len) {
SHA2Digest digest;
for (uint32_t i = 0; i < n; i++) {
sha2_256_oneshot(data, len, digest);
}
}

View file

@ -0,0 +1,55 @@
/*
* This implementation of SHA2 is somewhat similar to that in RFC6234, thanks
* for publishing that!
*/
#ifndef SHA2_H
#define SHA2_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#define HASH(b0, b1, b2, b3, b4, b5, b6, b7) {b0, b1, b2, b3, b4, b5, b6, b7}
#define SHA2_256_HashBits 256
#define SHA2_256_HashBytes SHA2_256_HashBits / 8
#define SHA2_256_HashParts SHA2_256_HashBytes / 4
#define SHA2_256_BlockSize 2 * SHA2_256_HashBytes
typedef enum {
shaSuccess = 0,
shaNull, /* Null pointer parameter */
shaInputTooLong, /* input data too long */
shaStateError, /* called Input after Result */
shaBadArg /* Bad argument was given to a function */
} SHA2Result;
typedef uint32_t SHA2Digest[SHA2_256_HashParts];
/*
* This structure will hold context information for the SHA-1
* hashing operation
*/
typedef struct SHA2Context {
SHA2Digest intermediate_hash; /* Message Digest */
uint32_t length_low; /* Message length in bits */
uint32_t length_high; /* Message length in bits */
/* Index into message block array */
int_least16_t message_block_index;
uint8_t message_block[SHA2_256_BlockSize]; /* 512-bit message blocks */
bool computed; /* Is the digest computed? */
bool corrupted; /* Is the message digest corrupted? */
} SHA2Context;
/** data should always be null terminated */
extern SHA2Result sha2_256_oneshot(const uint8_t data[], const size_t len,
SHA2Digest digest);
extern SHA2Result sha2_256_reset(SHA2Context *context);
extern SHA2Result sha2_256_input(SHA2Context *context, const uint8_t data[],
size_t len);
extern SHA2Result sha2_256_result(SHA2Context *context, SHA2Digest digest);
extern void sha2_256_oneshot_n_times(uint32_t n, const uint8_t data[],
const size_t len);
#endif // !SHA2_H

View file

@ -0,0 +1,12 @@
#include "trace.h"
#ifdef TEST
void dump_data(const uint8_t *data, size_t len) {
for (size_t i = 0; i < len; i++) {
TRACE("%02x", data[i])
}
TRACELN("")
}
#endif // TEST

View file

@ -0,0 +1,27 @@
#ifndef TRACE_H
#define TRACE_H
#define STR(a) #a
#ifdef TEST
#include "stdio.h"
#include <stddef.h>
#include <stdint.h>
#define TRACE(...) fprintf(stderr, __VA_ARGS__);
#define TRACELN(MSG) TRACE(MSG "\n")
extern void dump_data(const uint8_t *data, size_t len);
#endif // TEST
// just do nothing if TEST is not defined
#ifndef TEST
#define TRACE(...)
#define TRACELN(MSG)
#define dump_data(DATA_PTR, LEN)
#endif // !TEST
//
#endif // !TRACE_H

View file

@ -0,0 +1,3 @@
#include "crc_common.h"
const char CRC_CHECK_DATA[CRC_CHECK_DATA_LEN] = "123456789";

View file

@ -0,0 +1,7 @@
#ifndef CRC_COMMON_H
#define CRC_COMMON_H
#define CRC_CHECK_DATA_LEN 9
extern const char CRC_CHECK_DATA[CRC_CHECK_DATA_LEN];
#endif // !CRC_COMMON_H

View file

@ -0,0 +1,11 @@
#include "unity.h"
#include "crc.h"
void setUp(void) {}
void tearDown(void) {}
void test_crc_NeedToImplement(void) {
TEST_IGNORE_MESSAGE("Need to Implement crc");
}

View file

@ -0,0 +1,14 @@
#include "crc_common.h"
#include "unity.h"
#include "crc32.h"
void setUp(void) {}
void tearDown(void) {}
void test_crc32_check(void) {
TEST_ASSERT_EQUAL_HEX(crc32_checksum(CRC_CHECK_DATA, CRC_CHECK_DATA_LEN),
0xCBF43926);
TEST_ASSERT_EQUAL_HEX(crc32_checksum("Hello World", 11), 0x4a17b156);
}

View file

@ -0,0 +1,56 @@
#include "hash.h"
#include "sha2.h"
#include "trace.h"
#include "unity.h"
#include <stddef.h>
#include <stdint.h>
#include <string.h>
void setUp(void) {}
void tearDown(void) {}
// BUG: may drop the null at end of strings
#define SAMPLE(INPUT, HASH) \
{(uint8_t[]){INPUT "\0"}, (uint8_t *)(uint32_t[])HASH}
#define TEST_VALUES_LEN 2
uint8_t *test_values[TEST_VALUES_LEN][2] = {
SAMPLE("AAAA", HASH(0x63c1dd95, 0x1ffedf6f, 0x7fd968ad, 0x4efa39b8,
0xed584f16, 0x2f46e715, 0x114ee184, 0xf8de9201)),
SAMPLE("BAAA", HASH(0x49e3cd45, 0x27c96cdc, 0x010160ff, 0x08520e0c,
0xb63c6ef8, 0xc4e7d486, 0x08995343, 0x7f83a159)),
};
void test_sha2_check(void) {
SHA2Digest digest;
SHA2Result res;
uint8_t *input;
size_t len;
size_t i;
for (i = 0; i < TEST_VALUES_LEN; i++) {
TRACE("Hash iteration %d\n", i);
input = test_values[i][0];
len = strlen((char *)input);
TRACELN("Input:");
dump_data(input, len);
TRACELN("Call oneshot");
res = sha2_256_oneshot(input, len, digest);
TEST_ASSERT_EQUAL_MESSAGE(
shaSuccess, res,
"sha2_256_oneshot exited with a code that is not shaSuccess");
// NOTE: If it segfaults here, then the sha2_oneshot function is at fault
// anyways!!!!!!!!!!!!
TRACELN("Hash should be:");
print_digest(test_values[i][1]); // idk how to fix this warning
TRACELN("Hash is:");
print_digest(digest);
TEST_ASSERT_EQUAL_HEX32_ARRAY(test_values[i][1], digest,
SHA2_256_HashParts);
}
}

View file

@ -0,0 +1,12 @@
#include "unity.h"
#include "algorithms.h"
void setUp(void) {}
void tearDown(void) {}
void test_algorithms_loaded(void) {
TEST_ASSERT(algorithms_c_is_loaded() == 1);
}

View file

@ -0,0 +1,22 @@
use algorithms::crc::{self, Crc};
use algorithms::hash;
use criterion::{Criterion, black_box, criterion_group, criterion_main};
pub fn criterion_benchmark(c: &mut Criterion) {
c.bench_function("crc32", |b| {
b.iter(|| crc::Crc32::checksum(black_box(&crc::CHECK_DATA)))
});
c.bench_function("ffi::crc32", |b| {
b.iter(|| crc::ffi::Crc32::checksum(black_box(&crc::CHECK_DATA)))
});
c.bench_function("sha2_256", |b| {
b.iter(|| hash::sha2_256_oneshot(black_box(hash::HASH_EXAMPLE_DATA)))
});
c.bench_function("ffi::sha2_256", |b| {
b.iter(|| hash::ffi::sha2_256_oneshot(black_box(hash::HASH_EXAMPLE_DATA)))
});
}
criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);

View file

@ -0,0 +1,24 @@
use algorithms::crc::{self, Crc};
use algorithms::hash;
use iai::black_box;
fn crc_benchmark_native() -> <crc::Crc32 as Crc>::Checksum {
crc::Crc32::checksum(black_box(&crc::CHECK_DATA))
}
fn crc_benchmark_ffi() -> <crc::ffi::Crc32 as Crc>::Checksum {
crc::ffi::Crc32::checksum(black_box(&crc::CHECK_DATA))
}
fn hash_benchmark_native() -> hash::Digest256 {
hash::sha2_256_oneshot(hash::HASH_EXAMPLE_DATA).unwrap()
}
fn hash_benchmark_ffi() -> hash::Digest256 {
hash::ffi::sha2_256_oneshot(hash::HASH_EXAMPLE_DATA).unwrap()
}
iai::main!(
crc_benchmark_native,
crc_benchmark_ffi,
hash_benchmark_native,
hash_benchmark_ffi
);

67
crates/algorithms/build.rs Executable file
View file

@ -0,0 +1,67 @@
fn env(s: &str) -> String {
std::env::var(s).unwrap()
}
// do yourself a favor if you can, don't use windows
fn main() {
#[cfg(target_os = "windows")]
{
println!(concat!(
"NOTE: Windows can't easily find what to execute for 'ceedling' (the build system for algorithms-c).\n",
"You may need to set it's path in crates/algorithms/build.rs"
));
std::process::Command::new("ceedling.bat")
.arg("clobber")
.current_dir("./algorithms-c/")
.status()
.expect("could not cleanup old algorithms-c files");
}
#[cfg(not(target_os = "windows"))]
{
std::process::Command::new("ceedling")
.arg("clobber")
.current_dir("./algorithms-c/")
.status()
.expect("could not cleanup old algorithms-c files");
}
#[cfg(target_os = "windows")]
let mut cmd = std::process::Command::new("ceedling.bat");
#[cfg(not(target_os = "windows"))]
let mut cmd = std::process::Command::new("ceedling");
let arch = env("CARGO_CFG_TARGET_ARCH");
let pw = env("CARGO_CFG_TARGET_POINTER_WIDTH");
let os = env("CARGO_CFG_TARGET_OS");
if arch == "arm" && pw == "32" && os == "none" {
cmd.env("CC", "arm-none-eabi-gcc")
.env("AR", "arm-none-eabi-ar")
.env("CC_FLAGS", "-march=armv6-m");
} else if os == "linux" || os == "windows" {
cmd.env("CC", "gcc").env("AR", "ar");
} else {
panic!("Unsupported build target")
}
println!("Cwd: {}", std::env::current_dir().unwrap().display());
let status = cmd
.arg("release")
.current_dir("./algorithms-c")
.status()
.expect("could not make c stuff");
if !status.success() {
panic!("ceedling returned an error")
}
let cwd = std::env::current_dir().unwrap().display().to_string();
let libpath_s = format!("{cwd}/algorithms-c/build/artifacts/release/libalgorithms.a");
let libpath = std::path::Path::new(&libpath_s);
assert!(libpath.exists());
println!("cargo::rustc-link-lib=algorithms");
println!("cargo::rerun-if-changed={cwd}/algorithms-c/src/");
println!(
"cargo::rustc-link-search={}",
libpath.parent().unwrap().display()
);
}

View file

@ -0,0 +1,18 @@
use std::io::Read;
use algorithms::crc::Crc;
fn main() {
let args: Vec<String> = std::env::args().collect();
let use_ffi = args.contains(&"-c".to_string());
let mut input = Vec::new();
std::io::stdin()
.read_to_end(&mut input)
.expect("could not read from stdin");
let crc = if use_ffi {
algorithms::crc::ffi::Crc32::checksum(&input)
} else {
algorithms::crc::Crc32::checksum(&input)
};
println!("{crc:08x}");
}

View file

@ -0,0 +1,18 @@
use std::io::Read;
use algorithms::hash::format_digest;
fn main() {
let args: Vec<String> = std::env::args().collect();
let use_ffi = args.contains(&"-c".to_string());
let mut input = Vec::new();
std::io::stdin()
.read_to_end(&mut input)
.expect("could not read from stdin");
let hash = if use_ffi {
algorithms::hash::ffi::sha2_256_oneshot(&input).expect("could not hash your input data")
} else {
algorithms::hash::sha2_256_oneshot(&input).expect("could not hash your input data")
};
println!("{}", format_digest(&hash));
}

View file

@ -0,0 +1,82 @@
//! See RFC1662 Appendix C.3
//!
//! [Link](https://datatracker.ietf.org/doc/html/rfc1662#appendix-C.3)
use super::Crc;
/// Lookup table from RFC1662 C.3
pub const CRC32_TABLE: [u32; 256] = [
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
];
/// Initial Value from RFC1662
pub const CRC32_INIT: u32 = 0xffffffff;
/// Implements CRC-32/ISO-HDLC with look up table
pub struct Crc32(<Crc32 as Crc>::Checksum);
impl Crc for Crc32 {
type Input = [u8];
type Checksum = u32;
#[inline]
fn new() -> Self {
Self(Self::Checksum::default())
}
#[inline]
fn shift_reg(&mut self) -> &mut Self::Checksum {
&mut self.0
}
fn process(&mut self, data: &Self::Input) {
let chksum = self.shift_reg();
*chksum = CRC32_INIT;
for byte in data {
*chksum ^= *byte as u32;
*chksum = (*chksum >> 8) ^ CRC32_TABLE[(*chksum & 0xff) as usize];
}
*chksum ^= CRC32_INIT;
}
}
#[cfg(test)]
mod tests {
use crate::crc::CHECK_DATA;
use super::*;
#[test]
fn test_check() {
// see https://reveng.sourceforge.io/crc-catalogue/17plus.htm#crc.cat-bits.32 for the check
// value
assert_eq!(Crc32::checksum(&CHECK_DATA), 0xCBF43926);
}
}

View file

@ -0,0 +1,65 @@
use crate::{crc::Crc, ffi::ref_to_ptr};
pub type ChecksumCrc32 = u32; // uint32_t in C
unsafe extern "C" {
fn crc32_new() -> Crc32;
fn crc32_process(data: *const u8, len: u32, crc32: *mut Crc32);
fn crc32_checksum(data: *const u8, len: u32) -> ChecksumCrc32;
fn crc32_checksum_n_times(n: u32, data: *const u8, len: u32) -> ChecksumCrc32;
}
#[repr(C)]
pub struct Crc32 {
buf: ChecksumCrc32,
}
impl Crc for Crc32 {
type Input = [u8];
type Checksum = ChecksumCrc32;
#[inline(always)]
fn new() -> Self {
unsafe { crc32_new() }
}
#[inline(always)]
fn process(&mut self, data: &Self::Input) {
unsafe { crc32_process(ref_to_ptr(data), data.len() as u32, self as *mut Self) }
}
#[inline(always)]
fn shift_reg(&mut self) -> &mut Self::Checksum {
&mut self.buf
}
#[inline(always)]
fn checksum(data: &Self::Input) -> Self::Checksum {
unsafe { crc32_checksum(ref_to_ptr(data), data.len() as u32) }
}
}
impl Crc32 {
#[inline(always)]
pub fn checksum_n_times(n: u32, data: &<Crc32 as Crc>::Input) {
unsafe {
crc32_checksum_n_times(n, ref_to_ptr(data), data.len() as u32);
}
}
}
#[cfg(test)]
mod tests {
use crate::crc::CHECK_DATA;
use super::*;
#[test]
fn test_check() {
// see https://reveng.sourceforge.io/crc-catalogue/17plus.htm#crc.cat-bits.32 for the check
// value
assert_eq!(Crc32::checksum(&CHECK_DATA), 0xCBF43926);
}
}

View file

@ -0,0 +1,3 @@
mod crc32;
pub use crc32::*;

View file

@ -0,0 +1,22 @@
/// CRCs from this module are implemented in C instead of Rust
pub mod ffi;
mod crc_32;
pub use crc_32::*;
pub const CHECK_DATA: [u8; 9] = *b"123456789";
pub trait Crc: Sized {
type Input: ?Sized;
type Checksum: Eq + Default + Copy;
fn new() -> Self;
fn process(&mut self, data: &Self::Input);
fn shift_reg(&mut self) -> &mut Self::Checksum;
#[inline]
fn checksum(data: &Self::Input) -> Self::Checksum {
let mut c = Self::new();
c.process(data);
*c.shift_reg()
}
}

View file

@ -0,0 +1,28 @@
unsafe extern "C" {
fn algorithms_c_is_loaded() -> i32;
}
#[inline]
pub fn ffi_is_loaded() -> bool {
unsafe { algorithms_c_is_loaded() == 1 }
}
#[inline]
pub(crate) fn ref_to_ptr<T: ?Sized, P>(r: &T) -> *const P {
r as *const T as *const P
}
#[inline]
pub(crate) fn ref_to_ptr_mut<T: ?Sized, P>(r: &mut T) -> *mut P {
r as *mut T as *mut P
}
#[cfg(test)]
mod test {
use crate::ffi_is_loaded;
#[test]
fn test_ffi_loaded() {
assert!(ffi_is_loaded())
}
}

View file

@ -0,0 +1,2 @@
mod sha2;
pub use sha2::*;

View file

@ -0,0 +1,128 @@
use crate::ffi::{ref_to_ptr, ref_to_ptr_mut};
use super::super::sha2::{DIGEST256_EMPTY, Digest256, SHA2_256_BLOCK_SIZE};
#[repr(C)]
#[allow(non_camel_case_types)]
#[allow(unused)]
#[allow(clippy::enum_variant_names)]
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
pub enum SHA2Outcome {
shaSuccess = 0,
shaNull, /* Null pointer parameter */
shaInputTooLong, /* input data too long */
shaStateError, /* called Input after Result */
shaBadArg, /* Bad argument was given to a function */
}
#[repr(C)]
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
pub struct Sha2_256Context {
pub intermediate_hash: Digest256,
pub length_low: u32,
pub length_high: u32,
pub message_block_index: i16,
pub message_block: [u8; SHA2_256_BLOCK_SIZE],
pub computed: bool,
pub corrupted: bool,
}
impl Sha2_256Context {
pub fn new() -> Self {
Self {
intermediate_hash: DIGEST256_EMPTY,
length_low: 0,
length_high: 0,
message_block_index: 0,
message_block: [0; SHA2_256_BLOCK_SIZE],
computed: false,
corrupted: false,
}
}
}
impl Default for Sha2_256Context {
fn default() -> Self {
Self::new()
}
}
mod ffi {
use super::*;
unsafe extern "C" {
pub fn sha2_256_oneshot(data: *const u8, len: usize, digest: *mut Digest256)
-> SHA2Outcome;
pub fn sha2_256_reset(context: *mut Sha2_256Context) -> SHA2Outcome;
pub fn sha2_256_input(
context: *mut Sha2_256Context,
data: *const u8,
len: usize,
) -> SHA2Outcome;
pub fn sha2_256_result(
context: *mut Sha2_256Context,
digest: *mut Digest256,
) -> SHA2Outcome;
pub fn sha2_256_oneshot_n_times(n: u32, data: *const u8, len: usize);
}
}
#[inline(always)]
pub fn sha2_256_oneshot(data: &[u8]) -> Result<Digest256, SHA2Outcome> {
let mut digest: Digest256 = DIGEST256_EMPTY;
let res =
unsafe { ffi::sha2_256_oneshot(ref_to_ptr(data), data.len(), ref_to_ptr_mut(&mut digest)) };
to_res(digest, res)
}
#[inline(always)]
pub fn sha2_256_reset(context: &mut Sha2_256Context) -> Result<(), SHA2Outcome> {
let res = unsafe { ffi::sha2_256_reset(ref_to_ptr_mut(context)) };
to_res((), res)
}
#[inline(always)]
pub fn sha2_256_input(context: &mut Sha2_256Context, data: &[u8]) -> Result<(), SHA2Outcome> {
let res = unsafe { ffi::sha2_256_input(ref_to_ptr_mut(context), ref_to_ptr(data), data.len()) };
to_res((), res)
}
#[inline(always)]
pub fn sha2_256_result(context: &mut Sha2_256Context) -> Result<Digest256, SHA2Outcome> {
let mut digest: Digest256 = DIGEST256_EMPTY;
let res = unsafe { ffi::sha2_256_result(ref_to_ptr_mut(context), ref_to_ptr_mut(&mut digest)) };
to_res(digest, res)
}
#[inline(always)]
pub fn sha2_256_oneshot_n_times(n: u32, data: &[u8]) {
unsafe {
ffi::sha2_256_oneshot_n_times(n, ref_to_ptr(data), data.len());
};
}
#[inline(always)]
pub(crate) fn to_res<T>(if_ok: T, res: SHA2Outcome) -> Result<T, SHA2Outcome> {
if res == SHA2Outcome::shaSuccess {
Ok(if_ok)
} else {
Err(res)
}
}
// NOTE: this SHA2_256 implementation does not suit core::hash::Hasher in Rust, since that expects
// a finish method with &self and that the hasher can be used after finish.
#[cfg(test)]
mod test {
use crate::hash::Digest256;
use crate::hash::ffi::sha2_256_oneshot;
use crate::hash::test::TEST_VALUES;
#[test]
fn test_sha2_ffi_check() {
for (input, expected_output) in TEST_VALUES.iter().copied() {
assert_eq!(sha2_256_oneshot(input.as_bytes()), Ok(expected_output))
}
}
}

View file

@ -0,0 +1,79 @@
pub mod ffi;
mod sha2;
pub use sha2::*;
pub const HASH_EXAMPLE_DATA: &[u8] = b"lalilolela";
#[cfg(feature = "std")]
pub fn format_digest(digest: &[u32]) -> String {
digest
.iter()
.map(|b| format!("{b:08x}"))
.collect::<String>()
}
#[cfg(test)]
pub(crate) mod test {
use super::*;
use assert_hex::*;
use pretty_assertions::{assert_eq, assert_ne};
#[macro_export]
macro_rules! assert_eq_bin {
($left:expr, $right:expr $(,)?) => ({
match (&$left, &$right) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
panic!(r#"assertion `left == right` failed
left: {:b}
right: {:b}"#, &*left_val, &*right_val)
}
}
}
});
($left:expr, $right:expr, $($arg:tt)+) => ({
match (&($left), &($right)) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
panic!(r#"assertion `left == right` failed: {}
left: {:b}
right: {:b}"#, format_args!($($arg)+), &*left_val, &*right_val)
}
}
}
});
}
pub(crate) const TEST_VALUES: &[(&str, Digest256)] = &[
(
"AAAA",
[
0x63c1dd95, 0x1ffedf6f, 0x7fd968ad, 0x4efa39b8, 0xed584f16, 0x2f46e715, 0x114ee184,
0xf8de9201,
],
),
(
"BAAA",
[
0x49e3cd45, 0x27c96cdc, 0x010160ff, 0x08520e0c, 0xb63c6ef8, 0xc4e7d486, 0x08995343,
0x7f83a159,
],
),
];
#[test]
fn test_sha2_ffi_same_as_native() {
let mut dig_native;
let mut dig_ffi;
for (input, expected_output) in TEST_VALUES.iter().copied() {
dig_native = sha2_256_oneshot(input.as_bytes()).unwrap();
dig_ffi = ffi::sha2_256_oneshot(input.as_bytes()).unwrap();
assert_eq_hex!(
dig_native,
dig_ffi,
"ffi does not return the same result as native"
)
}
}
}

View file

@ -0,0 +1,393 @@
use crate::hash::ffi::SHA2Outcome;
pub const SHA2_256_HASH_BITS: usize = 256;
pub const SHA2_256_HASH_BYTES: usize = SHA2_256_HASH_BITS / 8;
pub const SHA2_256_HASH_PARTS: usize = SHA2_256_HASH_BYTES / 4 /* storing with u32 */;
pub const SHA2_256_BLOCK_SIZE: usize = 2 * SHA2_256_HASH_BYTES;
pub type Digest256 = [u32; SHA2_256_HASH_PARTS];
pub(crate) const DIGEST256_EMPTY: Digest256 = [0; SHA2_256_HASH_PARTS];
macro_rules! show_internals {
($block:block) => {
#[cfg(feature = "show_internals")]
$block
};
}
#[derive(PartialEq, Eq, Clone, Hash)]
pub struct Sha2_256Context {
intermediate_hash: Digest256,
block: [u8; SHA2_256_BLOCK_SIZE],
block_idx: usize,
length_low: usize,
length_high: usize,
}
impl Sha2_256Context {
const K: [u32; SHA2_256_BLOCK_SIZE] = [
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4,
0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe,
0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f,
0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc,
0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116,
0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7,
0xc67178f2,
];
const H: [u32; SHA2_256_HASH_PARTS] = [
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab,
0x5be0cd19,
];
const PAD_BYTE: u8 = 0x80;
pub fn new() -> Self {
Self {
intermediate_hash: Self::H,
block: [0; SHA2_256_BLOCK_SIZE],
block_idx: Default::default(),
length_low: Default::default(),
length_high: Default::default(),
}
}
#[inline]
pub fn clear(&mut self) {
*self = Self::new();
}
pub fn input(&mut self, data: &[u8]) -> Result<(), SHA2Outcome> {
if data.is_empty() {
return Ok(());
}
for byte in data {
self.block[self.block_idx] = *byte;
self.block_idx += 1;
if self.add_length(8).is_ok() && self.block_idx == SHA2_256_BLOCK_SIZE {
self.process_block();
}
}
Ok(())
}
pub fn finish(mut self) -> Result<Digest256, SHA2Outcome> {
self.finalize();
Ok(self.intermediate_hash)
}
fn process_block(&mut self) {
show_internals!({
self.show_internal_state("start processing");
});
let mut w = [0; SHA2_256_BLOCK_SIZE];
#[allow(clippy::needless_range_loop)]
for t in 0..16 {
let t4 = t * 4;
w[t] = ((self.block[t4] as u32) << 24)
| ((self.block[t4 + 1] as u32) << 16)
| ((self.block[t4 + 2] as u32) << 8)
| (self.block[t4 + 3] as u32);
}
// NOTE: The sigma functions used for initializing W and for calculating the alphabet
// variables differ.
for t in 16..SHA2_256_BLOCK_SIZE {
w[t] = Self::sha256_sigma1_w(w[t - 2])
.wrapping_add(w[t - 7])
.wrapping_add(Self::sha256_sigma0_w(w[t - 15]))
.wrapping_add(w[t - 16]);
}
show_internals!({
for (i, w) in w.iter().enumerate() {
println!("w[{i}]:\t{w:032b}")
}
});
let mut a = self.intermediate_hash[0];
let mut b = self.intermediate_hash[1];
let mut c = self.intermediate_hash[2];
let mut d = self.intermediate_hash[3];
let mut e = self.intermediate_hash[4];
let mut f = self.intermediate_hash[5];
let mut g = self.intermediate_hash[6];
let mut h = self.intermediate_hash[7];
show_internals!({
println!("A:\t{a:032b}");
println!("B:\t{b:032b}");
println!("C:\t{c:032b}");
println!("D:\t{d:032b}");
println!("E:\t{e:032b}");
println!("F:\t{f:032b}");
println!("G:\t{g:032b}");
println!("H:\t{h:032b}");
});
let mut temp1;
let mut temp2;
#[allow(clippy::needless_range_loop)]
for t in 0..SHA2_256_BLOCK_SIZE {
show_internals!({
println!("Iter {t}");
});
temp1 = h
.wrapping_add(Self::sha256_sigma1(e))
.wrapping_add(Self::sha_ch(e, f, g))
.wrapping_add(Self::K[t])
.wrapping_add(w[t]);
temp2 = Self::sha256_sigma0(a).wrapping_add(Self::sha_maj(a, b, c));
h = g;
g = f;
f = e;
e = d.wrapping_add(temp1);
d = c;
c = b;
b = a;
a = temp1.wrapping_add(temp2);
show_internals!({
println!("temp1:\t{temp1:032b} {temp1:08x}");
println!("temp2:\t{temp2:032b} {temp2:08x}");
println!("A:\t{a:032b} {a:08x}");
println!("B:\t{b:032b} {b:08x}");
println!("C:\t{c:032b} {c:08x}");
println!("D:\t{d:032b} {d:08x}");
println!("E:\t{e:032b} {e:08x}");
println!("F:\t{f:032b} {f:08x}");
println!("G:\t{g:032b} {g:08x}");
println!("H:\t{h:032b} {h:08x}");
for (i, h) in self.intermediate_hash.iter().enumerate() {
println!("h[{i}]:\t{h:032b} {h:08x}");
}
});
}
show_internals!({
self.show_internal_state("assigning intermediate_hash");
});
self.intermediate_hash[0] = self.intermediate_hash[0].wrapping_add(a);
self.intermediate_hash[1] = self.intermediate_hash[1].wrapping_add(b);
self.intermediate_hash[2] = self.intermediate_hash[2].wrapping_add(c);
self.intermediate_hash[3] = self.intermediate_hash[3].wrapping_add(d);
self.intermediate_hash[4] = self.intermediate_hash[4].wrapping_add(e);
self.intermediate_hash[5] = self.intermediate_hash[5].wrapping_add(f);
self.intermediate_hash[6] = self.intermediate_hash[6].wrapping_add(g);
self.intermediate_hash[7] = self.intermediate_hash[7].wrapping_add(h);
self.block_idx = 0;
show_internals!({
self.show_internal_state("processing end");
for (i, h) in self.intermediate_hash.iter().enumerate() {
println!("h[{i}]:\t{h:032b}");
}
});
}
fn add_length(&mut self, len: usize) -> Result<(), SHA2Outcome> {
let add_temp = self.length_low;
// Update length_low and check for overflow
self.length_low = self.length_low.wrapping_add(len);
if self.length_low < add_temp {
// Overflow occurred, increment length_high
self.length_high = self.length_high.wrapping_add(1);
if self.length_high == 0 {
return Err(SHA2Outcome::shaInputTooLong);
}
}
Ok(())
}
#[inline]
fn finalize(&mut self) {
self.pad_block();
}
fn pad_block(&mut self) {
if self.block_idx >= (SHA2_256_BLOCK_SIZE - 8) {
self.block[self.block_idx] = Self::PAD_BYTE;
self.block_idx += 1;
while self.block_idx < SHA2_256_BLOCK_SIZE {
self.block[self.block_idx] = 0;
self.block_idx += 1;
}
self.process_block();
} else {
self.block[self.block_idx] = Self::PAD_BYTE;
self.block_idx += 1;
}
while self.block_idx < (SHA2_256_BLOCK_SIZE - 8) {
self.block[self.block_idx] = 0;
self.block_idx += 1;
}
self.block[56] = (self.length_high >> 24) as u8;
self.block[57] = (self.length_high >> 16) as u8;
self.block[58] = (self.length_high >> 8) as u8;
self.block[59] = (self.length_high) as u8;
self.block[60] = (self.length_low >> 24) as u8;
self.block[61] = (self.length_low >> 16) as u8;
self.block[62] = (self.length_low >> 8) as u8;
self.block[63] = (self.length_low) as u8;
self.process_block();
}
#[cfg(feature = "show_internals")]
fn show_internal_state(&self, msg: impl core::fmt::Display) {
println!("{msg}\n{self:#x?}")
}
}
/// internal functions for SHA2 process_block
impl Sha2_256Context {
#[inline]
fn sha256_shr(bits: u32, word: u32) -> u32 {
word >> bits
}
#[inline]
fn sha256_rotr(bits: u32, word: u32) -> u32 {
word.rotate_right(bits)
}
/// This is a different function for W
#[inline]
fn sha256_sigma0_w(word: u32) -> u32 {
Self::sha256_rotr(7, word) ^ Self::sha256_rotr(18, word) ^ Self::sha256_shr(3, word)
}
/// This is a different function for W
#[inline]
fn sha256_sigma1_w(word: u32) -> u32 {
Self::sha256_rotr(17, word) ^ Self::sha256_rotr(19, word) ^ Self::sha256_shr(10, word)
}
// NOTE: these do not use shift right for the last internal variable!
#[inline]
fn sha256_sigma0(word: u32) -> u32 {
Self::sha256_rotr(2, word) ^ Self::sha256_rotr(13, word) ^ Self::sha256_rotr(22, word)
}
#[inline]
fn sha256_sigma1(word: u32) -> u32 {
Self::sha256_rotr(6, word) ^ Self::sha256_rotr(11, word) ^ Self::sha256_rotr(25, word)
}
#[inline]
fn sha_ch(x: u32, y: u32, z: u32) -> u32 {
(x & (y ^ z)) ^ z
}
#[inline]
fn sha_maj(x: u32, y: u32, z: u32) -> u32 {
(x & y) ^ (x & z) ^ (y & z)
}
}
impl Default for Sha2_256Context {
fn default() -> Self {
Self::new()
}
}
pub fn sha2_256_oneshot(data: &[u8]) -> Result<Digest256, SHA2Outcome> {
let mut ctx = Sha2_256Context::default();
ctx.input(data)?;
ctx.finish()
}
#[cfg(feature = "show_internals")]
#[allow(unused)]
mod debug {
use super::*;
struct InlineArrHex2<'a, T: core::fmt::Debug + core::fmt::LowerHex>(&'a [T]);
impl<'a, T> core::fmt::Debug for InlineArrHex2<'a, T>
where
T: core::fmt::Debug + core::fmt::LowerHex,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
writeln!(f, "[")?;
for (i, t) in self.0.iter().enumerate() {
write!(f, "0x{t:02x}")?;
if i < self.0.len() - 1 {
write!(f, ", ")?;
}
if i % 8 == 7 && i < self.0.len() - 1 {
writeln!(f)?;
}
}
write!(f, "\n]")?;
Ok(())
}
}
impl core::fmt::Debug for Sha2_256Context {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Sha2_256Context")
.field("intermediate_hash", &InlineArrHex2(&self.intermediate_hash))
.field("block", &InlineArrHex2(&self.block))
.field("block_idx", &self.block_idx)
.field("length_low", &self.length_low)
.field("length_high", &self.length_high)
.finish()
}
}
}
#[cfg(feature = "show_internals")]
#[allow(unused)]
use debug::*;
#[cfg(test)]
mod test {
use super::*;
use crate::assert_eq_bin;
use crate::hash::test::TEST_VALUES;
use assert_hex::*;
use pretty_assertions::{assert_eq, assert_ne};
#[test]
fn test_sha256_check() {
let mut dig;
for (input, expected_output) in TEST_VALUES.iter().copied() {
dig = sha2_256_oneshot(input.as_bytes()).unwrap();
println!(
"Binary of first seg matches: {}\n{:032b}\n{:032b}",
dig[0] == expected_output[0],
dig[0],
expected_output[0]
);
assert_eq_hex!(dig, expected_output)
}
}
#[test]
fn test_sha256_sigma0() {
let a = 0b01101010000010011110011001100111;
assert_eq_bin!(
Sha2_256Context::sha256_sigma0(a),
0b11001110001000001011010001111110
);
}
#[test]
fn test_sha256_sigma1() {
let a = 0b01010001000011100101001001111111;
assert_eq_bin!(
Sha2_256Context::sha256_sigma1(a),
0b00110101100001110010011100101011
);
}
}

16
crates/algorithms/src/lib.rs Executable file
View file

@ -0,0 +1,16 @@
//! # CRC's from scratch, nothing else
//!
//! This crate implements some CRC algorithms from scratch in a `no_std` environment.
//!
//! ## Acknowledgements
//!
//! Many thanks to the [crc-catalogue](https://reveng.sourceforge.io/crc-catalogue/) for providing
//! an overview over the various algorithms with test vectors and examples.
#![cfg_attr(not(any(test, feature = "std")), no_std)]
pub mod crc;
pub mod hash;
pub(crate) mod ffi;
pub use ffi::ffi_is_loaded;

Binary file not shown.

View file

@ -0,0 +1 @@
37206c142fbe243e5eb299fea8fa4a0cc7b26d668dc394d8851c8059c5a8abcf measurement-2025-08-11.tar.gz

6
scripts/bench_algorithms.sh Executable file
View file

@ -0,0 +1,6 @@
#!/bin/bash
# I'm using a bash script because if i set the target in .cargo/config.toml
# i can't build for x86_64 anymore, which means I can't run the unit tests.
TARGET="x86_64-unknown-linux-gnu"
cd crates/algorithms
cargo bench --target $TARGET --no-default-features

5
scripts/build.sh Executable file
View file

@ -0,0 +1,5 @@
#!/bin/bash
# I'm using a bash script because if i set the target in .cargo/config.toml
# i can't build for x86_64 anymore, which means I can't run the unit tests.
TARGET="thumbv6m-none-eabi"
cargo build --target $TARGET $@

6
scripts/flash.sh Executable file
View file

@ -0,0 +1,6 @@
#!/bin/bash
# I'm using a bash script because if i set the target in .cargo/config.toml
# i can't build for x86_64 anymore, which means I can't run the unit tests.
TARGET="thumbv6m-none-eabi"
cargo build --target $TARGET
cargo run -r --target $TARGET $@

6
scripts/test_algorithms.sh Executable file
View file

@ -0,0 +1,6 @@
#!/bin/bash
# I'm using a bash script because if i set the target in .cargo/config.toml
# i can't build for x86_64 anymore, which means I can't run the unit tests.
TARGET="x86_64-unknown-linux-gnu"
cd crates/algorithms
cargo test --target $TARGET --no-default-features

2
scripts/winattach.sh Executable file
View file

@ -0,0 +1,2 @@
#!/bin/bash
powershell.exe -Command "probe-rs attach C:\SVN\nt\BA\trunk\Studium\Christoph_Scherr\system\Implementation\crcbench\target\thumbv6m-none-eabi\release\nucleo-l053r8-benches --chip STM32L053R8"

10
scripts/winflash.sh Executable file
View file

@ -0,0 +1,10 @@
#!/bin/bash
set -e
bash ./scripts/copy_to_svn.sh
TARGET="thumbv6m-none-eabi"
powershell.exe -Command "
cd C:\SVN\nt\BA\trunk\Studium\Christoph_Scherr\system\Implementation\crcbench;
cargo build -r --target $TARGET;
cargo run -r --target $TARGET $@
"

130
src/bench.rs Normal file
View file

@ -0,0 +1,130 @@
use algorithms::crc::{Crc, Crc32 as Crc32Rust, ffi::Crc32 as Crc32C};
use algorithms::hash::{ffi as sha2_ffi, sha2_256_oneshot};
use defmt::info;
use hal::{
delay::Delay,
gpio::{Output, Pin, PushPull},
prelude::*,
};
pub type SomePin = Pin<Output<PushPull>>;
pub struct MeasurePins<'a> {
pub c: &'a mut SomePin,
pub rs: &'a mut SomePin,
pub led: &'a mut SomePin,
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum MeasurementKind {
Rust,
C,
}
const RUNS: u32 = 5000;
impl MeasurePins<'_> {
pub fn set_led(&mut self, state: PinState) {
self.led.set_state(state).expect("could not set led state")
}
pub fn set_for_kind(&mut self, kind: MeasurementKind, state: PinState) {
match kind {
MeasurementKind::Rust => self.rs.set_state(state),
MeasurementKind::C => self.c.set_state(state),
}
.expect("could not set rs or c pin")
}
pub fn set_all(&mut self, state: PinState) {
self.led.set_state(state).expect("could not set led state");
self.rs.set_state(state).expect("could not set rs state");
self.c.set_state(state).expect("could not set c state");
}
}
#[inline]
pub fn bench(pins: &mut MeasurePins, delay: &mut Delay) {
bench_crc(pins, delay);
bench_sha256(pins, delay);
}
fn time_exec<F>(
id: &str,
kind: MeasurementKind,
pins: &mut MeasurePins,
delay: &mut Delay,
do_loop: bool,
mut f: F,
) where
F: FnMut(),
{
if do_loop {
info!("Running '{}' {} times", id, RUNS);
pins.set_for_kind(kind, PinState::High);
for _ in 0..RUNS {
f();
}
pins.set_for_kind(kind, PinState::Low);
} else {
info!("Running '{}' 1 time", id);
pins.set_for_kind(kind, PinState::High);
f();
pins.set_for_kind(kind, PinState::Low);
}
info!("Measurement of '{}' finished!", id);
delay.delay_ms(100_u32);
}
fn bench_crc(pins: &mut MeasurePins, delay: &mut Delay) {
const DATA: &[u8] = b"hello world AAAAAAAAAAAAAAAAAAAAAAA";
time_exec("crc32_rs", MeasurementKind::Rust, pins, delay, true, || {
Crc32Rust::checksum(DATA);
});
time_exec("crc32_c_ffi", MeasurementKind::C, pins, delay, true, || {
Crc32C::checksum(DATA);
});
time_exec(
"crc32_c_native",
MeasurementKind::C,
pins,
delay,
false,
|| {
Crc32C::checksum_n_times(RUNS, DATA);
},
);
}
fn bench_sha256(pins: &mut MeasurePins, delay: &mut Delay) {
const DATA: &[u8] = b"hello world AAAAAAAAAAAAAAAAAAAAAAA";
time_exec(
"sha256_rs",
MeasurementKind::Rust,
pins,
delay,
true,
|| {
sha2_256_oneshot(DATA).unwrap();
},
);
time_exec(
"sha256_c_ffi",
MeasurementKind::C,
pins,
delay,
true,
|| {
sha2_ffi::sha2_256_oneshot(DATA).unwrap();
},
);
time_exec(
"sha256_c_native",
MeasurementKind::C,
pins,
delay,
false,
|| {
sha2_ffi::sha2_256_oneshot_n_times(RUNS, DATA);
},
);
}

View file

47
src/error_handlers.rs Normal file
View file

@ -0,0 +1,47 @@
use cortex_m_rt::ExceptionFrame;
use defmt::error;
// same panicking *behavior* as `panic-probe` but doesn't print a panic message
// this prevents the panic message being printed *twice* when `defmt::panic` is invoked
#[defmt::panic_handler]
fn panic() -> ! {
cortex_m::asm::udf()
}
fn display_ef(ef: &ExceptionFrame) {
struct Wrapper(ExceptionFrame);
impl defmt::Format for Wrapper {
fn format(&self, fmt: defmt::Formatter) {
defmt::write!(
fmt,
"ExceptionFrame(\n\tr0: {:08x}\n\tr1: {:08x}\n\tr2: {:08x}\n\tr3: {:08x}\n\tr12: {:08x}\n\tlr: {:08x}\n\tpc: {:08x}\n\txpsr: {:08x}\n)",
self.0.r0(),
self.0.r1(),
self.0.r2(),
self.0.r3(),
self.0.r12(),
self.0.lr(),
self.0.pc(),
self.0.xpsr()
);
}
}
error!("HardFault: Exception occured!");
error!("Exception occured at: {:08x}", ef.pc());
error!("XSPR: {:032b}", ef.xpsr());
error!("LR: {:08x}", ef.lr());
error!("HardFault: {:#?}", Wrapper(*ef))
}
#[allow(unreachable_code)]
#[cortex_m_rt::exception(trampoline = true)]
unsafe fn HardFault(ef: &ExceptionFrame) -> ! {
static mut EXCEPTION: Option<ExceptionFrame> = None;
unsafe { EXCEPTION = Some(*ef) };
display_ef(ef);
#[allow(clippy::empty_loop)]
loop {}
}

View file

@ -1,27 +1,33 @@
#![no_main]
// If rust-analyzer says it can't find `test`, you need to disable `allTargets` in it's
// configuration. This project has a `.cargo/config.toml` file that explicitly sets targets.
// See https://github.com/rust-lang/rust-analyzer/issues/3297
#![no_std]
#![no_main]
mod crc;
#[cfg(not(all(target_os = "none", target_pointer_width = "32", target_arch = "arm")))]
compile_error!("This program can only be compiled for arm32 bare metal");
use defmt::{debug, error, info, println, trace, warn};
use defmt::{debug, info};
use panic_probe as _;
use defmt_rtt as _; // global logger
use cortex_m_rt::entry;
use hal::{pac, prelude::*, rcc::Config};
use hal::{
pac::{self},
prelude::*,
rcc::Config,
};
// same panicking *behavior* as `panic-probe` but doesn't print a panic message
// this prevents the panic message being printed *twice* when `defmt::panic` is invoked
#[defmt::panic_handler]
fn panic() -> ! {
cortex_m::asm::udf()
}
use crate::bench::MeasurePins;
mod bench;
mod error_handlers; // defines a handler for evil hardfaults
#[entry]
fn main() -> ! {
let dp = pac::Peripherals::take().unwrap();
let cp = cortex_m::Peripherals::take().unwrap();
let mut cp = cortex_m::Peripherals::take().unwrap();
// Configure the clock.
let mut rcc = dp.RCC.freeze(Config::hsi16());
@ -29,26 +35,41 @@ fn main() -> ! {
// Acquire the GPIOA peripheral. This also enables the clock for GPIOA in
// the RCC register.
let gpioa = dp.GPIOA.split(&mut rcc);
let gpiob = dp.GPIOB.split(&mut rcc);
// Configure PA5 as output.
let mut led = gpioa.pa5.into_push_pull_output();
// This is D4 on CN19 for the NCLEO L053R8 according to the user manual:
// "UM1724"
let mut measurepin_0 = gpiob.pb5.into_push_pull_output().downgrade();
// This is D5 on CN19 for the NCLEO L053R8
let mut measurepin_1 = gpiob.pb4.into_push_pull_output().downgrade();
let mut led = gpioa.pa5.into_push_pull_output().downgrade(); // this is the led
measurepin_0.set_low().unwrap();
led.set_low().unwrap();
// setup timer for measuring time of benchmarks
cp.SYST.set_reload(0x00ffffff); // max
cp.SYST.clear_current();
cp.SYST.enable_counter();
// Get the delay provider.
let mut delay = cp.SYST.delay(rcc.clocks);
#[allow(clippy::never_loop)]
debug!("Asserting that libalgorithms is correctly loaded");
assert!(algorithms::ffi_is_loaded(), "ffi is not loaded?");
let mut measurepins = bench::MeasurePins {
c: &mut measurepin_0,
rs: &mut measurepin_1,
led: &mut led,
};
info!("Starting the Rust vs C benchmark");
bench::bench(&mut measurepins, &mut delay);
info!("Benchmark done");
measurepins.set_all(PinState::Low);
loop {
println!("Hello World!");
trace!("trace log");
debug!("debug log");
info!("info log");
warn!("warn log");
error!("error log");
led.set_high().unwrap();
delay.delay_ms(500_u16);
led.set_low().unwrap();
delay.delay_ms(500_u16);
delay.delay_ms(5000u32);
}
}