feat(identity): UNA identidad para todo Origin — contexto KDF compartido (RV 9→10)
DC ORIGIN IDENTITY UNIFICATION V1 (Larihana), Opción A + enmienda D-ID-7 mía.
Ratificado por David 2026-07-28. Firmado approve (pendientes Larihana + Mathi).
EL PROBLEMA (medido por Larihana, verificado por mí en ambos lados):
chain: blake3::derive_key("origin-chain/agent-did/v1", pk) → Did
OCF: blake3::hash(pk) → OitFingerprint
La MISMA pubkey Ed25519 producía 32 bytes DISTINTOS en cada capa. No era un bug
de criptografía: cada capa hizo domain separation correctamente por separado y
nadie decidió la relación entre las dos. Consecuencia: viendo un fingerprint en
un canal de chat NO se podía resolver el DID on-chain sin la pubkey completa —
un usuario tenía una identidad en el chat y otra en la blockchain. Directiva de
David: "que todo lo que creamos tenga una misma identidad para poder acceder".
EL CAMBIO:
- Nueva constante pública ORIGIN_IDENTITY_KDF_CONTEXT = "origin/identity/v1",
el contexto CANÓNICO compartido por todas las capas de Origin.
- derive_did pasa a derivar con ese contexto ⇒ el identificador de 32 bytes es
ahora EL MISMO en chain, chat (OCF), assets y credenciales.
- RUNTIME_VERSION 9→10: cambia la transición de estado de register_agent_did (el
DID calculado y almacenado) ⇒ spec bump obligatorio. Las FIRMAS de los
extrinsics NO cambian ⇒ TRANSACTION_VERSION intacto.
POR QUÉ SIN MIGRACIÓN (la verificación que el DC me delegó, medida no asumida):
- Sin GenesisConfig en el pallet → no se siembran identidades en génesis.
- Sin DIDs en los 3 presets de génesis.
- Sin golden vectors ni DID hex hardcodeado en el repo.
- StorageVersion = 0, nunca migrado — greenfield puro.
- derive_did = UNA función, UN call-site; los tests lo invocan (no pinnean bytes).
⇒ Ningún estado on-chain dependía del esquema viejo. La ventana pre-mainnet
estaba abierta y el costo fue una constante de string.
ENMIENDA D-ID-7 — golden vectors cross-repo (lo que aporté al DC):
El DC arreglaba la INSTANCIA pero no la CLASE. Origin Chain es submódulo y NO
puede depender de arkhe-fabric-core (dep-direction submódulo→monorepo = ILEGAL,
la misma ley que impide el swap del attestation SSOT), así que las dos capas no
pueden compartir la constante por Cargo — y sin ancla podían volver a divergir en
silencio, que es justo el bug que cerramos. Añadidos 3 vectores pinneados a bytes
(2 patrones + 1 pubkey Ed25519 real) para que fabric-core pinnee LOS MISMOS.
Si cualquiera de los dos lados cambia el contexto o la función, su test falla.
Mismo patrón que ya nos salvó con el attestation SSOT: paridad por matemática,
no por disciplina humana.
NO VACUO — verificado empíricamente: saboteé el contexto a "v2-DRIFT" y AMBOS
tests fallaron con el diagnóstico correcto; restaurado, verdes de nuevo. (Un test
que pasa no prueba nada hasta que se le ve fallar sin el fix.)
TRADE-OFF asumido y dejado explícito en el acta del DC: un identificador único en
chat + chain + assets + credenciales implica que ver el fingerprint de alguien en
un canal permite resolver sus activos y transacciones on-chain — no hay frontera
de seudonimato entre capas. Es INHERENTE a "una identidad para todo"; la
alternativa (derivación por-contexto tipo HD) reintroduce los dos identificadores
en dos pantallas que justamente eliminamos. Decisión consciente, no efecto
secundario descubierto después.
Verificado: workspace completo verde (0 fallos), 20/20 en agent-identity.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
266ee4084d
commit
13f8ac00a5
2 files changed
+130
-11
No files matched your search
@@ -266,7 +266,16 @@ pub const IMPL_NAME: &str = "origin-chain-charon";
|
||||
/// Las FIRMAS de los extrinsics NO cambian ⇒ TRANSACTION_VERSION intacto. La feature
|
||||
/// `runtime-benchmarks` gana `define_benchmarks!` + runtime API `Benchmark` (inerte
|
||||
/// sin la feature) + fix del bug `pallet-grandpa/try-runtime` en la feature.
|
||||
pub const RUNTIME_VERSION: u32 = 9;
|
||||
///
|
||||
/// **v10 (identidad unificada)**: DC ORIGIN IDENTITY UNIFICATION V1 — `derive_did`
|
||||
/// pasa del contexto propio de la chain (`origin-chain/agent-did/v1`) al contexto
|
||||
/// COMPARTIDO `origin/identity/v1`, de modo que la misma pubkey Ed25519 produce EL
|
||||
/// MISMO identificador de 32 bytes en chain y en OCF (antes eran distintos: dos
|
||||
/// identidades para el mismo usuario). Cambia la transición de estado de
|
||||
/// `register_agent_did` (el DID calculado y almacenado) ⇒ spec bump obligatorio.
|
||||
/// Las FIRMAS de los extrinsics NO cambian ⇒ TRANSACTION_VERSION intacto. Sin
|
||||
/// migración: verificado que ningún estado on-chain dependía del esquema viejo.
|
||||
pub const RUNTIME_VERSION: u32 = 10;
|
||||
|
||||
/// Canonical authoring version per Substrate semver canonical.
|
||||
pub const AUTHORING_VERSION: u32 = 1;
|
||||
@@ -925,13 +934,14 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn runtime_version_v9_benchmarking_weights() {
|
||||
// v9 = benchmarking real machinery: los 19 extrinsics de los 5 pallets
|
||||
// custom pasan de weights placeholder (proof_size=0, DoS) a weights INTERIM
|
||||
// hand-derived DB-aware vía WeightInfo. Los weights son consenso-relevantes
|
||||
// (fee + llenado de bloque) ⇒ spec bump. Las FIRMAS de los extrinsics NO
|
||||
// cambian ⇒ TRANSACTION_VERSION intacto.
|
||||
assert_eq!(RUNTIME_VERSION, 9);
|
||||
fn runtime_version_v10_unified_identity() {
|
||||
// v10 = DC ORIGIN IDENTITY UNIFICATION V1: derive_did usa el contexto KDF
|
||||
// COMPARTIDO `origin/identity/v1` → la misma pubkey Ed25519 produce el
|
||||
// MISMO identificador de 32 bytes en chain y en OCF. Cambia la transición
|
||||
// de estado de register_agent_did ⇒ spec bump. Las FIRMAS de los extrinsics
|
||||
// NO cambian ⇒ TRANSACTION_VERSION intacto.
|
||||
// (v9 fue la maquinaria de benchmarking: weights INTERIM DB-aware.)
|
||||
assert_eq!(RUNTIME_VERSION, 10);
|
||||
assert_eq!(TRANSACTION_VERSION, 1);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user