コンテンツにスキップ

@dcp-ai/wasm — WebAssembly SDK v2.0

英語版 READMEの参考訳です。更新日:02/11/2026。検証済みの例を維持するため、識別子とコードブロック(コメントを含む)は原文のままにしています。

Digital Citizenship Protocol(DCP)v2.0 向けの WebAssembly モジュールで、Rust SDK からコンパイルされます。耐量子複合署名、ハイブリッド鍵生成、ML-KEM-768 による鍵カプセル化、二重ハッシュ、バンドルの構築・検証、セキュリティ階層の算出を提供します。ブラウザーまたは Node.js で直接動作し、サーバーは不要です。

インストール

npm 公開済み(2026 年 10 月 26 日)。 この日、@dcp-ai/wasm 2.1.0 が latest として公開され、この文書の API と実験的な dcp-jcs-v2 API を含んでいました。公開によって候補が有効になったわけではありません。候補は明示的な選択が必要な非規範的機能であり、dcp-jcs-v1 は変更されません。Rust クレートのリリース周期は独立しています。

@dcp-ai/wasm 2.1.1。 このバージョンは、VERIFICATION.md の V2-11 の二次の SHA3-256 フィールドが存在する場合、それらも検証します:audit_merkle_root_secondary、各 prev_hash_secondary、各 intent_hash_secondary。存在しないフィールドは要求されないため、検証済みのバンドルが完全な二次チェーンを持たないこともあります。存在するフィールドが null、文字列でない、または不整合の場合は拒否されます。API、結果のフィールド、dcp-jcs-v1、hash_alg の扱いは変わりません。2.1.0 はこれらのフィールドを確認しません。以下のインストールコマンドはこのバージョンを指定しています。レジストリでの提供状況は公開済みバージョンを参照してください。

npm install @dcp-ai/wasm@^2.1.1

全パッケージのバージョンは npm リリース一覧を参照してください。

@dcp-ai/wasm 2.1.2(準備済み・未公開)。 dualMerkleRoot を修正します。2.1.1 以前では、2 個以上の葉に対して V2-11 と異なるルートを返します(後述の「ハッシュ操作」を参照)。npm にはないため、上記のコマンドは 2.1.1 のままです。npm パッケージを参照してください。

チェックアウトしたソースで開発する場合は、ローカルのパッケージをビルドしてインストールします。

# Build in sdks/wasm first (see Build)
npm install /path/to/dcp-ai/sdks/wasm

ビルド

# Build WASM + TypeScript wrapper
npm run build

# WASM only (browser target)
npm run build:wasm

# WASM only (Node.js target)
npm run build:wasm:node

必要なもの: wasm-pack と、wasm32-unknown-unknown ターゲットを備えた Rust ツールチェーン。

初期化:ブラウザーと Node.js

initDcp(wasmUrl?) は dcp_ai_bg.wasm を一度だけ読み込みます。

  • ブラウザー(または pkg/ を配信するバンドラー):await initDcp() は pkg/dcp_ai.js と同じ場所のファイルを取得します。URL を渡すこともできます:await initDcp('/assets/dcp_ai_bg.wasm')。
  • Node.js: Node の fetch は file: URL を読み込めないため、この環境では引数なしの initDcp() は失敗します。ファイルを読み込み、data: URL として渡してください。
import { readFileSync } from 'node:fs';
import { initDcp } from '@dcp-ai/wasm';

// The .wasm file sits next to the `@dcp-ai/wasm/pkg` entry point.
const wasmFile = new URL('dcp_ai_bg.wasm', import.meta.resolve('@dcp-ai/wasm/pkg'));
const dcp = await initDcp(`data:application/wasm;base64,${readFileSync(wasmFile).toString('base64')}`);

wasm-bindgen がこの形式の引数は非推奨であると警告する場合がありますが、モジュールの初期化は行われます。

クイックスタート — TypeScript ラッパー

SDK の利用には TypeScript ラッパーを推奨します。この V2 バンドルでは、責任主体(principal)が RPR とマニフェストに署名し、エージェントがパスポート、インテント、ポリシー判断に署名します。それぞれが Ed25519 + ML-DSA-65 のハイブリッド鍵を使用します。この例は Node.js で動作します。ブラウザーでは初期化を await initDcp() に置き換えてください。

import { readFileSync } from 'node:fs';
import { initDcp } from '@dcp-ai/wasm';

const wasmFile = new URL('dcp_ai_bg.wasm', import.meta.resolve('@dcp-ai/wasm/pkg'));
const dcp = await initDcp(`data:application/wasm;base64,${readFileSync(wasmFile).toString('base64')}`);

const principal = dcp.generateHybridKeypair();
const agent = dcp.generateHybridKeypair();
type Hybrid = ReturnType<typeof dcp.generateHybridKeypair>;
const keyEntries = (keys: Hybrid) => [keys.classical, keys.pq].map((k) => ({
  kid: k.kid ?? dcp.deriveKid(k.alg, k.public_key_b64), alg: k.alg, public_key_b64: k.public_key_b64,
  created_at: '2026-01-01T00:00:00Z', expires_at: null, status: 'active',
}));
const sign = (context: string, payload: object, keys: Hybrid) =>
  dcp.signPayload(
    context, payload,
    keys.classical.secret_key_b64, keys.classical.kid ?? dcp.deriveKid('ed25519', keys.classical.public_key_b64),
    keys.pq.secret_key_b64, keys.pq.kid ?? dcp.deriveKid('ml-dsa-65', keys.pq.public_key_b64),
  );

const nonce = dcp.generateSessionNonce();
const now = new Date().toISOString();
const intent = {
  dcp_version: '2.0', intent_id: 'intent:example-001', session_nonce: nonce, agent_id: 'agent:example-001',
  human_id: 'human:example-001', timestamp: now, action_type: 'browse', target: { channel: 'web' },
  data_classes: ['none'], estimated_impact: 'low', requires_consent: false,
};

const bundle = dcp.buildBundle({
  rpr: sign('DCP-AI.v2.ResponsiblePrincipal', {
    dcp_version: '2.0', human_id: 'human:example-001', session_nonce: nonce, legal_name: 'Example Principal',
    entity_type: 'natural_person', jurisdiction: 'ES', liability_mode: 'owner_responsible', override_rights: true,
    issued_at: now, expires_at: null, contact: null, binding_keys: keyEntries(principal),
  }, principal),
  passport: sign('DCP-AI.v2.AgentPassport', {
    dcp_version: '2.0', agent_id: 'agent:example-001', session_nonce: nonce, keys: keyEntries(agent),
    principal_binding_reference: 'human:example-001', capabilities: ['browse'], risk_tier: 'low',
    created_at: now, status: 'active',
  }, agent),
  intent: sign('DCP-AI.v2.Intent', intent, agent),
  policy: sign('DCP-AI.v2.PolicyDecision', {
    dcp_version: '2.0', intent_id: intent.intent_id, session_nonce: nonce, decision: 'approve', risk_score: 50,
    reasons: ['low-impact browse'], required_confirmation: null,
    applied_policy_hash: dcp.preparePayload({ policy: 'default' }).payload_hash, timestamp: now,
  }, agent),
  auditEntries: [{
    dcp_version: '2.0', audit_id: 'audit:example-001', session_nonce: nonce, prev_hash: 'GENESIS', hash_alg: 'sha256',
    timestamp: now, agent_id: 'agent:example-001', human_id: 'human:example-001', intent_id: intent.intent_id,
    intent_hash: dcp.preparePayload(intent).payload_hash, policy_decision: 'approved', outcome: 'page_read',
    evidence: { tool: 'browser', result_ref: null, evidence_hash: null }, pq_checkpoint_ref: null,
  }],
  sessionNonce: nonce,
});

// The principal signs the manifest with a composite signature.
const signed = dcp.signBundle(
  bundle,
  principal.classical.secret_key_b64, principal.classical.kid ?? dcp.deriveKid('ed25519', principal.classical.public_key_b64),
  principal.pq.secret_key_b64, principal.pq.kid ?? dcp.deriveKid('ml-dsa-65', principal.pq.public_key_b64),
);

const result = dcp.verifyBundle(signed);
console.log(result.verified, result.classical_valid, result.pq_valid); // true true true

API リファレンス

初期化

initDcp(wasmUrl?: string): Promise<DcpWasm>

WASM モジュールを初期化します。各 API を使う前に一度呼び出す必要があります。任意で .wasm ファイルの URL を渡せます。Node.js では data: URL として渡してください(初期化を参照)。

鍵ペアの生成

メソッド 戻り値 説明
generateEd25519Keypair() KeypairResult Ed25519 の従来型鍵ペア
generateMlDsa65Keypair() KeypairResult ML-DSA-65 の耐量子署名用鍵ペア
generateSlhDsa192fKeypair() KeypairResult 状態を保持しないハッシュベース署名 SLH-DSA-192f の鍵ペア
generateHybridKeypair() HybridKeypairResult 一度の呼び出しで Ed25519 + ML-DSA-65 のハイブリッド鍵ペアを生成

ML-KEM-768 鍵カプセル化

メソッド 戻り値 説明
mlKem768Keygen() KemKeypairResult ML-KEM-768 のカプセル化・デカプセル化用鍵ペアを生成
mlKem768Encapsulate(pk) KemEncapsulateResult 公開鍵を用いて共有秘密をカプセル化
mlKem768Decapsulate(ct, sk) string 暗号文から共有秘密をデカプセル化し、16進数で返す

複合署名

メソッド 説明
compositeSign(context, payload, classicalSk, classicalKid, pqSk, pqKid) pq_over_classical 結合による完全な Ed25519 + ML-DSA-65 ハイブリッド署名
classicalOnlySign(context, payload, sk, kid) 従来型の Ed25519 署名のみを使用する移行モード
signPayload(context, payload, classicalSk, classicalKid, pqSk, pqKid) ペイロードに署名し、SignedPayload エンベロープに格納

検証

検証に成功しても、責任主体への信頼、受け入れ判定(admission)、行為の実行権限は与えられません。V2 検証器は主監査チェーンと主 Merkle ルートを確認しますが、2.1.1 以降は、存在する任意の副のリンク、意図のハッシュ、audit_merkle_root_secondary も確認します。2.1.0 は確認しません(二重ハッシュチェーン)。実験的候補もこれらの検証処理を再利用します。

メソッド 戻り値 説明
compositeVerify(context, payload, sig, classicalPk, pqPk?) CompositeVerifyResult 複合署名の暗号学的検証
verifyBundle(signedBundle, policy?) V2VerificationResult ポリシーモードとセキュリティ階層のモードのうち厳しい方を用い、V2 バンドルの構造、暗号、主ハッシュチェーンを検証します(spec §14.3)。resolved_tier と verification_mode を返します。policy で既定値から変更できるのは、default_mode、risk_overrides、フェーズ3のフィールド(advisory_rejected_algs、warn_classical_only_deprecated、allow_classical_fallback_disable)、max_session_duration_seconds(署名された session_issued_at から測定。マニフェストに session_expires_at がある場合、signBundle がこのフィールドを書き込みます)、require_session_expiry(session_expires_at のないマニフェストを拒否)、および verifier_id と組み合わせた require_audience_binding(intended_verifier がない、または verifier_id と異なるマニフェストを拒否)のみです。ポリシーを渡した場合、V1 バンドルは拒否されます

スキーマ検証(V2-2。main にあり、公開済みのバージョンには含まれない)。 verifyBundle と wasm_verify_signed_bundle_v2は、ポリシーと時計の確認の後、検証器がマニフェスト、ペイロードのハッシュ、鍵、署名を確認する前に、まず署名済み bundle のエンベロープと四つのペイロードを schemas/v2 に照らして検証します。実験的な候補のエクスポートも同じゲートを通ります。失敗した bundle は verified: false と schema: <JSON pointer> <keyword>[ <member>] のエラー(最大 16 件、その後に schema: further errors not listed)を返し、暗号に関する詳細は返しません。閉じたオブジェクトの未知のメンバーは拒否されます。intent の target のような開いたオブジェクトでは、宣言されたメンバーは制約を保ち、追加のメンバーだけが検査されません。マニフェストの session_issued_at と session_expires_at は、存在する場合は null ではなく文字列でなければなりません。date-time は参照検証器の ajv-formats 3.0.1 による確認に従い、これは厳密な RFC 3339 ではありません。バインディングのポリシーのパースエラー、JSON parse error、バージョンの振り分け(Unknown DCP version)は、引き続き V2-2 の前に来ます。受理の変更: 以前は検証に成功していたスキーマ上無効な bundle は、今は拒否されます。スキーマだけの API はありません。カバレッジマップを参照してください。

ハッシュ操作

メソッド 戻り値 説明
dualHash(data) DualHash SHA-256 + SHA3-256 の二重ハッシュ
sha3_256(data) string SHA3-256 ハッシュを16進数で返す
hashObject(obj) string JSON オブジェクトの SHA-256 ハッシュ
dualMerkleRoot(leaves) DualHash 空でない DualHash の葉(それぞれ 32 バイトの 16 進ダイジェスト)の配列から VERIFICATION.md の V2-11 の二重 Merkle ルートを算出。空の配列や無効な葉では例外を投げる。ルートは小文字の 16 進。2.1.2 は準備済み・未公開:2.1.1 以前は 16 進テキストをハッシュするため、2 個以上の葉のルートが異なる

正規化とドメイン分離

メソッド 戻り値 説明
canonicalize(value) string RFC 8785 JCS に基づく dcp-jcs-v1 正規化
domainSeparatedMessage(context, payloadHex) string ドメイン分離されたメッセージを16進数で返す
deriveKid(alg, publicKeyB64) string アルゴリズムと公開鍵から決定的に鍵 ID を導出

セッションとセキュリティ

メソッド 戻り値 説明
generateSessionNonce() string 256ビットのランダム nonce(16進数64文字)
verifySessionBinding(artifacts) SessionBindingResult アーティファクト間の nonce の整合性を確認
computeSecurityTier(intent, policyDecision?) SecurityTierResult 適応型セキュリティ階層 routine/standard/elevated/maximum を算出。risk_score はポリシー判断から取得

ペイロードの準備

メソッド 戻り値 説明
preparePayload(payload) PreparedPayload ペイロードを正規化してハッシュを算出

バンドルの構築と署名

メソッド 戻り値 説明
buildBundle(opts) CitizenshipBundleV2 signPayload で署名されたアーティファクトから、マニフェスト付き V2 バンドルを構築。sessionNonce の既定値は RPR の session_nonce
signBundle(bundle, classicalSk, classicalKid, pqSk, pqKid) SignedBundleV2 複合署名でバンドルに署名。signer.id は RPR の human_id。マニフェストに session_expires_at があり session_issued_at がない場合、session_issued_at を署名時刻に設定

所有証明

メソッド 戻り値 説明
generateRegistrationPop(challenge, sk, alg) SignatureEntry 鍵登録用の所有証明(PoP)を生成
verifyRegistrationPop(challenge, pop, pk, alg) PopResult PoP を検証

ユーティリティ

メソッド 戻り値 説明
detectVersion(value) string \| null JSON オブジェクトから DCP プロトコルのバージョンを検出

DCP-05–09 の型

WASM SDK には、DCP-05 から DCP-09 までのすべてのアーティファクトについて、Rust SDK の型に対応する TypeScript インターフェースが含まれます。

仕様 インターフェース
DCP-05 ライフサイクル LifecycleState, CommissioningCertificate, VitalityReport, VitalityMetrics, DecommissioningRecord, TerminationMode, DataDisposition
DCP-06 継承 DigitalTestament, SuccessionRecord, MemoryTransferManifest, MemoryTransferEntry, SuccessorPreference, MemoryClassification, TransitionType, MemoryDisposition
DCP-07 紛争 DisputeRecord, ArbitrationResolution, JurisprudenceBundle, ObjectionRecord, DisputeType, EscalationLevel, DisputeStatus, ObjectionType, AuthorityLevel
DCP-08 権利 RightsDeclaration, RightEntry, ObligationRecord, RightsViolationReport, RightType, ComplianceStatus
DCP-09 委任 DelegationMandate, AdvisoryDeclaration, PrincipalMirror, InteractionRecord, AwarenessThreshold, ThresholdRule, AuthorityScopeEntry, ThresholdOperator, ThresholdAction

domainSeparatedMessage() で利用できるドメイン分離コンテキスト:Lifecycle、Succession、Dispute、Rights、Delegation、Awareness。

実験的機能:正規化候補 dcp-jcs-v2(明示的な選択が必要)

規範ではなく、既定では有効になっていません。dcp-jcs-v1 が引き続き唯一の正規化プロファイルであり、既定値、ビルダー、署名処理、検証器は変更されません。これらのメソッドは、npm WASM 2.1.0 を含め、明示的に選択した呼び出し元向けに提供されています。WASM バインディングが受け取るのはバイト列のみで、ホスト側の値は先に JavaScript で検査されます。候補バンドルの検証に成功しても、信頼や受け入れは認められません。設計と契約:docs/proposals/canonicalization-candidate(§15 入力処理、§16 ルーター、§17 検証器、§18 生成側)。

メソッド 説明
experimentalCandidateIngress(bytes) { status: 'accept', canonical, ... } または { status: 'reject', class, offset }
experimentalCandidateExtractUnit(bytes, transport) bare または envelope 形式の転送単位を取得
createExperimentalCandidateRouter(config) バイト列を振り分けます。historical は experimentalWasmHistoricalAdapters のいずれか(w1… は JSON.stringify を通すオブジェクト、w2… はテキスト)で、既定の選択肢はありません
createExperimentalCandidateVerifier(config).verify(bytes, policy?) 元のバイト列から、最大1つの検証器で検証。時刻は Date.now から取得
experimentalCandidateSignPayload(context, input, keys) { bytes } または { value } から1つのアーティファクトに署名
experimentalCandidateSignBundle(parts, signer, options) マニフェストに dcp-jcs-v2 を指定したバンドルを組み立てて署名
ExperimentalWasmCandidateProduceError 入力の値域または形式が不正な場合、バインディングが署名する前に拒否
import { readFileSync } from 'node:fs';
import { initDcp } from '@dcp-ai/wasm';

const wasmFile = new URL('dcp_ai_bg.wasm', import.meta.resolve('@dcp-ai/wasm/pkg'));
const dcp = await initDcp(`data:application/wasm;base64,${readFileSync(wasmFile).toString('base64')}`);

// The ingress decides on the original bytes: 1.0 is the integer 1, members are sorted.
const accepted = dcp.experimentalCandidateIngress(new TextEncoder().encode('{"b":1.0,"a":[]}'));
if (accepted.status === 'accept') console.log(new TextDecoder().decode(accepted.canonical)); // {"a":[],"b":1}

// A producer signs an artifact from those bytes (hybrid keys, today's composite signature).
const h = dcp.generateHybridKeypair();
const key = (k: typeof h.classical) => ({
  kid: k.kid ?? dcp.deriveKid(k.alg, k.public_key_b64), alg: k.alg, secretKeyB64: k.secret_key_b64, publicKeyB64: k.public_key_b64,
});
const artifact = dcp.experimentalCandidateSignPayload(
  'DCP-AI.v2.Intent', { bytes: new TextEncoder().encode('{"intent_id":"intent:1","risk":1.0}') },
  { classical: key(h.classical), pq: key(h.pq) },
);
console.log(artifact.signedPayload.payload_hash); // sha256:… of {"intent_id":"intent:1","risk":1}

低レベル API

TypeScript ラッパーを使わず、WASM 関数を直接利用することもできます。

import init, {
  wasm_generate_hybrid_keypair,
  wasm_composite_sign,
  wasm_composite_verify,
  wasm_build_bundle,
  wasm_sign_bundle,
  wasm_verify_signed_bundle_v2,
  wasm_ml_kem_768_keygen,
  wasm_ml_kem_768_encapsulate,
  wasm_ml_kem_768_decapsulate,
  wasm_dual_hash,
  wasm_compute_security_tier,
} from '@dcp-ai/wasm/pkg';

await init();

const keys = JSON.parse(wasm_generate_hybrid_keypair());
// ... use raw functions, all return JSON strings

ブラウザーで動作する完全な対話型デモは example.html を参照してください。

セキュリティ階層

computeSecurityTier(intent, policyDecision?) は適応型セキュリティ階層を算出します(spec §14.2)。risk_score はポリシー判断から取得し、ポリシー判断がなければ 0 です。action_type、estimated_impact、data_classes が不明または欠落している場合、あるいは risk_score が欠落しているか 0〜1000 の整数でない場合は、elevated とみなします。intent.security_tier は結果を引き上げることしかできません。該当する最も高い階層が適用されます。

階層 条件(いずれかに該当) 検証モード チェックポイント間隔
routine 以下のいずれにも該当しない classical_only 50
standard risk_score 200–499、estimated_impact: medium hybrid_preferred 10
elevated risk_score 500–799、pii / financial_data / health_data、initiate_payment、estimated_impact: high、不明な値 hybrid_required 1
maximum risk_score ≥ 800、credentials / children_data hybrid_required 1

対応アルゴリズム

分類 アルゴリズム 標準
従来型署名 Ed25519 RFC 8032
耐量子署名 ML-DSA-65 FIPS 204
状態を保持しない耐量子署名 SLH-DSA-192f FIPS 205
耐量子鍵カプセル化 ML-KEM-768 FIPS 203
ハッシュ SHA-256 + SHA3-256 FIPS 180-4, FIPS 202
正規化 dcp-jcs-v1 RFC 8785(JCS)に基づく

開発

前提条件

# Install wasm-pack
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh

# Install WASM target
rustup target add wasm32-unknown-unknown

Rust WASM テストの実行

cd ../rust
wasm-pack test --headless --chrome -- --features wasm

ライセンス

Apache-2.0