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

104 lines
3.9 KiB
Markdown

# 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:
```rust
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)
```rust
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.**
```sh
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`:
```markdown
| `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.**
```sh
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`.