From 27f11bf85a4dfe8117ccbdf795b8aa8122aab3a8 Mon Sep 17 00:00:00 2001 From: archipelago Date: Tue, 16 Jun 2026 12:40:57 -0400 Subject: [PATCH] feat(trust): wire Phase 0 signed-catalog verification + pin release-root KAT Completes the parked trust module and wires it into the live build: - main.rs: register `mod trust` - app_catalog::fetch_one: verify the release-root detached signature when present (verify against raw JSON so forward-compat fields stay in the signed preimage); accept unsigned during the migration window, hard-reject a present-but-bad signature so a tampering mirror can't pass altered bytes - seed: pin release-root Ed25519 known-answer test (priv+pub) for the signing ceremony / pinned-anchor / external-verifier cross-check - signed_doc: drop unused import 20/20 Phase 0 unit tests pass (trust::canonical/did/signed_doc/anchor, seed release-root, app_catalog). Crate compiles clean. Co-Authored-By: Claude Opus 4.8 (1M context) --- core/archipelago/src/container/app_catalog.rs | 29 +++++++++++++++++-- core/archipelago/src/main.rs | 1 + core/archipelago/src/seed.rs | 4 +-- core/archipelago/src/trust/signed_doc.rs | 2 +- 4 files changed, 30 insertions(+), 6 deletions(-) diff --git a/core/archipelago/src/container/app_catalog.rs b/core/archipelago/src/container/app_catalog.rs index 9253070e..912c3b8f 100644 --- a/core/archipelago/src/container/app_catalog.rs +++ b/core/archipelago/src/container/app_catalog.rs @@ -268,9 +268,32 @@ async fn fetch_one(client: &reqwest::Client, url: &str) -> anyhow::Result { + debug!("app-catalog: unsigned (accepted during migration window)"); + } + crate::trust::SignatureStatus::Verified { signer_did, anchored } => { + if anchored { + info!("app-catalog: release-root signature verified ({})", signer_did); + } else { + warn!( + "app-catalog: signature self-consistent but release-root anchor \ + not pinned ({}); cannot confirm signer identity", + signer_did + ); + } + } + } + Ok(catalog) } diff --git a/core/archipelago/src/main.rs b/core/archipelago/src/main.rs index 0850a813..be620245 100644 --- a/core/archipelago/src/main.rs +++ b/core/archipelago/src/main.rs @@ -68,6 +68,7 @@ mod storage_crypto; mod streaming; mod totp; mod transport; +mod trust; mod update; mod vpn; mod wallet; diff --git a/core/archipelago/src/seed.rs b/core/archipelago/src/seed.rs index 7b3def15..96cc6cbe 100644 --- a/core/archipelago/src/seed.rs +++ b/core/archipelago/src/seed.rs @@ -606,12 +606,12 @@ mod tests { let key = derive_release_root_ed25519(&seed).unwrap(); assert_eq!( hex::encode(key.to_bytes()), - "__RELEASE_ROOT_PRIV_HEX__", + "613ab879e5fbd4fcded32bc7ffad662fff1ce0f744c69baa63e7416ffabe7b71", "release-root private key KAT" ); assert_eq!( hex::encode(key.verifying_key().to_bytes()), - "__RELEASE_ROOT_PUB_HEX__", + "995eaf9188617f0ecbcff9cd44d57adb9aa7dd5f34db2733e97f3e317fb0aba2", "release-root public key KAT" ); } diff --git a/core/archipelago/src/trust/signed_doc.rs b/core/archipelago/src/trust/signed_doc.rs index 07e1bc88..adb4d70a 100644 --- a/core/archipelago/src/trust/signed_doc.rs +++ b/core/archipelago/src/trust/signed_doc.rs @@ -16,7 +16,7 @@ //! them*. The DHT plan requires both. use anyhow::{anyhow, bail, Context, Result}; -use ed25519_dalek::{Signature, Signer, SigningKey, VerifyingKey}; +use ed25519_dalek::{Signature, Signer, SigningKey}; use serde_json::Value; use super::anchor;