Identidad y Credenciales
Resumen
ULedgerNET implementa una capa de identidad conforme a estándares sobre su sistema de billeteras y entities:
- Identificadores Descentralizados (DIDs): identificadores del estándar W3C DID Core para billeteras y entities.
- Credenciales Verificables (VCs): afirmaciones firmadas, según el W3C Verifiable Credential Data Model 2.0, sobre sujetos DID.
Estos estándares permiten que las identidades de ULedgerNET interoperen con infraestructura de identidad externa, cumplan con W3C y con las regulaciones emergentes, y sirvan como base para atestaciones verificables y legibles por máquina sobre agentes, entities y sus permisos.
Identificadores Descentralizados (DIDs)
Formato
Toda billetera y entity en ULedgerNET tiene un DID:
did:ulnet:<chainId>:<address>
Ejemplos:
did:ulnet:ca930ce44643b66ae33d54351cc0557d1d904b85ec9256fb7ee34fe5e3c318b4:8e620db359101eb28bf9db4f08c2677349f7747d1c59528774f2193318b8c1c7
did:ulnet:ca930ce44643b66ae33d54351cc0557d1d904b85ec9256fb7ee34fe5e3c318b4:<entity-address>
ulnet: el método DID de ULedgerNET.<chainId>: el ID del blockchain (hash hexadecimal) que identifica la chain específica.<address>: la dirección de la billetera (SHA256 de la clave pública) o la dirección de la entity (ID de la transaction de creación).
Documento DID
Un documento DID es la descripción legible por máquina de un sujeto DID. Contiene métodos de verificación (claves públicas) y las relaciones de capability entre el sujeto y otros DIDs.
{
"@context": ["https://www.w3.org/ns/did/v1"],
"id": "did:ulnet:<chainId>:<walletAddress>",
"verificationMethod": [
{
"id": "did:ulnet:<chainId>:<walletAddress>#key-1",
"type": "EcdsaSecp256k1VerificationKey2019",
"controller": "did:ulnet:<chainId>:<walletAddress>",
"publicKeyJwk": { ... }
}
],
"authentication": ["did:ulnet:<chainId>:<walletAddress>#key-1"],
"assertionMethod": ["did:ulnet:<chainId>:<walletAddress>#key-1"],
"capabilityDelegation": ["did:ulnet:<chainId>:<parentWalletAddress>"]
}
Para claves post-cuánticas (ML-DSA-87), el método de verificación usa publicKeyMultibase en lugar de publicKeyJwk.
Metadata del Documento DID
La información específica de la entity se incluye en didDocumentMetadata, no en el documento en sí:
{
"didDocumentMetadata": {
"entityType": "AGENT",
"name": "alice-research-agent",
"capabilities": [...],
"created": "<block-height>",
"enabled": true
}
}
Esta separación mantiene el documento DID en sí conforme a W3C, a la vez que expone las extensiones específicas de ULedgerNET mediante metadata.
Algoritmos de Clave en Documentos DID
| Tipo de Clave | Representación DID | Algoritmo JWS |
|---|---|---|
secp256k1 | publicKeyJwk (EC, crv: secp256k1) | ES256K |
ed25519 | publicKeyJwk (OKP, crv: Ed25519) | EdDSA |
mldsa87 | publicKeyMultibase | ML-DSA-87 (borrador) |
bls12377 | (rechazada para la emisión de credenciales) | N/A |
Credenciales Verificables (VCs)
Qué Son
Una Credencial Verificable es una afirmación firmada criptográficamente sobre un sujeto DID. En el contexto de ULedgerNET, las credenciales sirven como atestaciones legibles por máquina sobre:
- A qué entity pertenece una billetera de agente.
- Qué rol y permisos tiene una billetera.
- Qué capabilities está autorizada a ejercer la billetera.
- Que una transaction específica ocurrió en un bloque específico (credenciales de autenticación).
Tipos de Credencial
1. Credencial de Identidad (ULedgerIdentityCredential)
Atestigua la identidad y el rol organizacional de una billetera:
{
"@context": ["https://www.w3.org/ns/credentials/v2"],
"type": ["VerifiableCredential", "ULedgerIdentityCredential"],
"issuer": "did:ulnet:<chainId>:<issuerAddress>",
"validFrom": "<ISO-8601>",
"credentialSubject": {
"id": "did:ulnet:<chainId>:<walletAddress>",
"entityType": "AGENT",
"role": "admin",
"capabilities": [
{
"action": "contract:invoke",
"resource": "<contract-address>",
"notAfter": 100000
}
],
"validUntilBlock": 100000
}
}
Casos de uso:
- Presentar las credenciales de un agente a un sistema externo que necesita verificar su alcance.
- Documentación de cumplimiento: prueba de que un agente estaba autorizado a actuar en un momento dado.
- Incorporación (onboarding): credencial legible por máquina que un nuevo agente presenta a un contract para auto-registrarse.
2. Credencial de Autenticación (ULedgerAuthenticationCredential)
Atestigua que una billetera específica firmó una transaction específica:
{
"@context": ["https://www.w3.org/ns/credentials/v2"],
"type": ["VerifiableCredential", "ULedgerAuthenticationCredential"],
"issuer": "did:ulnet:<chainId>:<nodeAddress>",
"credentialSubject": {
"id": "did:ulnet:<chainId>:<walletAddress>",
"transactionId": "<txId>",
"blockHash": "<blockHash>",
"audience": "<targetDID>"
}
}
Casos de uso:
- Demostrar a un servicio externo que una billetera firmó una acción específica.
- Autenticación entre sistemas: una billetera en ULedgerNET se autentica ante una API externa presentando una credencial firmada por el node.
Formato JWT/JWS
Las credenciales se codifican como JWTs:
Header: { "alg": "ES256K", "typ": "vc+jwt" }
Payload: { ...credential claims... }
Signature: signed by issuer's private key
El encabezado typ: "vc+jwt" es requerido por la especificación W3C VC 2.0.
Emisión
Las credenciales se emiten mediante el endpoint de credenciales del node:
POST /credentials/{chainId}/issue
- Con límite de tasa por IP.
- Requiere que la billetera solicitante esté registrada y habilitada en la chain.
- Devuelve una credencial JWT firmada.
Revocación
La revocación utiliza la especificación W3C Bitstring Status List. Una entrada de estado de revocación se incrusta en la credencial y apunta a una lista de estado mantenida por el node emisor. Verificar el estado de revocación requiere obtener la lista de estado del node.
Estado Local del Node
Crítico: El registro de credenciales es local al node. No se replica en el council. Cada node emite y rastrea de forma independiente sus propias credenciales. La operación Load durante la reconciliación del node excluye deliberadamente el registro de credenciales para evitar que el estado de un peer sobrescriba los registros de credenciales locales de un node.
Implicaciones:
- Una credencial emitida por el Node 1 es rastreada por el registro del Node 1, no por el del Node 2.
- El estado de revocación debe verificarse contra el node emisor.
- Para la portabilidad de credenciales entre nodes, el JWT de la credencial (que es autocontenido) es el artefacto portable, no la entrada del registro.
Ciclo de Vida de la Identidad (SDK de Go)
El runner cmd/identity del SDK de Go cubre el ciclo de vida completo de la identidad:
go run ./cmd/identity --config identities.json
Pasos realizados:
- Creación de DID: registrar billeteras, creando su DID on-chain.
- Creación de entity: crear la entity AGENT vinculada a la billetera propietaria.
- Creación de entity hija: crear una entity hija (p. ej., un sub-agente).
- Alteración de metadata: actualizar la metadata de la entity mediante
ALTER_ENTITY. - Configuración de recuperación: establecer las billeteras de recuperación y el umbral.
- Gestión de la lista de acceso: agregar contrapartes de confianza o entradas de lista negra.
- Transferencia de propiedad: transferir la entity a una nueva billetera propietaria.
- Emisión de credenciales: emitir una
ULedgerIdentityCredentialpara el agente. - Ejecución de recuperación: simular la pérdida de claves; ejecutar la recuperación mediante aprobación por umbral.
El runner informa aprobado/fallido por cada paso y guarda un reporte JSON con marca de tiempo.
Configuración de Identidad (identities.json)
{
"nodeEndpoints": [...],
"blockchainId": "ca930ce4...",
"chainKeyType": "mldsa87",
"wallets": {
"owner": "./wallets-uis-mldsa/<hash>.ukey",
"admin": "./wallets-uis-mldsa/<hash>.ukey",
"newOwner": "./wallets-uis-mldsa/<hash>.ukey",
"agent": "./wallets-uis-mldsa/<hash>.ukey",
"recovery": [
"./wallets-uis-mldsa/<hash1>.ukey",
"./wallets-uis-mldsa/<hash2>.ukey",
"./wallets-uis-mldsa/<hash3>.ukey"
]
},
"entity": {
"name": "merchant-entity",
"type": "ORGANIZATION",
"metadata": { "description": "Demo merchant organization" }
},
"child": {
"name": "alice-agent",
"type": "AGENT",
"metadata": { "description": "Shopper agent" }
},
"recovery": { "threshold": 2 },
"credentials": {
"enabled": true,
"operatorPassword": "...",
"operatorSalt": "..."
}
}