Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 7 additions & 23 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 2 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,6 @@ members = [
"lib/random",
"lib/rootimage",
"lib/scsi",
"lib/sha2",
"lib/sha2-hw",
"lib/swap",
"lib/symbols",
"lib/tco",
Expand Down Expand Up @@ -267,9 +265,8 @@ toyos-ssh = { path = "build/ssh" }
# `classify`, so the host reading a log volume and `logkeeper` writing it cannot
# disagree about which files on it are `logkeeper`'s.
toyos-wallclock = { path = "lib/wallclock" }
# Every SHA-256 the build takes: `NOTICE`'s record of a committed file, a
# store key, a ROOT's name and a release asset's digest.
toyos-sha2-hw = { path = "lib/sha2-hw" }
# Every SHA-256 the build takes (`toyos_build::sha256`).
toyos-crypto = { path = "lib/crypto" }
# The toolchain release's tarball, packed in-process (`build/release.rs`): Rust's
# own tar and gzip, where the binaries are hosts' tools.
tar = { version = "0.4.46", default-features = false }
Expand Down
11 changes: 5 additions & 6 deletions NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -474,8 +474,8 @@ image carries them. These are every file of that directory for an interface the
crate offers.


lib/crypto/tests/data/nist-*.json — NIST ACVP HMAC and ML-KEM vectors, NIST-Software
------------------------------------------------------------------------------------
tests/acvp/nist-*.json — NIST ACVP HMAC and ML-KEM vectors, NIST-Software
-------------------------------------------------------------------------

nist-hmac-sha1.json sha256 6e96eb5f53065219c437a99fedec7299c916c76e170d6b74507dc5409ed9cd6b
HMAC-SHA-1-2.0/internalProjection.json
Expand All @@ -491,7 +491,7 @@ lib/crypto/tests/data/nist-*.json — NIST ACVP HMAC and ML-KEM vectors, NIST-So
ML-KEM-keyGen-FIPS203/internalProjection.json
Upstream: https://github.com/usnistgov/ACVP-Server, `gen-val/json-files/`
at commit 975de31eb83d87039ec88934fdc47d8c312b892d, byte for byte
Licence text: lib/crypto/tests/data/nist-LICENSE (the `License` section of upstream's
Licence text: tests/acvp/nist-LICENSE (the `License` section of upstream's
`README.md` at that commit, sha256
8e6833bd6bd35dadd415147ba53a8eca4c3d31c53cb589e97abba6a4efd5b953)
SPDX-License-Identifier: NIST-Software
Expand Down Expand Up @@ -618,9 +618,8 @@ tests/cavp/SHA*.rsp — NIST's SHA-2 test vectors, CAVP SHAVS

The response files NIST's Cryptographic Algorithm Validation Program publishes
for the SHA Validation System: messages and the digests FIPS 180-4 gives them,
the external oracle `toyos-sha2`'s, `toyos-sha2-hw`'s and `toyos-crypto`'s tests
hold them to. A work of the United States government, not under copyright in
the United States (17 U.S.C. §105). Test input only: nothing built from this
the external oracle `toyos-crypto`'s tests hold them to. A work of the United
States government, not under copyright in the United States (17 U.S.C. §105). Test input only: nothing built from this
repository carries them, and no shipped package's directory holds them.

Of the archive, only SHA-256's, SHA-384's and SHA-512's files, the hashes
Expand Down
2 changes: 1 addition & 1 deletion build/cicache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ fn sources(root: &Path) -> Result<Sources, String> {
continue;
}
let bytes = fs::read(&file).map_err(|e| format!("read {path}: {e}"))?;
sources.insert(path, crate::release::sha256_hex(&bytes));
sources.insert(path, crate::sha256_hex(&bytes));
}
Ok(sources)
}
Expand Down
2 changes: 1 addition & 1 deletion build/hostedclang.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ fn pack(product: &Path, sysroot: &Path, licence: &Path, version: &str, into: &Pa
let packed = tar.into_inner().and_then(|gzip| gzip.finish()).and_then(|mut file| file.flush());
packed.unwrap_or_else(|e| panic!("{}: {e}", archive.display()));

let digest: String = toyos_sha2_hw::sha256_digest(read(&archive)).iter().map(|b| format!("{b:02x}")).collect();
let digest = crate::sha256_hex(&read(&archive));
let sums = into.join("SHA256SUMS");
fs::write(&sums, format!("{digest} {name}\n")).unwrap_or_else(|e| panic!("write {}: {e}", sums.display()));
Packaged { archive, sums }
Expand Down
10 changes: 5 additions & 5 deletions build/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,10 @@ fn format_root(
/// the bytes, so no two entries can run together into an input a different
/// split would also produce.
fn root_uuid(files: &[&(String, Vec<u8>)], symlinks: &[&(String, String)]) -> FsUuid {
let mut hasher = toyos_sha2_hw::sha256();
let mut hasher = toyos_crypto::hash::Sha256::new();
let mut field = |bytes: &[u8]| {
hasher.update((bytes.len() as u64).to_le_bytes());
hasher.update(bytes);
hasher.update(&(bytes.len() as u64).to_le_bytes()).expect(crate::SHA256_BOUND);
hasher.update(bytes).expect(crate::SHA256_BOUND);
};
for (name, data) in files {
field(name.as_bytes());
Expand Down Expand Up @@ -1362,8 +1362,8 @@ mod tests {
for (name, data) in &files {
let read = fs.read_file(name).unwrap_or_else(|e| panic!("read {name}: {e:?}"));
assert_eq!(
toyos_sha2_hw::sha256_digest(&read),
toyos_sha2_hw::sha256_digest(data),
crate::sha256(&read),
crate::sha256(data),
"{name} reads back as {} bytes that are not the {} it was given",
read.len(),
data.len()
Expand Down
15 changes: 15 additions & 0 deletions build/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,21 @@ pub mod wallpaper;
use std::path::{Path, PathBuf};
use std::process::Command;

/// The SHA-256 every digest the build takes is: `NOTICE`'s record of a
/// committed file, a store key, a ROOT's name and a release asset's digest.
pub fn sha256(bytes: &[u8]) -> [u8; 32] {
toyos_crypto::hash::Sha256::digest(bytes).expect(SHA256_BOUND)
}

/// [`sha256`] in lower-case hex, the spelling `NOTICE` and `SHA256SUMS` take.
pub fn sha256_hex(bytes: &[u8]) -> String {
sha256(bytes).iter().map(|b| format!("{b:02x}")).collect()
}

/// Why a build hash cannot refuse: FIPS 180-4 bounds a message at 2^61 bytes,
/// which nothing the build reads nears.
pub const SHA256_BOUND: &str = "a build input is far below SHA-256's 2^61-byte bound";

/// The `.git` directory every worktree of this repository shares.
///
/// `git rev-parse --git-common-dir` answers relatively from the primary
Expand Down
12 changes: 6 additions & 6 deletions build/licence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -901,37 +901,37 @@ pub const COMMITTED_FILES: &[(&str, &str, &str, Terms)] = &[
Terms::Spdx("Apache-2.0"),
),
(
"lib/crypto/tests/data/nist-hmac-sha1.json",
"tests/acvp/nist-hmac-sha1.json",
"6e96eb5f53065219c437a99fedec7299c916c76e170d6b74507dc5409ed9cd6b",
"NOTICE",
Terms::Spdx("NIST-Software"),
),
(
"lib/crypto/tests/data/nist-hmac-sha256.json",
"tests/acvp/nist-hmac-sha256.json",
"a9d0734b93aee71bc6f30b47daab782fd96b39688afe4fbddb009e99402ec989",
"NOTICE",
Terms::Spdx("NIST-Software"),
),
(
"lib/crypto/tests/data/nist-hmac-sha384.json",
"tests/acvp/nist-hmac-sha384.json",
"0ffa9332b9430ae94cfac0f23b3843293903fa34a3ac9c11a8af2bfdf7276ed3",
"NOTICE",
Terms::Spdx("NIST-Software"),
),
(
"lib/crypto/tests/data/nist-hmac-sha512.json",
"tests/acvp/nist-hmac-sha512.json",
"ea6e03f012d5237b95421b7d50c504f8ab010c4f7f18cd46fe61d8912d3442a0",
"NOTICE",
Terms::Spdx("NIST-Software"),
),
(
"lib/crypto/tests/data/nist-mlkem-encapdecap.json",
"tests/acvp/nist-mlkem-encapdecap.json",
"5e88fbd351dc2915b2ab399f5dffd269e1cdbdd0186103ab0e90b374cf592187",
"NOTICE",
Terms::Spdx("NIST-Software"),
),
(
"lib/crypto/tests/data/nist-mlkem-keygen.json",
"tests/acvp/nist-mlkem-keygen.json",
"d7a62a2c3476957f56dd8d24f9004ea6776ccfe995ffe71a65bb9506dc9c7b1b",
"NOTICE",
Terms::Spdx("NIST-Software"),
Expand Down
4 changes: 1 addition & 3 deletions build/release.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,7 @@ pub(crate) fn named_key(text: &str) -> Option<Key> {
text.lines().next()?.strip_prefix("toolchain ")?.strip_prefix(TAG).and_then(Key::parse)
}

pub(crate) fn sha256_hex(bytes: &[u8]) -> String {
toyos_sha2_hw::sha256_digest(bytes).iter().map(|b| format!("{b:02x}")).collect()
}
use crate::sha256_hex;

fn on_runner() -> bool {
std::env::var("GITHUB_ACTIONS").is_ok_and(|v| v == "true")
Expand Down
2 changes: 1 addition & 1 deletion build/sdkversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ fn plan_of(
// A requirement's build metadata is ignored, and cargo warns of it.
spec.insert("version".into(), dep.version.split('+').next().unwrap_or(&dep.version).into());
}
let key = crate::release::sha256_hex(hashed.as_bytes())[..16].to_string();
let key = crate::sha256_hex(hashed.as_bytes())[..16].to_string();
let (version, publish) = assign(&index(krate.name)?, &key)?;
let package = manifest.get_mut("package").and_then(|p| p.as_table_mut()).ok_or("no [package]")?;
package.insert("version".into(), version.clone().into());
Expand Down
2 changes: 1 addition & 1 deletion build/sourcegate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ fn host_files() -> Vec<PathBuf> {
/// `bytes` as lower-case hex SHA-256, the spelling `NOTICE` records.
#[cfg(test)]
fn digest(bytes: &[u8]) -> String {
toyos_sha2_hw::sha256_digest(bytes).iter().map(|b| format!("{b:02x}")).collect()
crate::sha256_hex(bytes)
}

/// The shapes of a value that identifies a machine or the network it is on,
Expand Down
15 changes: 8 additions & 7 deletions build/sysroot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ fn hex(digest: &[u8]) -> String {

/// The first 16 hex digits of the SHA-256 of `data`.
pub(crate) fn short(data: &[u8]) -> String {
hex(&toyos_sha2_hw::sha256_digest(data))[..16].to_string()
hex(&crate::sha256(data))[..16].to_string()
}

/// Every file under `dir` a build reads, sorted: no `target/` and no dotted
Expand Down Expand Up @@ -375,18 +375,19 @@ pub(crate) fn tree_identity(base: &Path, paths: &[&str], links: Links) -> String
let mut sources = Vec::new();
source_files(base, paths, links, &mut sources);
sources.sort();
let mut hasher = toyos_sha2_hw::sha256();
let mut hasher = toyos_crypto::hash::Sha256::new();
let mut put = |bytes: &[u8]| hasher.update(bytes).expect(crate::SHA256_BOUND);
for (path, commit) in sources {
hasher.update(path.strip_prefix(base).unwrap_or(&path).to_string_lossy().as_bytes());
hasher.update([0]);
put(path.strip_prefix(base).unwrap_or(&path).to_string_lossy().as_bytes());
put(&[0]);
match commit {
Some(commit) => hasher.update(commit.as_bytes()),
Some(commit) => put(commit.as_bytes()),
None => {
let data = fs::read(&path).unwrap_or_else(|e| panic!("read {}: {e}", path.display()));
hasher.update(&*identity::of(&path, &data));
put(&identity::of(&path, &data));
}
}
hasher.update([0]);
put(&[0]);
}
hex(&hasher.finalize())[..16].to_string()
}
Expand Down
2 changes: 1 addition & 1 deletion build/wallpaper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ mod tests {
/// point answers differently reds here rather than naming a different ROOT.
#[test]
fn the_wallpaper_is_the_same_on_every_host() {
let digest: String = toyos_sha2_hw::sha256_digest(rgb()).iter().map(|b| format!("{b:02x}")).collect();
let digest = crate::sha256_hex(&rgb());
assert_eq!(digest, "675f4fbc92985dc5e60b899fd869fa8e574b1147e2b1c9b42808a72bcfff1d91");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ opened: 2026-10-09

# No T14 reading of `update`'s ROOT hash before and after SHA-NI

`update`'s streamed ROOT hash (`system/update/src/main.rs`, `stream_root`)
moved from `toyos-sha2`'s scalar compression to `toyos-sha2-hw`'s SHA-NI one,
and no machine has timed it on either. `update` reports no hash time, and no
`update`'s streamed ROOT hash (`system/update/src/install/mod.rs`,
`stream_root`) runs on `toyos-crypto`'s SHA-NI compression, which replaced
`toyos-sha2`'s scalar one and then `toyos-sha2-hw`'s SHA-NI one, and no
machine has timed it on any of them. `update` reports no hash time, and no
metal row runs `update`.

The loader's ROOT hash, the same function on the same CPU, is not this
Expand All @@ -17,4 +18,5 @@ reading: it runs on a soft-float UEFI target before ExitBootServices, and
writes.

Exit: the T14's reading of `update`'s ROOT hash on one image, with
`toyos-sha2`'s scalar compression and with `toyos-sha2-hw`'s.
`toyos-crypto`'s portable rounds (its `portable` feature) and with its SHA-NI
compression.
6 changes: 3 additions & 3 deletions issues/the-tree-says-who-uses-each-thing.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,9 +174,9 @@ Where this differs from the tree the owner adopted:
sshserver serves on russh (rule step 4).
- `tests/metal/` is the metal loop. A machine's records are in the host's
store since #852, so there is no `tests/machines/t14/` and no descriptor.
- `tests/cavp/` stays: `lib/sha2`'s SHAVS driver and `toyos-crypto`'s
`tests/nist.rs` read it, and `lib/sha2-hw`'s tests include that driver. The orchestrator ruled it shared test data,
which inside `lib/sha2` the licence gate would count as shipping.
- `tests/cavp/` stays: `toyos-crypto`'s `tests/nist.rs` reads it. It was
ruled shared test data, which inside a crate's directory the licence gate
would count as shipping.
- There is no `tests/judges/ssh/`: no SSH judge is in the tree.

## Stages
Expand Down
Loading