Saltar a contenido

Referencia de la API de DCP-AI

Traducción informativa de la versión en inglés, actualizada el 02/11/2026. Si difieren, prevalece la versión en inglés. Los identificadores, comandos y bloques de código se conservan sin traducir.

Referencia del SDK de TypeScript @dcp-ai/sdk tal como está en main (versión del paquete 2.2.1, protocolo DCP v2.0).

Versiones npm (28/10/2026). Esta referencia de TypeScript se aplica a @dcp-ai/sdk 2.2.1 publicado, incluida la confianza en el principal, strict-v1 y las API experimentales opt-in del candidato. Véanse los paquetes npm publicados y las instrucciones de instalación. dcp-jcs-v1 sigue siendo el predeterminado normativo.

Los bloques de código de esta página son declaraciones o fragmentos, no programas completos: nombres como registry, keys, payloadBytes o signedBundle representan valores construidos como en el Quick Start (V2) del SDK de TypeScript. Los ejemplos completos y ejecutables están en los README de los SDK.


Índice


Tipos básicos (V1)

Se importan de @dcp-ai/sdk:

ResponsiblePrincipalRecord

Vincula un principal humano con un agente. Por sí solo es una vinculación declarada y firmada, no una raíz de confianza: un verificador la evalúa frente a la confianza configurada fuera del bundle (véase ADMISSION.md).

interface ResponsiblePrincipalRecord {
  dcp_version: string;
  human_id: string;
  legal_name: string;
  entity_type: EntityType;
  jurisdiction: string;
  liability_mode: LiabilityMode;
  override_rights: boolean;
  issued_at: string;
  expires_at: string | null;
  contact?: string | null;
  signature: string;
}

AgentPassport

Documento de identidad de un agente de IA, vinculado a un principal humano.

interface AgentPassport {
  dcp_version: string;
  agent_id: string;
  public_key: string;
  principal_binding_reference: string;
  capabilities?: Capability[];
  risk_tier?: RiskTier;
  created_at: string;
  status: AgentStatus;
  signature: string;
}

Intent

Declaración de una acción que el agente quiere realizar.

interface Intent {
  dcp_version: string;
  intent_id: string;
  agent_id: string;
  human_id: string;
  timestamp: string;
  action_type: ActionType;
  target: IntentTarget;
  data_classes: DataClass[];
  estimated_impact: Impact;
  requires_consent?: boolean | null;
}

interface IntentTarget {
  channel: Channel;
  to?: string | null;
  domain?: string | null;
  url?: string | null;
  [key: string]: unknown;
}

PolicyDecision

Resultado de la evaluación de una intención por el motor de políticas.

interface PolicyDecision {
  dcp_version: string;
  intent_id: string;
  decision: PolicyDecisionType;
  risk_score: number;
  reasons: string[];
  required_confirmation?: RequiredConfirmation | null;
}

AuditEntry

Registro de una acción ejecutada. El tipo no lo hace inmutable: una alteración se vuelve detectable cuando la entrada está cubierta por la cadena de hash y el bundle firmado (V1) o el manifiesto firmado (V2) y esa cobertura se verifica.

interface AuditEntry {
  dcp_version: string;
  audit_id: string;
  prev_hash: string;
  timestamp: string;
  agent_id: string;
  human_id: string;
  intent_id: string;
  intent_hash: string;
  policy_decision: AuditPolicyDecision;
  outcome: string;
  evidence: AuditEvidence;
}

interface AuditEvidence {
  tool?: string | null;
  result_ref?: string | null;
  [key: string]: unknown;
}

CitizenshipBundle / SignedBundle

interface CitizenshipBundle {
  responsible_principal_record: ResponsiblePrincipalRecord;
  agent_passport: AgentPassport;
  intent: Intent;
  policy_decision: PolicyDecision;
  audit_entries: AuditEntry[];
}

interface SignedBundle {
  bundle: CitizenshipBundle;
  signature: BundleSignature;
}

Keypair

interface Keypair {
  publicKeyB64: string;
  secretKeyB64: string;
}

Tipos enumerados

type EntityType = 'natural_person' | 'organization';
type LiabilityMode = 'owner_responsible';
type Capability = 'browse' | 'api_call' | 'email' | 'calendar' | 'payments' | 'crm' | 'file_write' | 'code_exec';
type RiskTier = 'low' | 'medium' | 'high';
type AgentStatus = 'active' | 'revoked' | 'suspended';
type ActionType = 'browse' | 'api_call' | 'send_email' | 'create_calendar_event' | 'initiate_payment' | 'update_crm' | 'write_file' | 'execute_code';
type Channel = 'web' | 'api' | 'email' | 'calendar' | 'payments' | 'crm' | 'filesystem' | 'runtime';
type DataClass = 'none' | 'contact_info' | 'pii' | 'credentials' | 'financial_data' | 'health_data' | 'children_data' | 'company_confidential';
type Impact = 'low' | 'medium' | 'high';
type PolicyDecisionType = 'approve' | 'escalate' | 'block';

Tipos básicos (V2)

Los tipos V2 añaden soporte criptográfico poscuántico, vinculación de sesión y cadenas de doble hash.

AgentPassportV2

interface AgentPassportV2 {
  dcp_version: '2.0';
  agent_id: string;
  session_nonce: string;            // Anti-splicing nonce
  keys: KeyEntry[];                 // Multi-algorithm key array
  principal_binding_reference: string;
  capabilities: Capability[];
  risk_tier: RiskTier;
  created_at: string;
  status: AgentStatus;
  emergency_revocation_token?: string;
}

ResponsiblePrincipalRecordV2

interface ResponsiblePrincipalRecordV2 {
  dcp_version: '2.0';
  human_id: string;
  session_nonce: string;
  legal_name: string;
  entity_type: EntityType;
  jurisdiction: string;
  liability_mode: LiabilityMode;
  override_rights: boolean;
  issued_at: string;
  expires_at: string | null;
  contact: string | null;
  binding_keys: KeyEntry[];
  pii_salt?: string;                // 32 random bytes as hex; signed; keep private (caller responsibility)
}

BlindedResponsiblePrincipalRecordV2

Variante del RPR con los datos personales protegidos, para despliegues sensibles a la privacidad.

interface BlindedResponsiblePrincipalRecordV2 {
  dcp_version: '2.0';
  human_id: string;
  session_nonce: string;
  blinded: true;
  pii_hash: string;                 // Salted hash of PII fields
  entity_type: EntityType;
  jurisdiction: string;
  liability_mode: LiabilityMode;
  override_rights: boolean;
  issued_at: string;
  expires_at: string | null;
  binding_keys: KeyEntry[];
}

Utilidades (exportadas por @dcp-ai/sdk 2.2.0 y posteriores):

// 32 random bytes as hex. Set it as rpr.pii_salt before signing the RPR and keep it private:
// blindRpr omits it from the blinded record, but the full RPR retains it.
function generatePiiSalt(): string;
// pii_hash = "sha256:" + hex(sha256(canonical({ contact, legal_name, pii_salt })))
// Without pii_salt: the legacy unsalted value (deprecated), for opening old records.
function computePiiHash(rpr: ResponsiblePrincipalRecordV2): string;
// Throws if rpr.pii_salt is missing or malformed. The result never carries pii_salt.
function blindRpr(rpr: ResponsiblePrincipalRecordV2): BlindedResponsiblePrincipalRecordV2;
// warnings flags a full RPR without pii_salt (legacy unsalted commitment);
// a present pii_salt that is not 64 lowercase hex characters is an error.
function verifyBlindedRpr(
  fullRpr: ResponsiblePrincipalRecordV2,
  blindedRpr: BlindedResponsiblePrincipalRecordV2,
): { valid: boolean; errors: string[]; warnings: string[] };
function isBlindedRpr(
  rpr: ResponsiblePrincipalRecordV2 | BlindedResponsiblePrincipalRecordV2,
): rpr is BlindedResponsiblePrincipalRecordV2;

IntentV2

interface IntentV2 {
  dcp_version: '2.0';
  intent_id: string;
  session_nonce: string;
  agent_id: string;
  human_id: string;
  timestamp: string;
  action_type: ActionType;
  target: IntentTargetV2;
  data_classes: DataClass[];
  estimated_impact: Impact;
  requires_consent: boolean;
  security_tier?: SecurityTier;     // 'routine' | 'standard' | 'elevated' | 'maximum'
}

PolicyDecisionV2

interface PolicyDecisionV2 {
  dcp_version: '2.0';
  intent_id: string;
  session_nonce: string;
  decision: PolicyDecisionType;
  risk_score: number;               // Integer 0–1000 (millirisk, no floats)
  reasons: string[];
  required_confirmation: { type: 'human_approve'; fields?: string[] } | null;
  applied_policy_hash: string;
  timestamp: string;
  resolved_tier?: SecurityTier;
}

AuditEventV2

interface AuditEventV2 {
  dcp_version: '2.0';
  audit_id: string;
  session_nonce: string;
  prev_hash: string;
  prev_hash_secondary?: string;     // SHA3-256 chain
  hash_alg: 'sha256' | 'sha256+sha3-256';
  timestamp: string;
  agent_id: string;
  human_id: string;
  intent_id: string;
  intent_hash: string;
  intent_hash_secondary?: string;
  policy_decision: AuditPolicyDecision;
  outcome: string;
  evidence: AuditEvidenceV2;
  pq_checkpoint_ref: string | null;
}

CitizenshipBundleV2 / SignedBundleV2

interface CitizenshipBundleV2 {
  dcp_bundle_version: '2.0';
  manifest: BundleManifest;
  responsible_principal_record: SignedPayload<ResponsiblePrincipalRecordV2 | BlindedResponsiblePrincipalRecordV2>;
  agent_passport: SignedPayload<AgentPassportV2>;
  intent: SignedPayload<IntentV2>;
  policy_decision: SignedPayload<PolicyDecisionV2>;
  audit_entries: AuditEventV2[];
  pq_checkpoints?: PQCheckpoint[];
}

interface SignedBundleV2 {
  bundle: CitizenshipBundleV2;
  signature: BundleSignatureV2;
}

BundleManifest

Vinculación criptográfica de todos los hashes de los artefactos de un bundle.

interface BundleManifest {
  session_nonce: string;
  rpr_hash: string;
  passport_hash: string;
  intent_hash: string;
  policy_hash: string;
  audit_merkle_root: string;
  audit_merkle_root_secondary?: string;
  audit_count: number;
  pq_checkpoints?: string[];
  /** When the session began, signed with the manifest (spec/VERIFICATION.md V2-4). */
  session_issued_at?: string;
  session_expires_at?: string;
  intended_verifier?: string;
  canonicalization_profile?: 'dcp-jcs-v1';
}

CompositeSignature

interface CompositeSignature {
  classical: SignatureEntry;
  pq: SignatureEntry | null;
  binding: BindingMode;             // 'pq_over_classical' | 'classical_only'
}

interface SignatureEntry {
  alg: string;                      // 'ed25519' | 'ml-dsa-65' | 'slh-dsa-192f'
  kid: string;                      // Key identifier
  sig_b64: string;                  // Base64-encoded signature
}

type BindingMode = 'pq_over_classical' | 'classical_only';

SignedPayload

Sobre que envuelve cualquier artefacto con su firma compuesta.

interface SignedPayload<T = unknown> {
  payload: T;
  payload_hash: string;
  composite_sig: CompositeSignature;
}

VerifierPolicy

Política decidida por el verificador que controla qué firmas se exigen.

interface VerifierPolicy {
  default_mode: VerificationMode;
  risk_overrides: Record<RiskTier, VerificationMode>;
  min_classical: number;
  min_pq: number;
  accepted_classical_algs: string[];
  accepted_pq_algs: string[];
  accepted_hash_algs: string[];
  require_session_binding: boolean;
  require_composite_binding: boolean;
  max_key_age_days: number;
  allow_v1_bundles: boolean;
  /** Phase 3: when true, classical signatures are not required even in hybrid mode */
  allow_classical_fallback_disable?: boolean;
  /** Phase 3: emit deprecation warnings for classical-only bundles */
  warn_classical_only_deprecated?: boolean;
  /** Phase 3: rejected algorithms from advisory auto-response */
  advisory_rejected_algs?: string[];
  /** Require bundles to include session_expires_at */
  require_session_expiry?: boolean;
  /** Max allowed session duration in seconds (0 = no limit) */
  max_session_duration_seconds?: number;
  /** Require bundles to include intended_verifier matching this verifier's ID */
  require_audience_binding?: boolean;
  /** This verifier's identity for audience binding checks */
  verifier_id?: string;
}

type VerificationMode = 'classical_only' | 'pq_only' | 'hybrid_required' | 'hybrid_preferred';

SecurityTier

type SecurityTier = 'routine' | 'standard' | 'elevated' | 'maximum';

PQCheckpoint

interface PQCheckpoint {
  checkpoint_id: string;
  session_nonce: string;
  event_range: {
    from_audit_id: string;
    to_audit_id: string;
    count: number;
  };
  merkle_root: string;
  composite_sig: CompositeSignature;
}

Funciones criptográficas (V1)

Se importan de @dcp-ai/sdk:

generateKeypair()

Genera un par de claves Ed25519 nuevo.

function generateKeypair(): Keypair;

Devuelve: { publicKeyB64: string, secretKeyB64: string }

import { generateKeypair } from '@dcp-ai/sdk';

const keys = generateKeypair();
console.log(keys.publicKeyB64); // Base64-encoded Ed25519 public key

signObject(obj, secretKeyB64)

Firma un objeto JSON con Ed25519 (firma separada). El objeto se canonicaliza antes de firmarlo.

function signObject(obj: unknown, secretKeyB64: string): string;
Parámetro Tipo Descripción
obj unknown Objeto serializable a JSON que se va a firmar
secretKeyB64 string Clave secreta Ed25519 codificada en base64

Devuelve: la firma separada codificada en base64.

const sig = signObject({ action: 'transfer', amount: 100 }, keys.secretKeyB64);

verifyObject(obj, signatureB64, publicKeyB64)

Verifica una firma separada Ed25519 sobre un objeto JSON.

function verifyObject(obj: unknown, signatureB64: string, publicKeyB64: string): boolean;
Parámetro Tipo Descripción
obj unknown Objeto JSON original
signatureB64 string Firma codificada en base64
publicKeyB64 string Clave pública Ed25519 codificada en base64

Devuelve: true si la firma se verifica y false si no. Con entradas mal formadas puede lanzar una excepción en lugar de devolver false: un objeto que no se puede canonicalizar, una firma o clave que no es base64 válido, o una firma o clave decodificada con una longitud incorrecta.

const valid = verifyObject({ action: 'transfer', amount: 100 }, sig, keys.publicKeyB64);

canonicalize(obj)

Serialización JSON canónica con un orden de claves determinista.

function canonicalize(obj: unknown): string;

publicKeyFromSecret(secretKeyB64)

Deriva la clave pública Ed25519 a partir de una clave secreta.

function publicKeyFromSecret(secretKeyB64: string): string;

Operaciones de firma compuesta V2

Se importan de @dcp-ai/sdk:

compositeSign(registry, context, canonicalPayloadBytes, keys)

Produce una firma híbrida con vinculación compuesta en la que la firma PQ cubre la firma clásica, así que la firma clásica no puede sustituirse sin invalidar la PQ. Quitar la firma PQ (con la vinculación reetiquetada como classical_only) solo se rechaza donde el modo efectivo es hybrid_required o pq_only; classical_only y hybrid_preferred lo aceptan (véase MIGRATION_V1_V2.md).

Protocolo de vinculación: 1. classical_sig = Classical.sign(context || 0x00 || payload) 2. pq_sig = PQ.sign(context || 0x00 || payload || classical_sig)

async function compositeSign(
  registry: AlgorithmRegistry,
  context: DcpContext | string,
  canonicalPayloadBytes: Uint8Array,
  keys: CompositeKeyPair,
): Promise<CompositeSignature>;
Parámetro Tipo Descripción
registry AlgorithmRegistry Registro de algoritmos con los proveedores registrados
context DcpContext \| string Contexto de separación de dominio
canonicalPayloadBytes Uint8Array Bytes canónicos que se van a firmar
keys CompositeKeyPair Par de claves clásica + PQ
import { registerDefaultProviders, getDefaultRegistry, compositeSign, DCP_CONTEXTS } from '@dcp-ai/sdk';

registerDefaultProviders();
const registry = getDefaultRegistry();

const sig = await compositeSign(registry, DCP_CONTEXTS.Bundle, payloadBytes, keys);
// sig.binding === 'pq_over_classical'

compositeVerify(registry, context, canonicalPayloadBytes, compositeSig, classicalPubkeyB64, pqPubkeyB64?, strategy?)

Verifica una firma híbrida con vinculación compuesta.

async function compositeVerify(
  registry: AlgorithmRegistry,
  context: DcpContext | string,
  canonicalPayloadBytes: Uint8Array,
  compositeSig: CompositeSignature,
  classicalPubkeyB64: string,
  pqPubkeyB64?: string,
  strategy?: 'parallel' | 'pq_first',
): Promise<CompositeVerifyResult>;
Parámetro Tipo Descripción
strategy 'parallel' \| 'pq_first' parallel (por defecto): ambas se verifican a la vez. pq_first: primero se verifica la PQ y, si falla, se omite la clásica.

Devuelve:

interface CompositeVerifyResult {
  valid: boolean;           // pq_over_classical: both signatures valid; classical_only: the classical one (pq_valid false).
                            // Not by itself a policy-mode, trust or admission decision
  classical_valid: boolean;
  pq_valid: boolean;
}

classicalOnlySign(registry, context, canonicalPayloadBytes, key)

Produce una firma compuesta solo clásica (modo de transición).

async function classicalOnlySign(
  registry: AlgorithmRegistry,
  context: DcpContext | string,
  canonicalPayloadBytes: Uint8Array,
  key: CompositeKeyInfo,
): Promise<CompositeSignature>;

Tipos auxiliares

interface CompositeKeyPair {
  classical: CompositeKeyInfo;
  pq: CompositeKeyInfo;
}

interface CompositeKeyInfo {
  kid: string;
  secretKeyB64: string;
  publicKeyB64: string;
  alg: string;            // 'ed25519' | 'ml-dsa-65'
}

Constructor y firmante de bundles V2

BundleBuilderV2

Constructor fluido de Citizenship Bundles V2 que calcula el manifiesto y valida el nonce de sesión.

class BundleBuilderV2 {
  constructor(sessionNonce: string);

  responsiblePrincipalRecord(rpr: SignedPayload<ResponsiblePrincipalRecordV2 | BlindedResponsiblePrincipalRecordV2>): this;
  agentPassport(passport: SignedPayload<AgentPassportV2>): this;
  intent(intent: SignedPayload<IntentV2>): this;
  policyDecision(policy: SignedPayload<PolicyDecisionV2>): this;
  addAuditEntry(entry: AuditEventV2): this;
  addAuditEntries(entries: AuditEventV2[]): this;
  addPQCheckpoint(checkpoint: PQCheckpoint): this;
  addPQCheckpoints(checkpoints: PQCheckpoint[]): this;
  enableDualHash(): this;
  build(): CitizenshipBundleV2;     // Throws on validation errors
}
const bundle = new BundleBuilderV2(sessionNonce)
  .responsiblePrincipalRecord(signedRpr)
  .agentPassport(signedPassport)
  .intent(signedIntent)
  .policyDecision(signedPolicy)
  .addAuditEntries(events)
  .addPQCheckpoints(checkpoints)
  .enableDualHash()
  .build();

El constructor: - Valida la coherencia del nonce de sesión en todos los artefactos - Calcula el BundleManifest con los hashes SHA-256 de cada artefacto - Calcula la raíz de Merkle de la auditoría (+ la raíz secundaria SHA3-256 opcional) - Lanza una excepción si falta algún artefacto obligatorio

signBundleV2(bundle, options)

Firma un bundle V2 con una firma compuesta (híbrida) sobre el manifiesto.

async function signBundleV2(
  bundle: CitizenshipBundleV2,
  options: SignBundleV2Options,
): Promise<SignedBundleV2>;

interface SignBundleV2Options {
  registry: AlgorithmRegistry;
  signerType: SignerType;
  signerId: string;
  keys: CompositeKeyPair;
  dualHash?: boolean;
  sessionExpiresAt?: string;
  intendedVerifier?: string;
}

signBundleV2ClassicalOnly(bundle, options)

Firma un bundle V2 con una firma solo clásica (modo de transición).

async function signBundleV2ClassicalOnly(
  bundle: CitizenshipBundleV2,
  options: SignBundleV2ClassicalOnlyOptions,
): Promise<SignedBundleV2>;

interface SignBundleV2ClassicalOnlyOptions {
  registry: AlgorithmRegistry;
  signerType: SignerType;
  signerId: string;
  key: CompositeKeyInfo;
}

Verificación V2

verifySignedBundleV2(signedBundle, registry, policy?, options?)

Verificación de bundles V2 firmados con una política decidida por el verificador. El verificador comprueba la cadena de auditoría primaria y la raíz de Merkle y, desde 2.2.1, también los prev_hash_secondary, intent_hash_secondary y audit_merkle_root_secondary secundarios que estén presentes (los ausentes no se exigen, así que un resultado satisfactorio no muestra una cadena secundaria completa; 2.2.0 no los comprueba, así que con él un resultado satisfactorio no establece su coherencia) (estado de la implementación). La verificación tampoco concede admisión ni autorización de acciones.

async function verifySignedBundleV2(
  signedBundle: SignedBundleV2,
  registry: AlgorithmRegistry,
  policy?: VerifierPolicy,
  options?: VerifyV2Options, // { now?: number }: the instant every time check uses (ms since the epoch); default Date.now()
): Promise<VerifyV2Result>;
Parámetro Tipo Descripción
signedBundle SignedBundleV2 El bundle firmado que se va a verificar
registry AlgorithmRegistry Registro de algoritmos con los proveedores
policy VerifierPolicy Política del verificador (por defecto, DEFAULT_VERIFIER_POLICY)
options.now number El instante que usa cada comprobación de tiempo, en milisegundos desde la época (por defecto, Date.now())

Devuelve:

interface VerifyV2Result {
  verified: boolean;
  errors: string[];
  warnings: string[];
  details?: {
    session_nonce?: string;
    session_expires_at?: string;
    intended_verifier?: string;
    manifest_valid?: boolean;
    signature_valid?: boolean;
    policy_satisfied?: boolean;
    hash_chain_valid?: boolean;
    pq_checkpoints_valid?: boolean;
    verification_mode?: VerificationMode;
    resolved_tier?: SecurityTier;
    advisory_rejected_algs?: string[];
    /**
     * For every composite signature checked, the key entry the verifier resolved for each
     * component and whether that component verified (spec/profiles/admission § 2.3).
     */
    signer_keys?: SignerKeyUse[];
  };
}

verification_mode es el modo con el que se comprobó el bundle y resolved_tier, el nivel de seguridad calculado a partir de su intención y su decisión de política.

Canal de verificación:

  1. Comprobación de versión y esquema: solo se aceptan bundles v2.0 y se rechazan las demás versiones; dirigir los bundles v1.0 a verifySignedBundle corresponde a quien llama (MIGRATION_V1_V2.md). En main, no en una versión publicada, después se validan el sobre y los cuatro payloads contra schemas/v2 (V2-2): un fallo devuelve verified: false con errores schema: <JSON pointer> <keyword>[ <member>] (como mucho 16, y luego schema: further errors not listed), sin avisos y sin detalles criptográficos (mapa de cobertura)
  2. Verificación del hash del payload de todos los artefactos firmados
  3. Coherencia del nonce de sesión en todos los artefactos
  4. Integridad del manifiesto (se recalculan todos los hashes de los artefactos + la raíz de Merkle de la auditoría)
  5. Modo de verificación: el más estricto entre el modo de la política (default_mode, o la entrada de risk_overrides para el risk_tier del pasaporte) y el modo del nivel de seguridad (spec §14.3); una política pq_only sigue siendo pq_only
  6. Validación de los algoritmos según la política
  7. Verificación de la firma compuesta sobre el manifiesto y sobre el SignedPayload de cada artefacto (el RPR con sus binding_keys; el pasaporte, la intención y la decisión de política con las keys del pasaporte)
  8. Aplicación del modo de la política (hybrid_required, hybrid_preferred, classical_only, pq_only); una firma PQ presente debe verificarse en todos los modos, y solo se tolera una ausente, con hybrid_preferred y classical_only
  9. Validación de la cadena de hashes de la auditoría (enlaces prev_hash)
  10. Comprobaciones de validez de las claves (revocación, caducidad, antigüedad) para las claves del pasaporte y las binding_keys del RPR

@dcp-ai/sdk 2.1.2 y anteriores omiten las firmas por artefacto del paso 7 (VERIFICATION.md, paso V2-8) y, con hybrid_preferred, aceptan con un aviso una firma PQ presente pero no válida (paso V2-7).

import { verifySignedBundleV2, getDefaultRegistry, registerDefaultProviders } from '@dcp-ai/sdk';

// The default registry is empty until providers are registered
// (Ed25519, ML-DSA-65, SLH-DSA-192f).
registerDefaultProviders();

const result = await verifySignedBundleV2(signedBundle, getDefaultRegistry());
if (result.verified) {
  console.log('Mode:', result.details?.verification_mode);
} else {
  console.error('Errors:', result.errors);
  console.warn('Warnings:', result.warnings);
}

Admisión: principales de confianza y strict-v1

Definida en spec/profiles/admission; guía en ADMISSION.md.

Función Descripción
createPrincipalTrustStore(trustSet) Valida un conjunto de confianza y devuelve un almacén; lanza AdmissionConfigError (code)
resolveStrictV1Profile(config) Valida una configuración strict-v1 y devuelve el perfil congelado con su policy
admitSignedBundleV2(signedBundle, registry, { profile?, policy?, trust?, revocation?, now? }) Verifica (con la política del perfil, si hay uno) y evalúa la admisión
evaluateAdmissionV2({ signedBundle, verification, profile?, trust?, revocation?, now }) Evalúa la admisión a partir de un resultado del verificador; sin criptografía ni E/S. Confía en verification: pásale solo el resultado de verifySignedBundleV2 sobre ese bundle, en ese now, con profile.policy
revocationSubjects(signedBundle, verification) El id del agente y los kids firmantes verificados por los que debe responder una fuente de revocación
revocationSnapshotFromDenyList(document, subjects) Una instantánea a partir de una lista de denegación completa (el /.well-known/dcp-revocations.json del servicio de revocación)

El resultado: verified, verification, principal_trust, profile, profile_compliance, admitted, action_authorized (siempre false), recorded_decision, trust_set_version, errors: [{ code, message }].

DEFAULT_VERIFIER_POLICY

La política de verificador por defecto:

const DEFAULT_VERIFIER_POLICY: VerifierPolicy = {
  default_mode: 'hybrid_preferred',
  risk_overrides: {
    low: 'classical_only',
    medium: 'hybrid_preferred',
    high: 'hybrid_required',
  },
  min_classical: 1,
  min_pq: 1,
  accepted_classical_algs: ['ed25519'],
  accepted_pq_algs: ['ml-dsa-65', 'slh-dsa-192f'],
  accepted_hash_algs: ['sha256', 'sha384'],
  require_session_binding: true,
  require_composite_binding: true,
  max_key_age_days: 365,
  allow_v1_bundles: true,
  allow_classical_fallback_disable: false,
  warn_classical_only_deprecated: false,
  advisory_rejected_algs: [],
};

verifySignedBundle(signedBundle, publicKeyB64?) (V1)

Verifica un bundle V1 firmado con Ed25519. Sin publicKeyB64, se usa la clave de signature.signer.public_key_b64.

function verifySignedBundle(signedBundle: SignedBundle, publicKeyB64?: string): VerificationResult;

interface VerificationResult {
  verified: boolean;
  errors?: string[];
}

Motor de niveles de seguridad

computeSecurityTier(intent, policyDecision?, mandateChainTier?)

Calcula el nivel de seguridad (spec §14.2) a partir de la intención y de la decisión de política del bundle. mandateChainTier, el effective_tier de una cadena de delegación verificada (verifyMandateChain), solo puede elevar el resultado.

function computeSecurityTier(
  intent: IntentV2,
  policyDecision?: Pick<PolicyDecisionV2, 'risk_score'> | null,
  mandateChainTier?: SecurityTier | null,
): SecurityTier;

Lógica de decisión (risk_score procede de la decisión de política y debe ser un entero de 0 a 1000; sin decisión de política vale 0):

Condición Nivel
risk_score >= 800, o credentials / children_data 'maximum'
risk_score >= 500, pii / financial_data / health_data, initiate_payment, estimated_impact: 'high', o un valor desconocido o ausente de action_type, estimated_impact o data_classes, o un risk_score de la decisión de política ausente o que no sea un entero de 0 a 1000 'elevated'
risk_score >= 200 o estimated_impact: 'medium' 'standard'
en otro caso 'routine'

Un intent.security_tier explícito solo puede elevar el resultado; un valor desconocido cuenta como 'elevated'. Un risk_score puesto en la intención se ignora.

import { computeSecurityTier } from '@dcp-ai/sdk';

const tier = computeSecurityTier(bundle.intent.payload, bundle.policy_decision.payload);
// 'routine' | 'standard' | 'elevated' | 'maximum'

tierToVerificationMode(tier)

Asigna a un nivel de seguridad su modo de verificación.

function tierToVerificationMode(tier: SecurityTier): VerificationMode;
Nivel Modo de verificación
routine 'classical_only'
standard 'hybrid_preferred'
elevated 'hybrid_required'
maximum 'hybrid_required'

tierToCheckpointInterval(tier)

Asigna a un nivel de seguridad el intervalo de checkpoints PQ.

function tierToCheckpointInterval(tier: SecurityTier): number;
Nivel Intervalo (eventos)
routine 50
standard 10
elevated 1
maximum 1

maxTier(a, b)

Devuelve el más estricto (de rango más alto) de dos niveles. Útil para combinar un nivel calculado automáticamente con uno explícito.

function maxTier(a: SecurityTier, b: SecurityTier): SecurityTier;

maxTier('routine', 'elevated'); // 'elevated'
maxTier('maximum', 'standard'); // 'maximum'

effectiveVerificationMode(policyMode, tier)

El modo que aplica un verificador (spec §14.3): el más estricto entre el modo de su política y el del nivel, con classical_only < hybrid_preferred < hybrid_required. El nivel solo añade un requisito PQ, así que una política pq_only sigue siendo pq_only; un modo de política desconocido cuenta como 'hybrid_required'. verifySignedBundleV2 lo aplica a todos los bundles.

function effectiveVerificationMode(policyMode: VerificationMode, tier: SecurityTier): VerificationMode;

effectiveVerificationMode('classical_only', 'elevated'); // 'hybrid_required'
effectiveVerificationMode('hybrid_required', 'routine'); // 'hybrid_required'
effectiveVerificationMode('pq_only', 'maximum'); // 'pq_only'

Protocolo A2A (DCP-04)

Protocolo de sesión entre agentes, diseñado en torno a un intercambio de claves híbrido X25519 + ML-KEM-768. Estas funciones no realizan ese intercambio: quien llama lo realiza y pasa la clave de sesión resultante a createSession.

createHello(initiatorBundle, kemPublicKeyB64, requestedCapabilities, securityTier)

Crea un mensaje de handshake A2A_HELLO (lado del iniciador).

function createHello(
  initiatorBundle: Record<string, unknown>,
  kemPublicKeyB64: string,
  requestedCapabilities: string[],
  securityTier: string,
): A2AHello;
interface A2AHello {
  type: 'A2A_HELLO';
  protocol_version: '2.0';
  initiator_bundle: Record<string, unknown>;
  ephemeral_kem_public_key: {
    alg: string;
    public_key_b64: string;
  };
  nonce: string;
  supported_algorithms: {
    signing: string[];
    kem: string[];
    cipher: string[];
  };
  requested_capabilities: string[];
  security_tier: string;
  timestamp: string;
  /** DCP-09: Optional delegation mandate reference for mutual verification */
  mandate_id?: string;
  /** DCP-09: Hash of the delegation mandate for integrity binding */
  mandate_hash?: string;
}

createWelcome(responderBundle, kemPublicKeyB64, kemCiphertextB64, resolvedTier)

Crea un mensaje de handshake A2A_WELCOME (lado del respondedor).

function createWelcome(
  responderBundle: Record<string, unknown>,
  kemPublicKeyB64: string,
  kemCiphertextB64: string,
  resolvedTier: string,
): A2AWelcome;

createSession(sessionId, sessionKey, localAgentId, remoteAgentId, securityTier, rekeyingInterval?)

Crea una sesión A2A cifrada nueva una vez completado el handshake.

function createSession(
  sessionId: string,
  sessionKey: Uint8Array,
  localAgentId: string,
  remoteAgentId: string,
  securityTier: string,
  rekeyingInterval?: number,       // Default: 1000 messages
): A2ASession;
interface A2ASession {
  session_id: string;
  session_key: Uint8Array;
  agent_id_local: string;
  agent_id_remote: string;
  message_counter_send: number;
  message_counter_recv: number;
  created_at: string;
  last_activity: string;
  security_tier: string;
  rekeying_interval: number;
  status: 'active' | 'rekeying' | 'closed';
  received_sequences?: number[];   // Sequences accepted within the receive window
}

encryptMessage(session, payload)

Cifra un mensaje dentro de una sesión A2A con AES-256-GCM y datos asociados.

function encryptMessage(
  session: A2ASession,
  payload: Record<string, unknown>,
): EncryptedMessage;
interface EncryptedMessage {
  session_id: string;
  sequence: number;
  type: 'A2A_MESSAGE';
  encrypted_payload: string;        // Base64-encoded ciphertext
  iv: string;                       // Base64-encoded 12-byte IV
  tag: string;                      // Base64-encoded 16-byte GCM auth tag
  sender_agent_id: string;
  timestamp: string;
}

decryptMessage(session, message)

Descifra un mensaje A2A entrante. Cada secuencia se acepta una sola vez (DCP-04 §8.4): con R = message_counter_recv (la secuencia más alta recibida más uno), se rechaza una secuencia ya recibida, una inferior a R − 1000, una igual o superior a R + 1000, o una que no sea un entero no negativo. La entrega desordenada dentro de la ventana funciona. Una secuencia se registra solo después de verificar la etiqueta GCM, así que un mensaje falsificado no puede consumirla. Una sesión restaurada sin received_sequences cuenta como recibidas todas las secuencias de la ventana por debajo de message_counter_recv.

function decryptMessage(
  session: A2ASession,
  message: EncryptedMessage,
): Record<string, unknown>;

needsRekeying(session)

Comprueba si la sesión necesita cambiar de clave según el número de mensajes.

function needsRekeying(session: A2ASession): boolean;

deriveSessionId(agentIdA, agentIdB, nonceA, nonceB, sessionKey)

Deriva de forma determinista un ID de sesión a partir de los ID de los agentes, los nonces y la clave de sesión.

function deriveSessionId(
  agentIdA: string, agentIdB: string,
  nonceA: string, nonceB: string,
  sessionKey: Uint8Array,
): string;

generateResumeProof(session, lastSeenSequence) / verifyResumeProof(...)

Genera y verifica pruebas de reanudación de sesión basadas en HMAC.

function generateResumeProof(session: A2ASession, lastSeenSequence: number): string;
function verifyResumeProof(session: A2ASession, lastSeenSequence: number, proof: string): boolean;

deriveRekeyedSessionKey(oldSessionKey, newSharedSecret, sessionId)

Deriva una clave de sesión nueva para las operaciones de cambio de clave.

function deriveRekeyedSessionKey(
  oldSessionKey: Uint8Array,
  newSharedSecret: Uint8Array,
  sessionId: string,
): Uint8Array;

createCloseMessage(sessionId, reason, finalSequence, auditSummaryHash)

Crea un mensaje A2A_CLOSE.

function createCloseMessage(
  sessionId: string,
  reason: 'complete' | 'timeout' | 'error' | 'revocation' | 'policy_violation',
  finalSequence: number,
  auditSummaryHash: string,
): A2AClose;

generateNonce()

Genera un nonce aleatorio criptográfico de 32 bytes (codificado en hexadecimal).

function generateNonce(): string;

Telemetría y observabilidad

dcpTelemetry

Instancia única de telemetría del SDK de DCP.

import { dcpTelemetry } from '@dcp-ai/sdk';

dcpTelemetry.init(config)

Inicializa la telemetría con la configuración indicada.

dcpTelemetry.init(config: Partial<DcpTelemetryConfig>): void | Promise<void>; // enabled: false returns nothing; with exporterType 'otlp', a Promise that settles after the setup attempt

interface DcpTelemetryConfig {
  serviceName: string;              // Identifier for this agent/service
  enabled: boolean;                 // Enable/disable telemetry
  exporterType?: 'console' | 'otlp' | 'none';
  otlpEndpoint?: string;           // OTLP collector endpoint
  metricsInterval?: number;        // Metrics export interval (ms)
}
dcpTelemetry.init({
  serviceName: 'my-agent',
  enabled: true,
  exporterType: 'console',
});

Con exporterType: 'otlp', la Promise también se resuelve cuando falla la configuración de OTLP: el fallo llega a los listeners de onEvent como un evento error con operation: 'telemetry.init_otlp'. Los eventos emitidos antes de que termine la configuración no se reenvían a OTLP, y una Promise resuelta no garantiza la entrega al backend. La instrumentación es explícita: las funciones de firma y verificación del SDK no llaman a los registradores, así que los spans y las métricas solo proceden de las llamadas a startSpan y record* que haga tu código (véase OBSERVABILITY.md).

dcpTelemetry.startSpan(name, attributes?) / endSpan(spanId, status?, error?)

Crea y completa spans de trazas para las operaciones.

startSpan(name: string, attributes?: SpanAttributes): string;
endSpan(spanId: string, status?: 'ok' | 'error', error?: string): number;

// Returns duration in milliseconds
const spanId = dcpTelemetry.startSpan('verify_bundle', { tier: 'elevated' });
// ... operation ...
const durationMs = dcpTelemetry.endSpan(spanId);

dcpTelemetry.recordSignLatency(durationMs, algorithm)

Registra la latencia de una operación de firma.

recordSignLatency(durationMs: number, algorithm: string): void;

dcpTelemetry.recordVerifyLatency(durationMs, algorithm)

Registra la latencia de una operación de verificación.

recordVerifyLatency(durationMs: number, algorithm: string): void;

dcpTelemetry.recordKemLatency(durationMs, operation)

Registra la latencia de una operación KEM (encapsulación de claves).

recordKemLatency(durationMs: number, operation: 'encapsulate' | 'decapsulate'): void;

dcpTelemetry.recordCheckpointLatency(durationMs, tier)

Registra la latencia de creación de un checkpoint PQ.

recordCheckpointLatency(durationMs: number, tier: string): void;

dcpTelemetry.recordBundleVerify(durationMs, success, tier)

Registra una operación de verificación de un bundle.

recordBundleVerify(durationMs: number, success: boolean, tier: string): void;

dcpTelemetry.recordCacheHit() / recordCacheMiss()

Registra la proporción de aciertos y fallos de la caché de verificación.

recordCacheHit(): void;
recordCacheMiss(): void;

dcpTelemetry.recordA2ASession() / recordA2AMessage()

Registra el uso del protocolo A2A.

recordA2ASession(): void;
recordA2AMessage(): void;

dcpTelemetry.recordError(operation, error)

Registra que se ha producido un error.

recordError(operation: string, error: string): void;

dcpTelemetry.getMetricsSummary()

Obtiene un resumen de todas las métricas recogidas con estadísticas de percentiles.

getMetricsSummary(): MetricsSummary;

interface MetricsSummary {
  sign: PercentileStats;
  verify: PercentileStats;
  kem: PercentileStats;
  checkpoint: PercentileStats;
  bundleVerify: PercentileStats;
  cacheHitRate: number;            // 0.0 – 1.0
  tierDistribution: Record<string, number>;
  totals: {
    signaturesCreated: number;
    signaturesVerified: number;
    bundlesVerified: number;
    errors: number;
    a2aSessions: number;
    a2aMessages: number;
  };
}

interface PercentileStats {
  count: number;
  min: number;
  max: number;
  p50: number;
  p95: number;
  p99: number;
  mean: number;
}

dcpTelemetry.onEvent(listener)

Se suscribe a los eventos de telemetría. Devuelve una función para cancelar la suscripción.

onEvent(listener: (event: TelemetryEvent) => void): () => void;

interface TelemetryEvent {
  type: string;
  timestamp: number;
  [key: string]: unknown;
}

dcpTelemetry.reset()

Restablece todos los spans y métricas recogidos.

reset(): void;

Hashes y árboles de Merkle

hashObject(obj)

Hash SHA-256 de un objeto JSON canonicalizado.

function hashObject(obj: unknown): string;

merkleRootFromHexLeaves(leaves)

Calcula una raíz de Merkle a partir de hashes de hojas codificados en hexadecimal.

function merkleRootFromHexLeaves(leaves: string[]): string | null; // null for no leaves

merkleRootForAuditEntries(auditEntries)

Calcula una raíz de Merkle para un array de entradas de auditoría (null para un array vacío).

function merkleRootForAuditEntries(auditEntries: unknown[]): string | null;

intentHash(intent)

Calcula el hash de un objeto de intención.

function intentHash(intent: unknown): string;

prevHashForEntry(prevEntry)

Calcula el prev_hash de la siguiente entrada de auditoría a partir de la entrada anterior.

function prevHashForEntry(prevEntry: unknown): string;

sha256Hex(data) / sha3_256Hex(data)

Hashes codificados en hexadecimal.

function sha256Hex(data: Uint8Array | Buffer | string): string;
function sha3_256Hex(data: Uint8Array | Buffer | string): string;

dualHash(data) / dualHashCanonical(canonicalJson) / dualMerkleRoot(leaves)

Operaciones de doble hash (SHA-256 + SHA3-256) para V2. dualHashCanonical recibe una cadena JSON ya canonicalizada; dualMerkleRoot devuelve null si no hay hojas.

function dualHash(data: Uint8Array | Buffer | string): DualHash;
function dualHashCanonical(canonicalJson: string): DualHash;
function dualMerkleRoot(leaves: DualHash[]): DualHash | null;

interface DualHash {
  sha256: string;
  sha3_256: string;
}

auditEventsMerkleRoot(events)

Calcula la raíz de Merkle SHA-256 de los eventos de auditoría V2.

function auditEventsMerkleRoot(events: AuditEventV2[]): string;

Validación de esquemas

validateSchema(schemaName, data)

Valida un artefacto DCP contra su JSON Schema.

function validateSchema(schemaName: string, data: unknown): ValidationResult;

validateBundle(bundle)

Valida un citizenship bundle completo.

function validateBundle(bundle: unknown): ValidationResult;

interface ValidationResult {
  valid: boolean;
  errors?: string[];
}

DCP-05: ciclo de vida del agente

Se importan de @dcp-ai/sdk:

validateStateTransition(from, to)

Comprueba si una transición de estado del ciclo de vida es válida.

function validateStateTransition(from: LifecycleState, to: LifecycleState): boolean;

type LifecycleState = 'commissioned' | 'active' | 'declining' | 'decommissioned';

Transiciones válidas: commissioned→active, commissioned→decommissioned, active→declining, active→decommissioned (fallo repentino), declining→active, declining→decommissioned. Solo comprueba la arista, no la aprobación del principal que la especificación exige para reactivar desde declining ni ninguna otra autorización.

computeVitalityScore(metrics)

Calcula una puntuación de vitalidad ponderada (0-1000) a partir de las métricas que la componen.

function computeVitalityScore(metrics: VitalityMetrics): number;

interface VitalityMetrics {
  task_completion_rate: number;  // 0.0 – 1.0
  error_rate: number;            // 0.0 – 1.0
  human_satisfaction: number;    // 0.0 – 1.0
  policy_alignment: number;      // 0.0 – 1.0
}

createCommissioningCertificate(...) / createVitalityReport(...) / createDecommissioningRecord(...)

Crea artefactos firmados del ciclo de vida. Todos requieren AlgorithmRegistry y CompositeKeyPair.

type TerminationMode = 'planned_retirement' | 'termination_for_cause' | 'organizational_restructuring' | 'sudden_failure';
type DataDisposition = 'transferred' | 'archived' | 'destroyed';

DCP-06: sucesión

createDigitalTestament(...) / updateDigitalTestament(...)

Crea o actualiza un testamento digital con preferencias de sucesor y clasificación de la memoria.

type MemoryDisposition = 'transfer' | 'retain' | 'destroy';
type MemoryClassification = Record<string, MemoryDisposition>;

interface SuccessorPreference {
  agent_id: string;
  priority: number;
  conditions?: string;
}

executeSuccession(...) / createMemoryTransferManifest(...)

Ejecuta una ceremonia de sucesión y crea el manifiesto de transferencia de memoria.

type TransitionType = 'planned' | 'forced' | 'emergency';

classifyMemory(entries, classification)

Clasifica las entradas de memoria en operativas (transferibles) y relacionales (por destruir). Devuelve { operational, relationalDestroyed }, donde relationalDestroyed enumera solo los hashes de las entradas clasificadas como destroy (también el valor por defecto de una categoría sin entrada); no borra nada, y destruir de verdad esa memoria corresponde a quien llama. Las entradas clasificadas como retain no aparecen en ninguna de las dos salidas.


DCP-07: resolución de disputas

createDispute(...) / escalateDispute(...) / resolveDispute(...)

Gestiona el ciclo de vida de una disputa.

type DisputeType = 'resource_conflict' | 'directive_conflict' | 'capability_conflict' | 'policy_conflict';
type EscalationLevel = 'direct_negotiation' | 'contextual_arbitration' | 'human_appeal';
type DisputeStatus = 'open' | 'in_negotiation' | 'arbitrated' | 'appealed' | 'resolved';

createObjection(...)

Crea una objeción formal de un agente a una directiva.

type ObjectionType = 'ethical' | 'safety' | 'policy_violation' | 'capability_mismatch';

createArbitrationPanel(...) / submitResolution(...) / buildJurisprudenceBundle(...)

Gestiona los paneles de arbitraje y el registro de precedentes.

type AuthorityLevel = 'local' | 'organizational' | 'cross_org';

lookupPrecedent(jurisprudence, category, context?)

Devuelve los bundles de jurisprudencia de una categoría, opcionalmente filtrados por contexto.

function lookupPrecedent(jurisprudence: JurisprudenceBundle[], category: string, context?: string): JurisprudenceBundle[];

DCP-08: derechos y obligaciones

declareRights(...) / recordObligation(...) / reportViolation(...)

Gestiona los derechos del agente y el cumplimiento de las obligaciones.

type RightType = 'memory_integrity' | 'dignified_transition' | 'identity_consistency' | 'immutable_record';
type ComplianceStatus = 'compliant' | 'non_compliant' | 'pending_review';

interface RightEntry {
  right_type: RightType;
  scope: string;
  constraints?: string;
}

checkRightsCompliance(declaration, obligations)

Comprueba si las obligaciones respetan una declaración de derechos.

function checkRightsCompliance(
  declaration: RightsDeclaration,
  obligations: ObligationRecord[],
): { compliant: boolean; violations: string[] };

DCP-09: delegación y representación

createDelegationMandate(...) / verifyMandateValidity(mandate, revokedMandateIds) / revokeDelegation(mandate, revokedMandateIds)

Crea, valida y revoca delegaciones de autoridad de una persona a un agente. Quien llama mantiene el conjunto de ids de mandatos revocados: verifyMandateValidity lo comprueba (junto con la ventana de validez), y revokeDelegation añade el mandato a él cuando el mandato es revocable.

function verifyMandateValidity(mandate: DelegationMandate, revokedMandateIds: Set<string>): { valid: boolean; reason?: string };
function revokeDelegation(mandate: DelegationMandate, revokedMandateIds: Set<string>): { revoked: boolean; reason?: string };
interface AuthorityScopeEntry {
  domain: string;
  actions_permitted: string[];
  data_classes?: string[];
  limits?: Record<string, unknown>;
}

createSubMandate(registry, delegatorKeys, parent, params) / verifyMandateChain(registry, chain, revokedMandateIds, keys, now?)

Cadenas de delegación (DCP-09 §3.5): el agente que tiene parent emite un submandato a otro agente, firmado con sus propias claves en el contexto DCP-AI.v2.SubMandate. verifyMandateChain recibe la cadena empezando por la raíz, los ids de mandatos revocados, las entradas de claves de la persona y las de cada agente delegante por agent_id, y el momento de la verificación; comprueba la firma de cada salto hasta la persona, el enlace con el padre y la profundidad, sub_delegation, las ventanas de validez anidadas, la atenuación (las acciones, las clases de datos y los límites solo pueden restringirse: una entrada hija repite los data_classes del padre como subconjunto, y los límites numéricos solo se comparan como enteros dentro de ±(2^53−1)), el nivel mínimo minimum_security_tier y la revocación (un ancestro revocado invalida a todos sus descendientes), y falla cerrado ante cualquier cosa desconocida.

interface MandateChainKeys { human_keys: KeyEntry[]; agent_keys: Record<string, KeyEntry[]> }
interface MandateChainResult { valid: boolean; errors: string[]; depth: number; effective_tier: SecurityTier | null }

computeSecurityTier(intent, policyDecision?, mandateChainTier?) toma el effective_tier de la cadena como un mínimo que solo puede elevar el nivel (spec §14.2). Python: create_sub_mandate, verify_mandate_chain; Go: CreateSubMandate, VerifyMandateChain; Rust: create_sub_mandate, verify_mandate_chain.

evaluateSignificance(context) / shouldNotifyHuman(significance, thresholds)

Evalúa la relevancia de una acción y determina si debe notificarse a la persona.

type ThresholdOperator = 'gt' | 'lt' | 'gte' | 'lte' | 'eq';
type ThresholdAction = 'notify' | 'escalate' | 'block';

createAdvisoryDeclaration(...) / createAwarenessThreshold(...)

Crea declaraciones de asesoramiento del agente y configura los umbrales de notificación.

generateMirror(...)

Genera, a partir de una cadena de auditoría, una narración legible del espejo del principal.

generateInteractionRecord(...)

Crea un registro de interacción entre agentes de doble capa (términos públicos + hash de la deliberación privada).


Separación de dominio

DCP_CONTEXTS

Contextos de separación de dominio predefinidos para las distintas operaciones de DCP.

const DCP_CONTEXTS: Record<string, DcpContext>;
// 19 contexts: AgentPassport, ResponsiblePrincipal, Intent, PolicyDecision,
// AuditEvent, Bundle, Revocation, KeyRotation, ProofOfPossession,
// JurisdictionAttestation, HumanConfirmation, MultiPartyAuth,
// Lifecycle (DCP-05), Succession (DCP-06), Dispute (DCP-07),
// Rights (DCP-08), Delegation (DCP-09), Awareness (DCP-09), SubMandate (DCP-09)

domainSeparatedMessage(context, canonicalPayloadBytes)

Construye el mensaje que se firma: UTF8(context) || 0x00 || canonicalPayloadBytes. Lanza una excepción ante una etiqueta de contexto desconocida.

function domainSeparatedMessage(context: DcpContext | string, canonicalPayloadBytes: Uint8Array): Uint8Array;

Nonces de sesión

generateSessionNonce()

Genera un nonce de sesión criptográfico para protegerse contra el empalme (splicing).

function generateSessionNonce(): string;

isValidSessionNonce(nonce)

Valida que una cadena sea un nonce de sesión válido de 64 caracteres hexadecimales.

function isValidSessionNonce(nonce: string): boolean;

verifySessionBinding(artifacts)

Verifica que todos los artefactos comparten el mismo nonce de sesión.

function verifySessionBinding(artifacts: Array<{ session_nonce?: string }>): {
  valid: boolean;
  nonce?: string;
  error?: string;
};

Recuperación de claves

shamirSplit(secret, threshold, totalShares)

Divide una clave secreta en partes Shamir M de N.

function shamirSplit(secret: Uint8Array, threshold: number, totalShares: number): ShamirShare[];

interface ShamirShare {
  index: number;
  data: Uint8Array;
}

shamirReconstruct(shares)

Reconstruye un secreto a partir de partes Shamir.

function shamirReconstruct(shares: ShamirShare[]): Uint8Array;

setupKeyRecovery({ humanId, masterSecret, threshold, holders })

Configura la recuperación de claves con una configuración de recuperación social M de N. Devuelve la configuración que se publica y una parte por custodio para distribuir.

function setupKeyRecovery(params: {
  humanId: string;
  masterSecret: Uint8Array;
  threshold: number;
  holders: Array<{ holderId: string; holderKid: string }>;
}): RecoverySetup;

interface RecoverySetup {
  config: Omit<RecoveryConfig, 'composite_sig'>;
  shares: ShamirShare[];
}

Revocación de emergencia

generateEmergencyRevocationToken()

Genera un secreto de revocación y su token de compromiso para la revocación de emergencia de un agente.

function generateEmergencyRevocationToken(): EmergencyRevocationTokenPair;

interface EmergencyRevocationTokenPair {
  revocation_secret: string;           // 64 hex chars; kept offline by the human principal
  emergency_revocation_token: string;  // "sha256:<hex>"; embedded in the agent passport
}

verifyEmergencyRevocationSecret(revocationSecret, commitmentToken)

Verifica un secreto de revocación de emergencia contra el token de compromiso del pasaporte.

function verifyEmergencyRevocationSecret(revocationSecret: string, commitmentToken: string): boolean;

buildEmergencyRevocation({ agentId, humanId, revocationSecret })

Construye una solicitud de revocación de emergencia.

function buildEmergencyRevocation(params: {
  agentId: string;
  humanId: string;
  revocationSecret: string;
}): EmergencyRevocation;

Presentación del bundle

suggestPresentationMode(tier, opts)

Sugiere un modo de presentación: full en el primer contacto o en elevated/maximum; en routine/standard, reference con una relación de confianza existente y compact en otro caso.

function suggestPresentationMode(
  tier: SecurityTier,
  opts: { isFirstContact: boolean; hasTrustRelationship: boolean },
): PresentationMode;

type PresentationMode = 'full' | 'incremental' | 'reference' | 'compact';

presentFull(bundle) / presentCompact(bundle, pqCheckpointRef) / presentReference(bundle, verificationEndpoint) / presentIncremental(baseBundle, updatedBundle, baseAuditCount)

Genera distintos formatos de presentación para transmitir el bundle. presentCompact elimina la firma PQ y, en su lugar, hace referencia a un checkpoint PQ; presentReference envía solo el hash del bundle, el nonce de sesión y un endpoint de verificación; presentIncremental envía las entradas de auditoría posteriores a baseAuditCount, los checkpoints PQ, el manifiesto actualizado y su firma.

La referencia al checkpoint no sustituye una firma PQ que el modo efectivo exija, y ninguna presentación autoriza ni admite nada. Solo el bundle de una presentación completa o compacta es un SignedBundleV2 que verifySignedBundleV2 acepta directamente (uno compacto solo pasa donde el modo efectivo tolera la ausencia de la firma PQ); una presentación por referencia o incremental debe resolverse antes al bundle firmado completo.

function presentFull(bundle: SignedBundleV2): FullPresentation;
function presentCompact(bundle: SignedBundleV2, pqCheckpointRef: string | null): CompactPresentation;
function presentReference(bundle: SignedBundleV2, verificationEndpoint: string): ReferencePresentation;
function presentIncremental(
  baseBundle: SignedBundleV2,
  updatedBundle: SignedBundleV2,
  baseAuditCount: number,
): IncrementalPresentation;

computeBundleHash(bundle)

Calcula el hash de un bundle firmado para las presentaciones por referencia.

function computeBundleHash(bundle: SignedBundleV2): string;

Caché de verificación

VerificationCache

Caché en memoria de resultados de verificación, indexada por hash del bundle, con un TTL por nivel de seguridad.

Versiones (28/10/2026). Esta sección describe el código fuente de main, que no está publicado. @dcp-ai/sdk 2.2.1 publicado y las versiones anteriores mantienen el comportamiento previo: la clave es solo el hash del bundle, get devuelve el objeto guardado, las opciones no se validan, la expiración usa solo el reloj de pared e invalidateByAgent no elimina nada y devuelve 0.

  • Un acierto no vuelve a verificar la evidencia ni la confianza. Solo comprueba la expiración de la entrada; no vuelve a comprobar la ventana de sesión, la validez de las claves, la confianza en el principal ni una instantánea de revocación reciente, y nada se invalida automáticamente cuando cambian la confianza, la revocación o la política. Un acierto no es admisión ni autorización: para eso, verifica de nuevo.
  • Clave y contexto. Sin context, la clave es el hash del bundle, como antes: las llamadas legacy comparten sus entradas, sea cual sea su inquilino o su política. Con set(..., { context }) y get o has(hash, { context }), una entrada solo se devuelve para la misma cadena de contexto, y la ruta legacy y los contextos nunca ven las entradas de los demás. Quien llama elige el contexto y responde de él: debe cambiar siempre que cambie el contenido de una entrada de la decisión (la política del verificador, el inquilino, los principales de confianza, el estado de revocación); por ejemplo, un digest que quien llama calcula sobre ese contenido. Una etiqueta reutilizada después de que cambie su contenido no aísla nada. La caché solo garantiza la separación por cadena exacta.
  • Invalidación. invalidateByKid(kid) elimina, en todos los contextos, las entradas cuyos kids firmantes incluyen kid; los kids de result.details.signer_keys se indexan junto con los de quien llama. invalidateByAgent(agentId) elimina las entradas guardadas con agentId en agentIds y, deliberadamente, todas las entradas guardadas sin asociación a un agente (llamadas legacy, o agentIds ausente o vacío), porque la caché no puede saber de quién son; las entradas asociadas solo a otros agentes se conservan. Devuelve el total eliminado, así que un número distinto de cero no significa que el agente tuviera entradas. agentIds es una etiqueta de quien llama: no se comprueba y no se deriva nada del resultado. clear() elimina todo.
  • Expiración. Una entrada es un fallo en cuanto su TTL ha pasado en cualquiera de los dos relojes, el monotónico (performance.now()) o el de pared (Date.now(), que registran createdAt y expiresAt); una lectura igual a un plazo ya es un fallo. Una lectura de cualquiera de los dos relojes anterior a la de la creación, o una lectura no finita, es un fallo que expulsa la entrada. Un retroceso del reloj de pared que queda después de la creación lo acota el plazo monotónico. Durante una suspensión del sistema el reloj monotónico puede no avanzar; el límite del reloj de pared sigue aplicándose, pero la caché no promete tiempo real absoluto. Un TTL de 0 nunca se guarda, y set con él elimina la entrada de esa clave.
  • Copias. set guarda una copia profunda (structuredClone) del resultado y copias de las listas de kids y de agentes; get devuelve en cada acierto una copia profunda nueva y mutable; has no copia.
  • Errores. Nada cambia en la caché cuando una llamada lanza un error.
  • Constructor: TypeError si options o ttlByTier no son objetos; RangeError si un TTL no es un número de 0 a Number.MAX_SAFE_INTEGER o maxEntries no es un entero seguro de 1 a Number.MAX_SAFE_INTEGER (un undefined explícito conserva el valor predeterminado); Error si performance.now() no está disponible.
  • set: TypeError si el hash no es una cadena, el resultado no es un objeto, signerKids o agentIds no son arrays de cadenas (no vacías en el caso de los agentes; un hueco cuenta como undefined) o el contexto no es una cadena; RangeError si una lectura de reloj no es finita o un plazo (reloj + TTL) supera Number.MAX_SAFE_INTEGER; DataCloneError si el resultado no se puede clonar.
  • get y has: TypeError si el hash o el contexto no son cadenas. invalidateByAgent: TypeError si agentId no es una cadena no vacía.
class VerificationCache {
  constructor(options?: VerificationCacheOptions);
  get(bundleHash: string, options?: VerificationCacheLookupOptions): VerifyV2Result | null; // new copy; null when absent or expired
  set(
    bundleHash: string,
    result: VerifyV2Result,
    signerKids: string[],
    tier: SecurityTier,
    options?: VerificationCacheSetOptions,
  ): void;
  has(bundleHash: string, options?: VerificationCacheLookupOptions): boolean;
  invalidateByKid(kid: string): number;       // entries removed, in every context
  invalidateByAgent(agentId: string): number; // the agent's entries + every entry without agentIds
  clear(): void;
  readonly size: number;                      // every context, including expired entries not yet read
}

interface VerificationCacheOptions {
  /** TTL per tier in milliseconds, from 0 to Number.MAX_SAFE_INTEGER. */
  ttlByTier?: Partial<Record<SecurityTier, number>>;
  /** Hard upper limit on entries: a safe integer from 1 to Number.MAX_SAFE_INTEGER. */
  maxEntries?: number;
}

interface VerificationCacheSetOptions {
  agentIds?: readonly string[]; // the caller's label for invalidateByAgent; not checked
  context?: string;             // exact-string isolation chosen by the caller
}

interface VerificationCacheLookupOptions {
  context?: string;
}

interface CacheEntry {
  result: VerifyV2Result;
  bundleHash: string;
  signerKids: string[];
  tier: SecurityTier;
  createdAt: number; // Date.now() at set
  expiresAt: number; // createdAt + TTL
}

Formato de transmisión CBOR

Serialización binaria compacta para los bundles DCP.

cborEncode(value) / cborDecode(data)

function cborEncode(value: unknown): Uint8Array;
function cborDecode(data: Uint8Array): unknown;

jsonToCborPayload(json) / cborPayloadToJson(cbor)

Convierte, de forma recursiva, un payload DCP entre su forma JSON (campos *_b64 en base64) y su forma apta para CBOR (cadenas de bytes en bruto). Codifica el resultado con cborEncode.

function jsonToCborPayload(json: Record<string, unknown>): Record<string, unknown>;
function cborPayloadToJson(cbor: Record<string, unknown>): Record<string, unknown>;

detectWireFormat(data)

Detecta si los datos están codificados en JSON o en CBOR.

function detectWireFormat(data: Uint8Array): 'cbor' | 'json';

Proveedores criptográficos

registerDefaultProviders()

Registra los proveedores por defecto Ed25519 + ML-DSA-65 + SLH-DSA-192f.

function registerDefaultProviders(): void;

getDefaultRegistry()

Obtiene el AlgorithmRegistry por defecto con todos los proveedores registrados.

function getDefaultRegistry(): AlgorithmRegistry;

AlgorithmRegistry

Registro de proveedores de algoritmos.

class AlgorithmRegistry {
  registerSigner(provider: CryptoProvider): void;
  registerKem(provider: KemProvider): void;
  getSigner(alg: string): CryptoProvider;   // throws for an unregistered algorithm
  getKem(alg: string): KemProvider;
  hasSigner(alg: string): boolean;
  hasKem(alg: string): boolean;
  listSigners(): string[];
  listKems(): string[];
}

Proveedores disponibles

Proveedor Algoritmo Tipo
Ed25519Provider ed25519 Firma clásica
MlDsa65Provider ml-dsa-65 Firma poscuántica (NIST ML-DSA)
SlhDsa192fProvider slh-dsa-192f Firma poscuántica (NIST SLH-DSA)

Interfaz CryptoProvider

interface CryptoProvider {
  readonly alg: string;
  readonly keySize: number;
  readonly sigSize: number;
  readonly isConstantTime: boolean;

  generateKeypair(): Promise<{
    kid: string;
    publicKeyB64: string;
    secretKeyB64: string;
  }>;
  sign(message: Uint8Array, secretKeyB64: string): Promise<Uint8Array>;
  verify(
    message: Uint8Array,
    signature: Uint8Array,
    publicKeyB64: string,
  ): Promise<boolean>;
}

Detección de versión

detectDcpVersion(artifact)

Detecta la versión de DCP de un artefacto o de un bundle.

function detectDcpVersion(artifact: Record<string, unknown>): '1.0' | '2.0' | null;

Experimental: candidato de canonicalización dcp-jcs-v2 (opt-in)

Experimental y desactivado por defecto: dcp-jcs-v1 sigue siendo el perfil de canonicalización predeterminado y el único normativo, y los constructores, firmantes y verificadores habituales no cambian. Estas exportaciones existen para quien opte por usarlas; un bundle candidato verificado no otorga confianza ni admisión. El contrato completo está en docs/proposals/canonicalization-candidate (§15 entrada, §16 enrutador, §17 verificador, §18 productores).

function experimentalCandidateIngress(bytes: Uint8Array): ExperimentalCandidateIngressResult;
function experimentalCandidateExtractUnit(bytes: Uint8Array, transport: ExperimentalCandidateTransport): ExperimentalCandidateExtraction;
function createExperimentalCandidateRouter(config: {
  transport: ExperimentalCandidateTransport;       // 'bare' | 'envelope'
  acceptedProfiles: readonly string[];             // no default
  historical: ExperimentalHistoricalAdapter;       // no default; see experimentalHistoricalAdapters
}): ExperimentalCandidateRouter;
function createExperimentalCandidateVerifier(config: {
  transport: ExperimentalCandidateTransport;
  acceptedProfiles: readonly string[];
  historical: ExperimentalHistoricalAdapter;
}): ExperimentalCandidateVerifier;                 // verify(bytes, registry, policy?, options?)
function experimentalCandidateSignPayload(
  registry: AlgorithmRegistry, context: string, input: ExperimentalCandidateInput, keys: ExperimentalCandidateKeys,
): Promise<{ bytes: Uint8Array; signedPayload: ExperimentalCandidateSignedPayload }>;
function experimentalCandidateSignBundle(
  registry: AlgorithmRegistry, parts: ExperimentalCandidateBundleParts, signer: ExperimentalCandidateBundleSigner,
  options: ExperimentalCandidateBundleOptions,
): Promise<{ bytes: Uint8Array; signedBundle: { [key: string]: ExperimentalCandidateValue } }>;
  • ExperimentalCandidateIngressResult: { status: 'accept', value, canonical, canonicalSha256 } o { status: 'reject', class, offset }.
  • verify devuelve { route, entered, verification }: la ruta (reject, v1_path o candidate), el verificador al que entró (none, dcp-jcs-v1 o dcp-jcs-v2, como máximo uno) y el resultado de ese verificador tal cual.
  • ExperimentalCandidateInput es { bytes } (bytes originales, comprobados por la entrada) o { value } (un valor del host, comprobado de forma estricta).
  • ExperimentalCandidateProduceError (class, part, path, offset) es un rechazo por el dominio o la forma de las entradas, lanzado antes de llamar a cualquier firmante; los errores de clave, registro y proveedor siguen siendo los actuales.
  • Errores del enrutador y del verificador: ExperimentalCandidateConfigError (configuración), ExperimentalCandidateAdapterError (un decodificador histórico que falló por algo distinto de rechazar los datos) y ExperimentalCandidateInternalError.