Files
boxmaker/docs/plans/M2a/01-proto-sha256.md
T
kyleandClaude Fable 5.1 76ccc251cd Add M2a plan: thirteen tasks, tests, fake server and recordings
The tasks build the inference path: emsha-backed SHA-256, inferproxy,
config, a hand-written HTTP and SSE client, request building, delta
assembly, the chat state machine, the thinking cap, the slot gate with
retry, the startup self-test and on-device verification.

Everything the tasks copy in was checked against a private reference
implementation: the gate passes after each task in order, the timing
tests pass repeatedly under CPU load, and the reference passes the
self-test and all four device checks on straylight. Expected results
for the recorded streams were derived by a separate script.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-17 13:34:11 -07:00

3.9 KiB

M2a task 01: SHA-256 in proto

Branch: m2a (create it from master: git switch master && git switch -c m2a) Commit subject: Add SHA-256 to proto, wrapping the emsha crate

Goal

Give the workspace one SHA-256 function. It wraps the emsha crate, which the project's owner wrote. Nothing else in the workspace may use emsha directly, so that the choice of implementation stays in one file.

Context

The hash is used to check that the inference server runs the chat template we expect, and later for the audit log. An earlier release of emsha hashed every message of 63, 127, 191, … bytes wrongly, because of a mistake at a padding boundary. That is fixed in 1.0.4, and it is why the test file checks lengths on both sides of every boundary and feeds each message in two pieces.

Files

  • Copy: crates/proto/tests/hash.rs
  • Create: crates/proto/src/hash.rs
  • Modify: Cargo.toml, crates/proto/Cargo.toml, crates/proto/src/lib.rs, docs/dependencies.md, docs/implementer-log.md, Cargo.lock (generated)

Interfaces

Consumes: proto::Hash32 (Hash32::from_bytes([u8; 32])).

Produces, in crates/proto/src/hash.rs, re-exported from the crate root:

pub struct HashError;          // Debug, Clone, Copy, PartialEq, Eq; Display; std::error::Error

pub struct Sha256(/* private */);
impl Sha256 {
    pub fn new() -> Self;
    pub fn update(&mut self, data: &[u8]) -> Result<(), HashError>;   // may be called many times
    pub fn finish(self) -> Result<Hash32, HashError>;
}
impl Default for Sha256 { /* same as new() */ }

pub fn sha256(data: &[u8]) -> Result<Hash32, HashError>;             // new, update, finish

Every emsha error becomes HashError. No unwrap or expect.

API notes (emsha 1.0.4, read from its source on 2026-09-17)

use emsha::Hash;                              // the trait that has update and finalize
let mut h = emsha::sha256::SHA256::new();
h.update(b"bytes")?;                          // fn update(&mut self, msg: &[u8]) -> emsha::Result<()>
let mut out = [0u8; emsha::sha256::SIZE];     // SIZE is 32
h.finalize(&mut out)?;                        // fn finalize(&mut self, digest: &mut [u8]) -> emsha::Result<()>

emsha::Result<T> is Result<T, emsha::Error>. The crate has no dependencies and is no_std.

Steps

  • 1. Branch, copy the test, add the dependency.
git switch master && git switch -c m2a
cp docs/plans/M2a/files/crates/proto/tests/hash.rs crates/proto/tests/

Add to [workspace.dependencies] in the root Cargo.toml: emsha = "1.0.4". Add to [dependencies] in crates/proto/Cargo.toml: emsha.workspace = true. Add this row to docs/dependencies.md:

| `emsha` | 1.0.4 | `proto` | SHA-256. Written by the owner; no dependencies, no `unsafe`. Checked against `sha256sum` on 3,204 inputs. |
  • 2. See the test fail. cargo test -p proto --test hash. Expected: it does not compile.

  • 3. Write hash.rs, and in lib.rs add pub mod hash; and pub use hash::{HashError, Sha256, sha256};. Run cargo fmt --all.

  • 4. See the test pass. cargo test -p proto --test hash. Expected: 4 passed.

  • 5. Run the gate. cargo build, then make gate. Expected last line: gate: ok. cargo deny prints a no-license-field warning for emsha; that is expected, because the crate's licence is a file and not an SPDX name. Do not edit deny.toml.

  • 6. Log and commit.

git add Cargo.toml Cargo.lock crates/proto docs/dependencies.md docs/implementer-log.md
git commit

Done when

  • cargo test -p proto --test hash reports 4 passed; make gate prints gate: ok.
  • grep -rn emsha crates/*/src shows crates/proto/src/hash.rs only.

Stop and report if

  • A vector in hash.rs fails. Do not change the vector: it would mean emsha is wrong again.
  • cargo deny reports an error, not a warning, for emsha.