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
5 changes: 5 additions & 0 deletions Cargo.lock

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

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ members = [
"lib/logstream",
"lib/manifest",
"lib/microcode",
"lib/parity",
"lib/pci-claim",
"lib/quiesce",
"lib/random",
Expand Down Expand Up @@ -304,6 +305,8 @@ toyos-metal = { path = "tests/metal" }
# The shutdown's stop record: the kernel renders it and the harness reads it
# back off a log, so one declaration is what both sides spell it with.
toyos-quiesce = { path = "lib/quiesce" }
# The parity table `crypto_parity` prints and the judge reads, under one rule.
toyos-parity = { path = "lib/parity" }

[patch.crates-io]
loom = { git = "https://github.com/ToyOSOrg/loom", branch = "toyos" }
Expand Down
34 changes: 28 additions & 6 deletions build/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,12 +238,12 @@ fn stale(crate_dir: &Path, identity: &Identity) -> Option<Stale> {
}

/// Remove what `stale` names of `crate_dir`'s target directory and stamp it
/// with `identity`. [`Stale::All`] is the guest profile's host half and every
/// with `identity`. [`Stale::All`] is the guest profiles' host halves and every
/// guest target's directory: the root's `target/` is also the build system's
/// own, which no sysroot made.
fn clean(crate_dir: &Path, stale: &Stale, identity: &Identity) {
let target = crate_dir.join("target");
let all: Vec<&str> = std::iter::once(PROFILE).chain(toolchain::GUEST_TARGETS.map(|t| t.triple())).collect();
let all: Vec<&str> = [PROFILE, UNASSERTED].into_iter().chain(toolchain::GUEST_TARGETS.map(|t| t.triple())).collect();
let moved = match stale {
Stale::All => &all,
Stale::Targets(moved) => moved,
Expand Down Expand Up @@ -368,6 +368,10 @@ fn config_crates(root: &Path, config: &SystemConfig) -> Vec<ConfigCrate> {
/// root the image is made of.
pub const PROFILE: &str = "toyos";

/// [`PROFILE`] with debug assertions off, which `tests/guest/rust-tests`
/// declares for a measurement's column that shows what they cost.
pub const UNASSERTED: &str = "toyos-unasserted";

/// What every guest `cargo` and `rustc` here runs with: the toolchain directory
/// of the sysroot this checkout's sources name, as `RUSTUP_TOOLCHAIN`, which
/// carries the linker too.
Expand Down Expand Up @@ -408,7 +412,20 @@ fn cargo_build(
extra_env: &[(&str, &str)],
quiet: bool,
) {
let mut args = vec!["build", "--target", target, "--profile", PROFILE];
cargo_build_as(PROFILE, crate_dir, target, extra_args, env, extra_env, quiet)
}

/// [`cargo_build`] in `profile`.
fn cargo_build_as(
profile: &str,
crate_dir: &Path,
target: &str,
extra_args: &[&str],
env: &GuestEnv,
extra_env: &[(&str, &str)],
quiet: bool,
) {
let mut args = vec!["build", "--target", target, "--profile", profile];
if quiet {
args.push("--quiet");
}
Expand Down Expand Up @@ -2224,11 +2241,16 @@ impl TestBuild {
/// The one binary `name` of the crate at `crate_path`, built for `arch`: for an
/// architecture the crate's other binaries do not all build for.
pub fn build_toyos_bin(root: &Path, arch: Arch, crate_path: &Path, name: &str, quiet: bool) -> Vec<u8> {
let _building = Building::start(format!("{} {name} of {}", arch.name(), hostws::rel(root, crate_path)));
build_toyos_bin_as(root, arch, crate_path, name, PROFILE, quiet)
}

/// [`build_toyos_bin`] in `profile`, which the crate declares.
pub fn build_toyos_bin_as(root: &Path, arch: Arch, crate_path: &Path, name: &str, profile: &str, quiet: bool) -> Vec<u8> {
let _building = Building::start(format!("{} {name} ({profile}) of {}", arch.name(), hostws::rel(root, crate_path)));
let build = TestBuild::begin(root, arch, "a test binary", &[crate_path.to_path_buf()]);
let (target, env) = (build.target, &build.env);
cargo_build(crate_path, target, &["--bin", name], env, &[], quiet);
let binary = crate_path.join(format!("target/{target}/{PROFILE}/{name}"));
cargo_build_as(profile, crate_path, target, &["--bin", name], env, &[], quiet);
let binary = crate_path.join(format!("target/{target}/{profile}/{name}"));
fs::read(&binary).unwrap_or_else(|e| panic!("read the test binary {}: {e}", binary.display()))
}

Expand Down
58 changes: 48 additions & 10 deletions issues/toyos-crypto-is-in-the-tree-on-par-with-ring-and-secure.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,11 @@ review has been done, and passing vectors does not show it is safer than ring.
- Evidence: `ToyOSOrg/evidence` `pr-913`,
https://github.com/ToyOSOrg/evidence/tree/b7cde8091500ac0f7773c56fd0d70c8bbe9429aa/pr-913/exploratory-mac-asym.
- No metal bench has measured these.
- **Inside ToyOS today `CR4.OSXSAVE` is clear**
(`issues/user-programs-use-avx-under-xsave.md`). Both the crate and ring
therefore run their SSE paths there, and the crate's ChaCha, whose only
vector path is AVX2, is scalar.
- **Inside ToyOS `CR4.OSXSAVE` is set** since f7b497231. The kernel's cpu0
records in #932's bench boots show XCR0 0xe7 on the T14 (AVX-512 state)
and 0x7 on the AMD bench (AVX). The parity instrument records what
feature detection admits there, AVX2 and AES-NI on both benches and
VAES/AVX-512 on the T14, so both crates' vector paths are open.
- **AArch64 is scalar.** No ARM bench exists to measure an ARM path, so the
crate's AArch64 AES and PMULL paths are not imported. They stay in the
archive until an ARM bench measures them. `toyos-sha2-hw` follows the same
Expand Down Expand Up @@ -123,9 +124,16 @@ Not consumers:
- `ring::test` stays in `tests/guest/rust-tests/src/bin/ring_kat.rs`, as
ring's own known-answer row: it is the one way to give ring a known
X25519 key.
- The program is `crypto_parity`, built a second time with debug
assertions off as `crypto_parity_unasserted`. `lib/parity` holds the
rule. The metal row `crypto_instrument` prints both builds' table in the
boot `cryptocase`.
**Exit**: both benches' tables are on `ToyOSOrg/evidence`, with the
columns stage 3 defines.
3. **Parity.**
- **The verdict's row is this stage's.** `toyos_parity::Table::verdict`
is the rule. Its metal row, judged on `cryptocase` beside
`crypto_instrument`, is registered when this stage's rows pass.
- **Profile.** The verdict is taken in `[profile.toyos]`, as every guest
binary ships: `opt-level = 2`, with debug assertions and overflow checks
on. The crate's assertions are part of what ships, and their cost
Expand All @@ -141,16 +149,46 @@ Not consumers:
5% gets no verdict and is measured again.
- **Verdict.** A row passes when the median over i of
ours_i / ((A_i + B_i) / 2) is at most 1 + spread.
- **A recorded bias.** An open row restores its ciphertext before each
open, and every backend pays for that copy, which pulls the ratio
toward 1. A pass on an open row is read with that bias in mind. On the
development Mac (exploratory), the copy is 3–6.5% of ring's AES-GCM open
and 1–1.7% of its ChaCha20-Poly1305 open. No bench has measured it.
- **Exit:**
- On both benches, every row a consumer uses passes on the ISA both
crates run in that boot. Today that ISA is SSE.
- The rows pass again in the boot after
`issues/user-programs-use-avx-under-xsave.md` lands, with both crates
admitting AVX. A consumer that passed on SSE and fails with AVX is a
filed defect.
- On both benches, every row a consumer uses passes on the ISA each
build records. That ISA is now AVX-capable state on both benches.
`issues/user-programs-use-avx-under-xsave.md`'s remaining exit,
userland threads' state, is not a gate here.
- Parity work reads ring's, BoringSSL's and OpenSSL's perlasm or C only
through a clean room, as root's research rule says.
- Faster code is accepted only with stage 4's evidence for it.
- **First measurement on the benches**, #932 at 85cda28d3, shipped
build. Each row was built only after ours matched ring on its inputs,
except the three ECDH rows: their check, an agreement of ours and ring
on one secret, came after this run.
A family's ratio is ours over ring's mean, and its median is the lower
middle of the family's rows. Each build recorded its ISA:
- the T14: `aes,pclmulqdq,sha,movbe,bmi2,adx,avx,avx2,vaes,vpclmulqdq,avx512f,avx512vl`;
- the AMD bench: `aes,pclmulqdq,sha,movbe,bmi2,adx,avx,avx2`.

| family | T14 median | T14 worst | AMD median | AMD worst |
|---|---|---|---|---|
| AES-GCM (26 rows) | 1.43 | 3.63 key setup | 1.68 | 2.36 seal 16 KiB |
| ChaCha20-Poly1305 (13) | 4.74 | 6.98 seal 16 KiB | 4.68 | 8.74 seal 16 KiB |
| chacha20-poly1305@openssh (16) | 2.82 | 13.5 key setup | 2.94 | 19.0 key setup |
| SHA-2 (4) | 1.96 | 7.25 SHA-256 16 KiB | 1.73 | 7.85 SHA-256 16 KiB |
| HMAC/HKDF (4) | 1.94 | 3.39 HMAC-SHA-256 | 1.80 | 3.98 HMAC-SHA-256 |
| ECDH (3) | 13.3 | 21.2 P-256 | 10.6 | 22.2 P-256 |
| Ed25519 sign, verify | 70.8, 34.3 | | 59.7, 25.3 | |
| ECDSA verify P-256, P-384 | 22.1, 4.92 | | 23.3, 5.39 | |
| RSA verify (4) | 30.6 | 38.2 2048 PKCS#1 | 27.6 | 34.6 2048 PKCS#1 |
| ML-KEM-768 beside `ml-kem`, excluded | 1.01 | 1.08 | 1.05 | 1.11 |

The T14 has 70 fails, 1 remeasure and 3 passes. The AMD bench has 73
fails and 1 pass. The first run, at 9a318695e, recorded no ISA and
printed samples rounded to 0.1 ns. Its figures agree with these within
about 5%. Tables:
https://github.com/ToyOSOrg/evidence/tree/4dfa4dc8c647bee3424a13be28191bdb2213bcbd/pr-932/r2.
- **First measurement, not a verdict.** `toyos-ssh`'s fuzz
(`build/ssh/tests/fuzz.rs`), on the crate since stage 1: 33.92 s and
15.46 s in two runs on the development Mac (an M4 Pro). On ring it took
Expand Down
6 changes: 6 additions & 0 deletions lib/parity/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "toyos-parity"
description = "The parity rule toyos-crypto is held to beside ring: rotated sampling of ours and two reference instances, the A/B spread, the verdict, and the table lines a guest prints and the judge reads."
version = "0.1.0"
edition = "2021"
license = "MIT OR Apache-2.0"
Loading