Skip to main content

max / everycycle

appraise: pin an Ed25519 fixture in the round-trip tests Every test in round_trip.rs signed and verified inside one process, so a change to seed-to-key derivation, canonical encoding, or signature encoding kept them all green. Pin the pubkey, the canonical box-payload JSON, its SHA-256, and both signatures, and add a test that verifies a report rebuilt from those bytes without touching the signing path.
Co-Authored-By
Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-07-22 18:02 UTC
Signed with PGP, not checked
Commit: 60dd9c8ba282ac96a8efa2f9eddce238fbbea3ed
Parent: 155d6b5
1 file changed, +91 insertions, -3 deletions
@@ -6,15 +6,17 @@
6 6 //! 3. The card payload's `box_report` hash matches what
7 7 //! `box_payload_hash` derives from the box payload.
8 8 //! 4. Tampering with any signed field breaks verification.
9 + //! 5. Key derivation, canonical encoding, and signature bytes match a
10 + //! pinned fixture, so a format break cannot pass silently.
9 11
10 12 use everycycle_appraise::{
11 13 TenantKey, VerifyError, box_payload_hash, canonical_json, sign_box_report, sign_card_report,
12 14 verify_box_report, verify_card_report,
13 15 };
14 16 use everycycle_hal::{
15 - BoxReportPayload, CapabilityVector, CardReportPayload, DeviceIdentity, DriverBinding,
16 - HostIdentity, Interconnect, LaunchOverhead, Memory, PeerLink, Precision, PrecisionThroughput,
17 - ProbeEnvironment, ThermalEnvelope,
17 + BoxReport, BoxReportPayload, CapabilityVector, CardReportPayload, DeviceIdentity,
18 + DriverBinding, HostIdentity, Interconnect, LaunchOverhead, Memory, PeerLink, Precision,
19 + PrecisionThroughput, ProbeEnvironment, Signature, ThermalEnvelope,
18 20 };
19 21
20 22 const TENANT: &str = "tailoredmachines";
@@ -176,6 +178,92 @@
176 178 assert!(verify_box_report(&box_report).is_err());
177 179 }
178 180
181 + /// Byte-level constants pinned from the fixture above. Every other test
182 + /// in this file signs and verifies inside one process, so all of them
183 + /// stay green if seed-to-key derivation, canonical encoding, or
184 + /// signature encoding changes. These literals are the only thing that
185 + /// notices.
186 + ///
187 + /// Regenerating them is never the fix for a failure here. A mismatch
188 + /// means previously issued appraisals no longer verify, which is a
189 + /// format break that needs a version bump, not a new constant.
190 + mod pinned {
191 + /// `TenantKey::from_seed(TENANT, SEED).pubkey_b64()`. Guards
192 + /// seed-to-key derivation and the base64 alphabet.
193 + pub(crate) const PUBKEY_B64: &str = "6kpsY+KcUgq+9VB7Ey7F+ZVHdq6+vnuSQh7qaRRG0iw=";
194 +
195 + /// `canonical_json(&box_payload())`. Guards key ordering at every
196 + /// level, compact separators, and float formatting.
197 + pub(crate) const BOX_JSON: &str = r#"{"ambient_c":24.5,"driver_versions":[{"bus_address":"0000:01:00.0","driver_version":"580.126.18"}],"host":{"cpu_model":"synthetic-cpu","dmi_string":"synthetic-dmi","hostname":"astra"},"present_devices":["0000:01:00.0"],"probe_suite_version":"0.1.0","probed_at":"2026-06-20T18:23:11Z","report_version":"1"}"#;
198 +
199 + /// `box_payload_hash(&box_payload())`. Guards the SHA-256 digest and
200 + /// the lowercase hex encoding.
201 + pub(crate) const BOX_HASH: &str =
202 + "b875c714b30278ded37f8522bcec679565a97a723e30820e4f378e027e22799d";
203 +
204 + /// Signature over `BOX_JSON`. Ed25519 nonces are derived from the
205 + /// key and message (RFC 8032), so this is reproducible.
206 + pub(crate) const BOX_SIG: &str =
207 + "gBVK+hWaX5SkmjzgwvhhsyYb9CTSo0I7xf1394G3TEQddri8CexNzs198N10cAocMu98DSrvowIHlI9oveCFCQ==";
208 +
209 + /// Signature over the card payload, which nests `CapabilityVector`
210 + /// and so also covers enum-variant and nested-object encoding that
211 + /// the box payload never exercises.
212 + pub(crate) const CARD_SIG: &str =
213 + "8Hwfz2Lf+CAsn8iU2AsNhwH0gyO192aAjAT4bCcaSUJiUyqQsdsiiXXMckMek5OF/7Ip+sv/X069dKImdHFVDg==";
214 + }
215 +
216 + #[test]
217 + fn seed_derives_the_pinned_pubkey() {
218 + let key = TenantKey::from_seed(TENANT, SEED);
219 + assert_eq!(key.pubkey_b64(), pinned::PUBKEY_B64);
220 + }
221 +
222 + #[test]
223 + fn box_payload_encodes_to_the_pinned_bytes() {
224 + assert_eq!(canonical_json(&box_payload()).unwrap(), pinned::BOX_JSON);
225 + assert_eq!(box_payload_hash(&box_payload()).unwrap(), pinned::BOX_HASH);
226 + }
227 +
228 + #[test]
229 + fn signatures_match_the_pinned_fixture() {
230 + let key = TenantKey::from_seed(TENANT, SEED);
231 +
232 + let box_report = sign_box_report(&key, box_payload()).unwrap();
233 + assert_eq!(box_report.signature.alg, "ed25519");
234 + assert_eq!(box_report.signature.tenant_identity, TENANT);
235 + assert_eq!(box_report.signature.tenant_pubkey, pinned::PUBKEY_B64);
236 + assert_eq!(box_report.signature.sig, pinned::BOX_SIG);
237 +
238 + let card_report = sign_card_report(
239 + &key,
240 + CardReportPayload {
241 + report_version: REPORT_VERSION.into(),
242 + probed_at: PROBED_AT.into(),
243 + box_report: pinned::BOX_HASH.into(),
244 + capability: capability(),
245 + },
246 + )
247 + .unwrap();
248 + assert_eq!(card_report.signature.sig, pinned::CARD_SIG);
249 + }
250 +
251 + /// A report carrying the pinned signature verifies without ever calling
252 + /// the signing path, which is what an archived appraisal does.
253 + #[test]
254 + fn a_report_rebuilt_from_pinned_bytes_verifies() {
255 + let report = BoxReport {
256 + payload: box_payload(),
257 + signature: Signature {
258 + alg: "ed25519".into(),
259 + tenant_identity: TENANT.into(),
260 + tenant_pubkey: pinned::PUBKEY_B64.into(),
261 + sig: pinned::BOX_SIG.into(),
262 + },
263 + };
264 + verify_box_report(&report).expect("pinned signature still verifies");
265 + }
266 +
179 267 #[test]
180 268 fn box_hash_changes_with_any_field() {
181 269 let baseline = box_payload_hash(&box_payload()).unwrap();