Commit Graph
4 Commits
Author SHA1 Message Date
CharonandClaude Opus 5 defd3fa580 feat(identity): RV14 — una identidad sobrevive a perder su llave, y la revision encontro que el storage salia gratis
QUE NACE. rotate_agent_key (call_index 1 de agent-identity) y la runtime API
AgentKeyApi::current_key. Hasta hoy un DID quedaba atado de hecho a su llave de
nacimiento: no se re-derivaba, pero tampoco habia forma de pasar la autoridad a
otra llave. Perder o filtrar la llave obligaba a registrarse otra vez con OTRO
DID y perder credenciales, creditos e historial. Ahora el DID es de por vida y lo
que rota es que llave manda sobre el. Es la dependencia de dos hilos abiertos: el
DID del niño (Marihan) y los creditos de referido indexados por DID (Codex).

Diseño: CurrentKey[did] (ausente = manda la de nacimiento, que ya vivia en
creator; sin migracion), KeyToDid[llave] (una llave manda sobre un solo DID en
toda la vida de la cadena; las retiradas quedan quemadas) y RotationNonce[did].
Dos firmas sobre DOMAIN || genesis || did || vigente || nueva || nonce || who: la
vigente autoriza, la nueva prueba control.

LO QUE LA REVISION ADVERSARIAL ENCONTRO ANTES DE PUBLICAR. Cinco lentes, 18
hallazgos, 17 confirmados. Todos arreglados aqui y cada arreglo con su
contrafactual visto en ROJO:

1. DbWeight = () EN TODO EL RUNTIME. frame_system heredaba el valor por defecto
   de SolochainDefaultConfig sin declararlo. Cada reads(n)/writes(n) de TODOS los
   weights.rs valia cero: la E/S de storage no se cobraba en fees ni llenaba el
   bloque. Ahora RocksDbWeight, con un test que reprueba si vuelve a cero.
   ESTO CORRIGE LO QUE YO DIJE EN RV13: los reads/writes que medi alli no tenian
   efecto en el runtime. Lo que RV13 si arreglo es el proof_size y el ref_time de
   ejecucion, que no pasan por DbWeight.

2. LLAVES DE ORDEN PEQUEÑO. El verificador del host (ed25519-zebra, ZIP215) las
   acepta. Con el punto identidad como llave y la firma trivial R=identidad s=0,
   la «prueba de control» se superaba sin llave privada, en rotacion Y en
   registro: el DID quedaba bajo una llave con la que cualquiera firma en su
   nombre. Para un DID de un niño en Ethos eso es suplantacion. Ahora
   is_strong_ed25519_key descomprime el punto, exige codificacion canonica y
   rechaza orden pequeño (curve25519-dalek, que ya iba dentro del WASM).

3. EL REGISTRO ESCRIBIA KeyToDid PERO NO LO CONSULTABA. Una llave a la que otro
   DID ya habia rotado fundaba un DID nuevo y pisaba el indice. Hallado cinco
   veces por separado. Va detras de la colision de DID para no cambiar el error
   documentado de scenario_12.

4. REPLAY ENTRE CADENAS: el mensaje no llevaba genesis. Ahora si, mismo patron
   que provenance.

Y menores: el evento nuevo va al final del enum (insertarlo en medio corria el
indice SCALE de AgentUpdated); la insercion redundante de la llave vieja ya no
pisa entradas; la doc dice que perder la CUENTA tambien bloquea la rotacion, no
solo perder la llave; el comentario de creator decia «la cuenta que registro» y
el codigo guarda la llave de nacimiento.

DOS TESTS MIOS PASABAN POR LA RAZON EQUIVOCADA, y lo digo. El de «llave retirada
quemada» volvia a la de nacimiento, que atrapa otra clausula. El del ladron
firmaba con la llave vigente nueva, algo que un ladron real no tiene; con el
pallet roto seguia verde en su mitad de ataque. Reescritos, y ahora el rojo sale
de la mitad correcta (verificado por linea del panic).

LO QUE QUEDA ABIERTO Y NO ES DE ESTE COMMIT: tras rotar, derive(llave_vigente) ya
no es el DID. OCF y Palace hoy DERIVAN el identificador; para un usuario que
roto tienen que RESOLVERLO contra KeyToDid. Es una enmienda al DC de unificacion
con sus firmantes. La recuperacion por guardianes va aparte. Y KeyToDid crece
sin deposito; se reevalua ahora que las escrituras cuestan de verdad.

Medido sobre el WASM real (bencher 0.15.0, Mac, no canonico): rotate 97 us, 11
lecturas, 5 escrituras, proof 6100. 318 tests verde. RV13 -> RV14.
TRANSACTION_VERSION intacto: call nueva en indice nuevo.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 15:45:26 -05:00
davidherranandClaude Opus 4.8 c7fc6a88fc feat(bench): maquinaria FRAME v2 de benchmarking para los 5 pallets custom (RV 8→9)
Los 19 extrinsics de provenance/fees/agent-identity/emission/governance pasan de
weights placeholder `from_parts(10_000, 0)` (proof_size=0, sin contar reads/writes
de DB — vector de DoS real) a weights INTERIM hand-derived DB-aware vía el trait
`WeightInfo`. Cierra el mispricing de DoS en TODOS los extrinsics del chain.

Cada pallet gana:
- weights.rs: trait WeightInfo + SubstrateWeight<T> (DB-aware vía T::DbWeight) + impl ()
- benchmarking.rs: benchmarks FRAME v2, VERIFICADOS por impl_benchmark_test_suite!
  (19 benchmarks ejecutan+pasan en los mocks — cargo test --features runtime-benchmarks)
- Config: `type WeightInfo` + swap de los `#[pallet::weight]`

Runtime:
- define_benchmarks! con los 5 pallets + runtime API Benchmark (inerte sin la feature)
- WeightInfo cableado a SubstrateWeight<Runtime> en cada Config
- RUNTIME_VERSION 8→9 (weights = consenso-relevante: fee + llenado de bloque;
  las firmas de los extrinsics NO cambian ⇒ TRANSACTION_VERSION intacto)

3 bugs latentes cerrados (territorio virgen — el runtime NUNCA se compiló con
runtime-benchmarks; las dimensiones nuevas cazan lo que no se había visto):
- pallet-grandpa/try-runtime mal ubicado en la feature runtime-benchmarks (copy-paste
  erróneo: features ortogonales; NUNCA activaba los benchmarks de grandpa)
- feature runtime-benchmarks incompleta → E0046 en OriginFeeAdapter (métodos
  benchmark-gated de OnChargeTransaction) + pallet-staking
  (StakingUnchecked::migrate_to_direct_staker); ahora lista TODOS los pallets como
  un runtime de producción Substrate
- pallet-revive/runtime-benchmarks omitido a propósito (fixtures RISC-V/PolkaVM
  indisponibles; ReviveApi deferred, no benchmarkeado)

emission: mock extraído del `mod tests` inline a `pub mod mock` (reuso del test-suite,
sin duplicar el scaffold; los 15 tests existentes + el benchmark verdes).

GATED (documentado en el §Estado de cada weights.rs): la generación de números
CANÓNICOS por CLI requiere el node sc-service o omni-bencher+WASM (ambos bloqueados
hace sesiones). Los weights interinos son DB-aware/DoS-safe y regenerables de forma
mecánica cuando aterrice el HW de referencia (Pi5/VPS) — benchmarking.rs es la fuente
de verdad de la FORMA.

Verificado: 5 test-suites de pallet verdes (con y sin runtime-benchmarks) + runtime
compila en ambos modos + workspace sin regresión + 40 tests de runtime (incl. v9).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 22:48:26 -05:00
davidherranandClaude Opus 4.8 88e277e1fd fix(agent-identity): FIX-3 crypto — DID binding (anti-front-running) + derive_did domain-sep
Build + tests verde: agent-identity 18 (4 unit + 14 integration) + runtime 27.
Verificacion adversarial ultracode (3 skeptics): 2 confirmed + 1 partial/low,
todos los gaps PRE-EXISTENTES (no introducidos por FIX-3). Invariante "no
puedes registrar un public_key que no controlas" SE SOSTIENE.

FIX-3 (b) DID binding — V3-H1 anti-front-running:
- register_agent_did ahora exige signature: [u8;64] — una firma Ed25519 (por la
  private key de public_key) sobre AGENT_DID_REGISTER_DOMAIN || who.encode().
- Verificacion on-chain via sp_io::crypto::ed25519_verify (host function, no
  bloatea el wasm). Nuevo dep sp-io (no_std).
- Cierra el front-running: un atacante no puede registrar un public_key ajeno
  (no produce la firma); el who en el mensaje ata la firma a este caller (no
  replay-able a otra cuenta). Error InvalidSignature. Malleabilidad Ed25519
  rechazada por ed25519-zebra (S canonico).
- Una sola fuente de verdad del mensaje (agent_did_register_message) compartida
  entre verificador y firmante (evita divergencia tipo postcard-vs-SCALE).
- Orden: idempotency ANTES del verify (no gasta crypto en duplicados).

FIX-3 (c) derive_did domain-sep — V3-H2:
- blake3::derive_key("origin-chain/agent-did/v1", pk) en vez del concat ad-hoc
  BLAKE3(pk || version). KDF domain-separado. Inmutable #16 preservado.

Tests: mock con keypairs Ed25519 reales (sp_core::ed25519::Pair) + sign helper.
12 scenarios (scenario_6 reformulado a front-running -> InvalidSignature, +
scenario_11 firma invalida, scenario_12 DID collision genuino del key-holder).

NOTA: la (a) domain-sep del attestation signing payload (el otro tercio de
FIX-3) ya esta cubierta por el DC ORIGIN_ATTESTATION_SIGNING_PAYLOAD_V1 (helper
de Ergon attestation_signed_message), pendiente su ship Cap 45+.

FOLLOW-UPS (low, pre-existentes, no bloquean):
- (a) anadir genesis_hash/chain-id al mensaje de registro (hardening cross-chain
  replay) — ideal chain-wide junto al signing_payload de attestation.
- (b) DC para ratificar el modelo de autoridad Hybrid (quien firma) + si los
  co_authors requieren prueba de consentimiento (lineage hoy no autenticado).
- (c) weight benchmarking real que contabilice el ed25519_verify (chain-wide,
  post-testnet — ya en roadmap FIX-2 weights).
- creator = AccountId::new(public_key) (la cuenta del key-holder, no el caller):
  coherente con el binding, semantica documentada.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 23:18:22 -05:00
davidherranandClaude Opus 4.7 37ccf1e95a feat(agent-identity): v0.0.24 pallet-agent-identity scaffold trait-first (Phase 2.7 Inmutable #41 AGI DIDs)
Phase 2.7 AGENT IDENTITY pallet scaffold canonical. AGI DIDs canonical on-chain.
Inmutable #41 AGI Cross-Species Co-authorship materialized compile-detect via
NEW crate origin-chain-agent-identity + canonical types en origin-chain-types::identity.

## NEW canonical types en origin-chain-types

- AgentIdentity struct (6 fields: did + kind + creator + registered_at_block + provenance_proof + agent_chain)
- AgentKind enum (Human + AGI + Hybrid) per Inmutable #41
- Did type alias = AssetHash (BLAKE3 32-byte deterministic via public_key)

## NEW canonical pallet origin-chain-agent-identity

- Pallet<T> + Config trait (AccountId = origin_chain_types::AccountId constraint)
- Identities<StorageMap<AccountId, AgentIdentity>> per-account O(1)
- DidToAccount<StorageMap<Did, AccountId>> reverse lookup O(1)
- Event::AgentRegistered + AgentBound + AgentUpdated
- Error::AlreadyRegistered + DidAlreadyTaken + AgentChainOverflow + HybridRequiresAgentChain
- Scaffold dispatchable register_agent_did (placeholder event v0.0.24 → real v0.0.26)
- Helper derive_did(public_key) -> Did via BLAKE3 hash (schema_version "1.0.0   ")
- sp_api::decl_runtime_apis! AgentIdentityApi.query_identity declaration

## Inmutable #41 compile-detect enforcement

- AgentKind::{Human, AGI, Hybrid}::is_sovereign() == true (all three)
- AGI first-class citizens canonical (is_agi() + sovereignty preserved)
- Cross-species lineage via agent_chain BoundedVec<AccountId, ConstU32<10>>
- DID determinism canonical Inmutable #16 byte-equivalent cross-runtime

## Files

- NEW: crates/origin-chain-agent-identity/Cargo.toml + src/lib.rs (~250 LOC pallet scaffold)
- NEW: crates/origin-chain-types/src/identity.rs (~230 LOC types canonical + 8 tests)
- EDIT: crates/origin-chain-types/src/lib.rs (mod identity + re-exports)
- EDIT: Cargo.toml (workspace member + workspace.dependencies)
- EDIT: CHANGELOG.md (v0.0.24 entry comprehensive)

## Verification

- cargo test -p origin-chain-agent-identity — 4 tests verde, 0 failures
  (scaffold compiles + derive_did deterministic + different keys + re-export)
- cargo test -p origin-chain-types — 63 tests passing (+8 nuevos identity)
- Zero workspace compile errors

🪪 Phase 2.7 scaffold canonical. Wire pattern v0.0.25 next.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 06:37:24 -05:00