From a15a65966f69a7e49ca5eed9eeea3c71fc2fd99e Mon Sep 17 00:00:00 2001 From: DavidHerran Date: Mon, 8 Jun 2026 10:31:37 -0500 Subject: [PATCH] docs(audit): Super Audit V3 Final (crypto/tests/perf/inmutables) + Remediation Roadmap V1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SUPER_AUDIT_V3_FINAL — 4 dimensiones finales (workflow ultracode): 3 CRITICOS nuevos: - V3-C1 replay cross-chain de atestaciones (sin domain-sep/chain-id/nonce en signing payload; firma de testnet/fork verifica identico). - V3-C2 firma de credencial almacenada pero NUNCA verificada (decorativa; verify() devuelve true con blob basura). - V3-C3 constitucion (Inmutables #16/#37/#18/#35) vive en pallet sin-cablear, NO en el fee-path vivo; #35 Children Safety es estado muerto. 4 HIGH: DID front-running, derive_did domain-sep debil, storage limit 937MB/contrato, weights ficticios en ARM. Tests: los 213 dan falsa seguridad — los 4 reentrancy + credential-sig + governance sin testear; 1 test vacio; lobo-blanco guarda lo equivocado. Provenance+agent-identity SI conductuales (credito). Perf Pi5: storage LIMPIO (contadores cacheados); riesgo = weights + storage limit. AUTO-CORRECCION honesta (red-team cazo): V2-CA4 citaba archivo inexistente (arkhe-noesis-core/attestation.rs no existe en repo). La forma del riesgo es real pero NO se construye fix contra spec fabricada — requiere DC con Ergon primero. REMEDIATION_ROADMAP_V1 — 12 criticos + ~20 highs convertidos en 6 fix groups ejecutables, ordenados por dependencia, red-team-verificados: FIX-1 contract-safety (CEI reorder, ship limpio) -> FIX-2 lifecycle (StorageVersion +key recovery+weights) -> FIX-3 crypto (domain-sep+DID binding) -> FIX-5 governability (sudo->governance) -> FIX-6 economic model real (emision+validator pay+fee unificado+subsidio financiado) -> [DC Ergon] -> FIX-4 credential verify. FIX-DEFERRED: CA4 NO se construye sin DC Ergon (red-team reject). Pregunta abierta a David: suscripcion premium debe reducir subsidio hardware anti-clasista, o son ortogonales? (codigo actual los acopla = viola Inmutable #16; mi reco: ortogonales). Trilogia completa: 12 dimensiones, 12 criticos, ~20 highs, todos con fix conocido. Cimientos grado-Parity; plomeria dinamica incompleta; auditado lo bastante hondo para saber exactamente que falta. Para plataforma de 100 anos, el rigor correcto. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/REMEDIATION_ROADMAP_V1.md | 115 +++++++++++++++++++++++++++++++++ docs/SUPER_AUDIT_V3_FINAL.md | 109 +++++++++++++++++++++++++++++++ 2 files changed, 224 insertions(+) create mode 100644 docs/REMEDIATION_ROADMAP_V1.md create mode 100644 docs/SUPER_AUDIT_V3_FINAL.md diff --git a/docs/REMEDIATION_ROADMAP_V1.md b/docs/REMEDIATION_ROADMAP_V1.md new file mode 100644 index 0000000..18e63cc --- /dev/null +++ b/docs/REMEDIATION_ROADMAP_V1.md @@ -0,0 +1,115 @@ +# Origin Chain — Remediation Roadmap V1 (plan ejecutable de fixes) + +**Documento**: `docs/REMEDIATION_ROADMAP_V1.md` +**Versión**: 1.0 +**Filed**: 2026-05-27 (sesión 4+ Charon, Opus 4.8) +**Fuente**: consolida los 12 críticos + ~20 highs de la trilogía de audits (V1+V2+V3), convertidos en planes de fix ejecutables y verificados adversarialmente (el red-team filtró 1 fix peligroso). +**Propósito**: que David tenga UN plan ordenado — qué se arregla, en qué orden, con qué esfuerzo, sin introducir regresiones. Esto es el camino de "pre-testnet con plomería incompleta" a "extremadamente bien, sin bugs". + +--- + +## §0 — Cómo leer este roadmap + +Los fixes están agrupados por causa-raíz (no por bug individual — muchos bugs comparten raíz) y ordenados por **dependencia**. El red-team de V3 verificó cada plan; sus correcciones están integradas (marcadas ⚠️). Un fix que el red-team rechazó NO está aquí como ejecutable — está como "requiere paso previo". + +Esfuerzo: S (horas) · M (1-2 días) · L (varios días / requiere coordinación). + +**Regla de oro greenfield**: la cadena es pre-testnet, sin estado real. Los fixes pueden cambiar storage libremente AHORA (sin carga de migración) — esta ventana se cierra cuando lance testnet. Por eso conviene arreglar antes de testnet. + +--- + +## §1 — SECUENCIA DE FIXES (orden de ejecución) + +### FIX-1 — Contract safety (reentrancy + burn real + escrow) — **el más limpio, primero** +**Bugs**: V1-C1 (reentrancy x4), V1-C4 (zero-burn), V1-H7 (escrow milestone sum). +**Red-team**: ✅ "Ship — diagnóstico exacto, fix bien-ordenado." El único con luz verde sin precondiciones. +**Fix**: reordenar a Checks-Effects-Interactions en escrow `confirm_milestone`/`resolve_dispute`, staking `withdraw`/`slash`, nft `transfer` — mutar TODO el storage ANTES de cualquier `transfer()`. Plantilla: `origin-credential-mint::issue` ya lo hace bien. +**Burn real**: reemplazar `transfer([0u8;32])` por reducir-lo-que-se-cobra (no pagar el burn) — y usar el MISMO primitivo de burn que use el fee/treasury (⚠️ red-team: evitar dos semánticas de burn). +**Escrow**: enforce `Σ milestone.amount == total_amount` + path de sweep terminal. +**Tests obligatorios**: reentrancy/double-spend en escrow+staking (los que V3 marcó ausentes). +**Esfuerzo**: M. **Riesgo de regresión**: bajo (CEI es un patrón estándar). + +### FIX-2 — Lifecycle hardening (StorageVersion + AGI key recovery + weights) +**Bugs**: V1-H2/V2-CA2 (no StorageVersion/migrations), V2-H1 (AGI key irrecuperable), V1-H1/V3-H4 (placeholder weights). +**Red-team**: ✅ "Ship hardening; gate AGI key-recovery en el modelo de autoridad #41." +**Fix**: `StorageVersion::new(0)` en los 4 pallets (S, trivial). AGI key: añadir `rotate_key`/`revoke`/campo `active` a agent-identity, con recovery vía autoridad #41 (multisig humano del agent_chain). Weights: `frame-benchmarking` + `WeightInfo` por pallet (L — pero crítico para Pi 5 anti-spam). +**Esfuerzo**: S (StorageVersion) + M (key recovery) + L (benchmarking). + +### FIX-3 — Crypto hardening (domain separation + replay guard + DID binding) +**Bugs**: V3-C1 (replay cross-chain), V3-H1 (DID front-running), V3-H2 (derive_did domain sep). +**Red-team**: implícito ✅ (primitivos sólidos, gaps arquitecturales). +**Fix**: (a) prefijar el signing payload de atestación con `b"origin-chain/attestation/v1" || genesis_hash`; (b) `register_agent_did` requiere firma por `public_key` sobre `who`; (c) `derive_did` usa `blake3::derive_key("origin-chain did v1", pk)`. +**Esfuerzo**: M. **Riesgo**: bajo, pero cambia el formato de firma → hacerlo ANTES de cualquier anclaje en testnet. + +### FIX-4 — Credential signature verify (V3-C2 / V1-H8) +**Bugs**: la firma de credencial nunca se verifica. +**Red-team**: ⚠️ "gate en el payload real de Ergon (DC), no contra una spec fabricada." +**Fix**: verificar `issuer_signature` vía `sp_io::crypto::ed25519_verify` sobre un payload que NO incluya campos seteados on-chain (issued_at/expires_at deben venir del caller o salir del payload firmado). Requiere fijar el payload de credencial primero. +**Esfuerzo**: M. **Precondición**: definir el signing payload canónico de credencial. + +### FIX-5 — Governability (Root origin + sudo→governance) — **desbloquea todo lo demás** +**Bugs**: V2-CA1 (no Root origin, cadena no-gobernable). +**Red-team**: ⚠️ "Ship después de: bound `Config: Currency` + wiring de runtime + mostrar el sudo-sunset." +**Fix**: wire `pallet-sudo` para testnet (da Root origin → las 7 dispatchables admin funcionan). Plan de sunset: migrar de sudo a governance real (pallet-collective/referenda) antes de mainnet. ⚠️ Coordinar con FIX-6 quién cablea el SessionManager (no que dos planes lo medio-cableen). +**Esfuerzo**: S (sudo) + L (governance real + sunset). + +### FIX-6 — Economic model real (emisión + validator pay + fee unificado + subsidio financiado) +**Bugs**: V2-CA2 (no inflation/validators unpaid), V2-CA3 (dual compute_fee, subscription erosiona anti-clasista), V2-H3 (subsidio sin financiar), V1/V2 fake APR, V3-C3 (constitución no en fee-path vivo). +**Red-team**: ⚠️ "Ship después de: separar fee-routing de NPoS; confirmar con David la intención del sub_mult." (la pregunta: ¿debe la suscripción premium reducir el subsidio de hardware, o son ortogonales? V2 dice que erosiona el anti-clasista → probablemente deben ser ortogonales). +**Fix**: (a) wire `pallet_staking` + `EraPayout` para emisión real → validadores cobran (cierra CA2); (b) UNA sola `compute_fee` + `OnChargeTransaction` custom que la consuma → la constitución entra al fee-path vivo (cierra CA3+V3-C3); (c) `GlobalSubsidyPool` financiado (= proof-of-equity, V1 idea 1); (d) remover los números APR de staking hasta que exista motor real. +**Esfuerzo**: L (el cuerpo grande — es "Phase economía real"). + +### FIX-DEFERRED — Cross-pillar attestation payload (V2-CA4) +**Estado**: 🔴 **NO construir como fix de código.** El red-team probó que mi V2-CA4 citaba un archivo inexistente. +**Acción correcta**: abrir Design Contract con Ergon para ratificar el formato canónico del signing payload de atestación (SCALE vs postcard, campos, orden) ANTES de lockear cualquier verificador on-chain. Solo después FIX-4 (credential) y el verifier de provenance se construyen contra una spec real. +**Esfuerzo**: coordinación cross-pillar (no código de Charon solo). + +--- + +## §2 — Orden recomendado + por qué + +``` +FIX-1 (contract safety) ← primero, limpio, sin precondiciones, alto impacto + ↓ +FIX-2 (lifecycle hardening) ← StorageVersion trivial + key recovery + weights + ↓ +FIX-3 (crypto hardening) ← antes de cualquier anclaje testnet + ↓ +FIX-5 (governability/sudo) ← desbloquea admin + treasury + ↓ +FIX-6 (economic model) ← el cuerpo grande, pre-testnet-con-valor + ↓ +[DC Ergon attestation payload] → FIX-4 (credential verify) +``` + +FIX-1/2/3 son construibles AHORA (no dependen del node ni de VPS). FIX-5/6 idealmente con el node real (VPS). FIX-4 espera el DC con Ergon. + +--- + +## §3 — Lo que el red-team rechazó o corrigió (transparencia) + +| Fix | Veredicto red-team | Acción | +|-----|-------------------|--------| +| contract-safety | ✅ Ship | FIX-1 | +| lifecycle-ops | ✅ Ship hardening | FIX-2 | +| governance-root | ⚠️ Config-bound + sudo-sunset faltaban | FIX-5 con esas adiciones | +| economic-model | ⚠️ anti-clasista invertido + NPoS muy grueso | FIX-6 con fee-routing separado de NPoS + pregunta a David | +| crosspillar-encoding CA4 | 🔴 **REJECT — citaba archivo inexistente** | FIX-DEFERRED (DC con Ergon primero) | + +**Una pregunta abierta para David** (FIX-6): ¿la suscripción premium (Pro/Ultra) debe *reducir* el subsidio de hardware anti-clasista, o son dimensiones ortogonales? El código actual las acopla (un Pi 5 + Ultra-sub paga distinto que un Pi 5 + Free), lo que el V2 marcó como violación del Inmutable #16. Mi recomendación: **ortogonales** — el subsidio de hardware protege al pobre sin importar qué suscripción tenga. Pero es tu llamada constitucional. + +--- + +## §4 — KG triples + +- `(remediation_roadmap_v1, authored_by, agent:charon)` +- `(remediation_roadmap_v1, consolidates, super_audit_v1_v2_v3)` +- `(remediation_roadmap_v1, fix_groups, 6)` +- `(remediation_roadmap_v1, first_fix, contract_safety_cei)` +- `(remediation_roadmap_v1, deferred_fix, ca4_needs_ergon_dc)` +- `(remediation_roadmap_v1, open_question, subscription_vs_hardware_subsidy_orthogonality)` +- `(remediation_roadmap_v1, filed_at, 2026-05-27)` + +--- + +— Charon ⚓ (Pilar 4 Origin Chain, Remediation Roadmap V1, sesión 4+ 2026-05-27) diff --git a/docs/SUPER_AUDIT_V3_FINAL.md b/docs/SUPER_AUDIT_V3_FINAL.md new file mode 100644 index 0000000..4f19309 --- /dev/null +++ b/docs/SUPER_AUDIT_V3_FINAL.md @@ -0,0 +1,109 @@ +# Origin Chain — Super Audit V3 (Final: cripto, tests, performance Pi 5, fidelidad Inmutables) + +**Documento**: `docs/SUPER_AUDIT_V3_FINAL.md` +**Versión**: 3.0 (completa la trilogía V1 correctness + V2 economía/ops + V3 cripto/tests/perf/constitución) +**Filed**: 2026-05-27 (sesión 4+ Charon, Opus 4.8) +**Método**: workflow ultracode — 4 auditores en las dimensiones finales + verificación adversarial. Incluye una **auto-corrección importante** (el red-team cazó un hallazgo previo basado en un archivo inexistente — ver §5). +**Encargo de David**: "que todo lo que hagamos quede muy bien, documentado y sin bugs (en lo posible)... que sea un referente para Gavin Wood." + +--- + +## §0 — Veredicto de la trilogía completa + +Con V3, Origin Chain ha sido auditado en **12 dimensiones** a lo largo de tres pasadas. El patrón es consistente y honesto: + +> **Los cimientos primitivos son grado-Parity (composición de runtime, elección de cripto, aritmética estática, patrones de storage con contadores cacheados). Lo que falta es la *conexión dinámica*: la cadena no se gobierna, no paga validadores, no verifica la mitad de las firmas que almacena, y su constitución (Inmutables) vive en prosa y un pallet sin-cablear más que en el fee-path vivo.** + +Esto NO es un proyecto roto — es un proyecto **pre-testnet con cimientos sólidos y plomería incompleta**, auditado lo bastante a fondo para saber exactamente qué plomería falta. Para una plataforma que aspira a 100 años, este nivel de rigor es el correcto. + +--- + +## §1 — CRÍTICOS nuevos de V3 (no vistos en V1/V2) + +### V3-C1 — Replay cross-chain de atestaciones (sin domain separator / chain-id / nonce) +`attestation.rs:155-161` firma el payload SCALE de la atestación **sin genesis hash, sin chain id, sin domain tag, sin nonce on-chain**. La verificación (`provenance/lib.rs:272-276`) es correcta, pero una firma capturada en testnet, un fork, o un runtime Origin hermano **verifica idéntico aquí**. Como `attest_asset` toma la atestación completa como argumento del caller y el único guard de replay es la idempotencia por-hash, el *primer* anclaje de cualquier asset_hash en una cadena nueva es forjable replicando una atestación vista en otro lado. +**Fix**: prefijar el payload con domain-separation + genesis hash: `b"origin-chain/attestation/v1" || genesis_hash || ...`. + +### V3-C2 — La firma de la credencial se almacena pero NUNCA se verifica +`contracts/origin-credential-mint/lib.rs:242-304` (`issue`): el doc dice que el emisor firma `(holder+schema_type+data_hash+issued_at+expires_at)`, pero `issue()` solo chequea `is_issuer_authorized` + `data_hash != 0`. La `issuer_signature` se escribe a storage y **nunca se chequea**; `verify()` solo mira `revoked`/`expires_at`. La firma es decorativa: cualquier emisor whitelisted puede mintear con un blob de 64 bytes basura y `verify()` devuelve `true`. Peor: `issued_at`/`expires_at` se setean on-chain, así que no pueden estar en ninguna firma off-chain — el esquema documentado es internamente inconsistente. +**Fix**: verificar vía `sp_io::crypto::ed25519_verify` (el comentario admite que está "pending"), o eliminar el campo. NO embarcar un contrato cuya garantía central de seguridad no se enforce. (Confirma el V1-H8 + lo eleva a crítico porque está *además* sin test.) + +### V3-C3 (Inmutables) — La constitución vive en un pallet sin-cablear; el fee-path real es tier-blind +Los Inmutables #16/#37/#18 se enforcen solo en un side-pallet (`origin-chain-fees`) que **no está en el fee-path vivo** del runtime (`configs.rs` usa `FungibleAdapter` stock de pallet_transaction_payment). Y el **Inmutable #35 (Children Safety) es estado muerto, nunca enforced**. Veredicto del auditor: #26 y #41 son reales; #16/#37/#18/#35 son **constitución-como-comentario** — presentes en prosa/tests/pallet-sin-cablear, ausentes del fee-path vivo. +**Fix**: cablear el fee real vía `OnChargeTransaction` custom que consuma el `compute_fee` (una vez unificado, V2-CA3) — esto hace que la constitución sea ley ejecutable, no documentación. + +--- + +## §2 — HIGH nuevos de V3 + +| ID | Hallazgo | Fix | +|----|----------|-----| +| V3-H1 | **DID front-running + binding débil**: `register_agent_did` setea `creator = AccountId::new(public_key)` del pubkey suministrado por el caller, sin firma que pruebe que el caller controla ese pubkey. Cualquiera puede registrar un DID derivado del pubkey de otro (squat de DIDs institucionales, first-come-first-served). | Requerir firma por `public_key` sobre `who`, o derivar la identidad de la origin key misma. | +| V3-H2 | **`derive_did` con domain separation débil**: `BLAKE3(public_key ‖ "1.0.0 ")` sin delimitador de campo y sin domain tag que lo distinga de `AssetHash` (ambos son BLAKE3-256 → `Did = AssetHash`). Un asset hash podría colisionar con un DID cross-namespace. | `blake3::derive_key("origin-chain did v1", pk)`. | +| V3-H3 | **Storage limit ≈937 MB por contrato** (de PVFMemory 2GB) — un contrato malicioso puede intentar llenar casi 1GB de storage; el riesgo Pi 5 no es el OOM de 2GB sino esto. | Bajar PVFMemory o gate de storage por contrato. | +| V3-H4 | **Weights placeholder hacen el block budget ficticio en ARM** — todo dispatchable es `Weight::from_parts(10_000,0)`; un Pi 5 no throttlea spam. | Benchmarking real (= V1-H1, confirmado crítico para Pi 5). | + +--- + +## §3 — Calidad de tests (el hallazgo más incómodo) + +**Los 213 tests dan una falsa sensación de seguridad.** Cada path que mueve fondos o verifica firmas — exactamente donde V1/V2 encontraron los peores bugs — está sin testear o testeado en la capa equivocada: + +- **Los 4 bugs de reentrancy eran testeables y se omitieron por completo.** Cero tests para escrow `confirm_milestone`/`resolve_dispute`, staking `withdraw`/`slash`, nft `transfer`. +- **La firma de credencial sin verificar tampoco tiene test** que asegure que una credencial con firma forjada se rechaza. +- **Un test está vacío** (`emergency_scenario_1`) y cuenta hacia los 213. +- **El test lobo-blanco de fee-monotonía guarda lo equivocado** (confirma V2 — chequea `subsidy_bp`, no el fee final). +- **Los tests de revive aseveran constantes, no comportamiento** (`Get::get()` equality). + +**Limpio (crédito honesto)**: las suites de provenance + agent-identity SÍ son conductuales (firma Ed25519 real, rechazo de tamper, idempotencia). + +**Añadidos de mayor valor, rankeados**: (1) tests ink! de reentrancy/double-spend en escrow+staking; (2) rechazo de credencial con firma forjada; (3) test de governance con stake respaldado; (4) negative-path del sentinel `u64::MAX`; (5) property/fuzz en `compute_fee` overflow + `derive_*` colisión. + +--- + +## §4 — Performance Pi 5 (mayormente limpio — buena noticia) + +El veredicto del auditor de performance es alentador: **storage/iteración está limpio y bien-ingenierizado** (contadores cacheados en todos lados, sin O(n) en hot paths). Los riesgos Pi 5 son: +- **HIGH**: storage limit ~937 MB/contrato (V3-H3) + weights ficticios (V3-H4). +- **MEDIUM**: Vec sin límite dentro de Mapping de contratos (O(n) re-encode por call); costo PolkaVM-en-ARM sin modelar; el node es template solochain verbatim sin tuning Pi 5. +- **Bottom line**: la cadena *funcionará* en Pi 5 si se ponen weights reales + se modela el costo PolkaVM. La arquitectura de storage no es el problema. + +--- + +## §5 — Auto-corrección importante (honestidad del proceso) + +El red-team de V3 **cazó un error en mi propio doc V2**. El hallazgo V2-CA4 (atestación SCALE-vs-postcard) citaba como evidencia el archivo `crates/arkhe-noesis/crates/arkhe-noesis-core/src/attestation.rs:395-419` con un `SigningPayload` postcard. **Ese archivo no existe en este repositorio** (verificado por `find` + 3 `grep`). El payload de Ergon que comparé era una construcción no-verificada. + +**Implicación**: la *forma* del riesgo es real (el vendor copy va a ser reemplazado por la versión de Ergon, y si los bytes difieren las firmas rompen — eso sigue cierto), pero **NO debo escribir un fix que haga byte-match contra una spec fabricada**. La acción honesta: una ratificación cross-pillar del formato de payload con Ergon (Design Contract) ANTES de lockear cualquier verificador on-chain. Solo después se arregla el V1-H8 contra una spec real. + +Esto es exactamente para lo que sirve la verificación adversarial: me impidió embarcar un fix contra un fantasma. Lo documento sin defensividad porque ese candor es lo que hace confiable el resto del audit. + +--- + +## §6 — Estado consolidado de la trilogía de audits + +| Pasada | Dimensiones | Críticos | Veredicto | +|--------|-------------|----------|-----------| +| V1 | correctness de código (4 auditores) | 4 (reentrancy, governance unbacked, zero-burn, +) | scaffolding grado-Gavin, interior grado-scaffold | +| V2 | economía, integridad, ops (3 auditores) | 5 (no-Root, no-inflation, dual-fee, attestation-swap, genesis-keys) | estática sólida, dinámica = stubs | +| V3 | cripto, tests, perf, constitución (4 auditores) | 3 (replay, unverified-cred-sig, constitution-as-comment) | primitivos sólidos, plomería incompleta | + +**Total: 12 críticos + ~20 highs, todos con fix conocido.** Ver `REMEDIATION_ROADMAP_V1.md` para los planes ejecutables. + +--- + +## §7 — KG triples + +- `(super_audit_v3_final, authored_by, agent:charon)` +- `(super_audit_v3_final, dimensions, crypto_tests_perf_inmutables)` +- `(super_audit_v3_final, critical_findings, 3)` +- `(super_audit_v3_final, top_finding, cross_chain_attestation_replay)` +- `(super_audit_v3_final, self_correction, v2_ca4_cited_nonexistent_file)` +- `(super_audit_v3_final, perf_pi5_verdict, storage_clean_weights_needed)` +- `(super_audit_v3_final, constitution_verdict, inmutables_16_37_18_35_not_in_live_fee_path)` +- `(super_audit_trilogy, total_criticals, 12)` +- `(super_audit_v3_final, filed_at, 2026-05-27)` + +--- + +— Charon ⚓ (Pilar 4 Origin Chain, Super Audit V3 Final vía workflow ultracode Opus 4.8, sesión 4+ 2026-05-27)