El verificador attestation queda VIVO: una firma producida por el código
REAL de Ergon (arkhe-noesis-core, postcard + mensaje domain-separado)
verifica byte-fiel en el pallet Substrate. Cierra el FIX-DEFERRED del
roadmap (helper de Ergon ya en árbol) + el replay cross-chain V3-C1.
origin-chain-types/attestation_verify.rs (nuevo):
- ATTESTATION_DOMAIN_TAG + attestation_signed_message: espejo BYTE-IDÉNTICO
del oráculo (DC 076d15cc ASP-3). Mensaje = TAG ‖ genesis_hash(32) ‖ payload.
- decode_signing_payload: lector postcard SECUENCIAL total y estricto del
SigningPayload de Ergon (sin dep nueva en el runtime wasm frágil). Lectores
varint u64/u32 con los bounds exactos de postcard (cierra el LOW de fidelidad
flagged: verdict/severity/constraints son u32, máx 5 bytes / 5º ≤ 15).
Cotas DoS en strings. NUNCA re-serializa (contrato ASP-3).
pallet-origin-provenance:
- attest_asset(signing_payload: BoundedVec<u8,512>, signature: [u8;64]):
recibe los bytes postcard OPACOS + la firma; decodifica, verifica Ed25519
vía sp_io::crypto::ed25519_verify (host function, no bloatea wasm, precedente
FIX-3) sobre el mensaje domain-separado con el genesis_hash de ESTA cadena.
La pubkey se decodifica del payload (no param aparte). creator = el validador,
anchored_at_block real (cerró los placeholders del scaffold).
- Dedup-by-BLAKE3 con rechazo EXPLÍCITO (asset_id = BLAKE3 content hash, dentro
del payload firmado → replay del mismo blob reusa el asset_id → AlreadyAttested).
Hallazgos de la verificación adversarial (workflow ultracode, 3 lentes)
cerrados de RAÍZ:
- HIGH asset-id squat / provenance poisoning + MEDIUM tier-forgery: el gate
era self-attested (level del payload) → cualquiera con una clave Ed25519
anclaba basura institucional bajo el hash PÚBLICO de un asset legítimo y lo
envenenaba de forma inmutable. FIX: registro on-chain AuthorizedValidators
(pubkey → nivel OIT) gobernado por Root (register_validator/revoke_validator);
la membresía es la VERDAD, no el payload. Mismo patrón que TierProfiles de
FIX-6 Stage 2a (legitimidad on-chain, no caller-supplied). Sunset a
attestation-driven cuando aterrice el registro OIT de Mathi.
- MEDIUM método muerto: removido el ValidationAttestation::signing_payload()
SCALE divergente (producía bytes que jamás verificarían — footgun).
Decisiones (autoridad Pilar 4): sp_io ed25519_verify (consistente FIX-3,
estándar Substrate) · dedup-by-asset_id subsume replay exacto · golden vectors
generados desde el oráculo REAL de Ergon (seed [7u8;32], genesis 0xAB) =
prueba cross-runtime.
PENDIENTE (gap legítimo, no bug): OriginChainAttestationSink (impl del trait
ValidationAttestationSink de Ergon) es código cliente off-chain — vive en un
crate bridge del monorepo (subxt), NO en el chain repo (dependency direction
submódulo→monorepo prohibida). Se cablea con la integración Noesis→chain.
Tests: 19 provenance (golden vectors cross-runtime + squat cerrado + revoke +
anti-replay cross/intra-chain + tamper + malformed) + 72 types (decoder fuzz-
equivalente a postcard + fidelidad u32) + 21 suites workspace verde. cargo +1.88.
WASM: build VPS-gated (UnknownOpcode 252 ambiental, ver v0.0.58).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>