<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://dpi-apps.space/feed.xml" rel="self" type="application/atom+xml" /><link href="https://dpi-apps.space/" rel="alternate" type="text/html" /><updated>2026-08-24T14:59:34+00:00</updated><id>https://dpi-apps.space/feed.xml</id><title type="html">Confidential AI Network</title><subtitle>Contract-governed, confidential AI training — vision, architecture, and security notes for multi-party collaboration without giving up data control.</subtitle><entry><title type="html">Is India’s OCEN protocol the missing blueprint for agentic AI workflows?</title><link href="https://dpi-apps.space/architecture/2026/08/23/ocen-protocol-agentic-ai-workflows/" rel="alternate" type="text/html" title="Is India’s OCEN protocol the missing blueprint for agentic AI workflows?" /><published>2026-08-23T00:00:00+00:00</published><updated>2026-08-23T00:00:00+00:00</updated><id>https://dpi-apps.space/architecture/2026/08/23/ocen-protocol-agentic-ai-workflows</id><content type="html" xml:base="https://dpi-apps.space/architecture/2026/08/23/ocen-protocol-agentic-ai-workflows/"><![CDATA[<blockquote>
  <p>Running bottom-up AI point solutions — letting a thousand flowers bloom — has failed to yield major returns. The big gains come from workflow redesign: taking a top-down view of the process and changing how execution steps work together end-to-end.<br />
— Andrew Ng</p>
</blockquote>

<p>In recent analyses on enterprise AI architecture, Andrew Ng made a compelling case: real breakthrough value doesn’t come from using an LLM to speed up an isolated task (like summarizing a PDF). It comes from <strong>top-down workflow redesign</strong>—re-architecting multi-step business operations into agentic execution graphs.</p>

<p>To illustrate this, Ng points to the commercial credit journey. Automating a single review step saves a modest ~5% in costs. But redesigning the entire process so a borrower gets approved in 10 minutes instead of two weeks redefines the product itself.</p>

<p>This raises an essential question for systems architects: if agentic AI requires end-to-end workflow graphs, <strong>what serves as the underlying protocol layer when those workflows cross enterprise boundaries?</strong></p>

<p>India’s <strong>Open Credit Enablement Network (OCEN 4.0)</strong> is the most concrete public example of that protocol layer for credit—not because it became “UPI for loans,” but because it already specifies roles, async APIs, and a loan-application state machine that agents can invoke without inventing the execution path.</p>

<p><em>Note: This essay is adjacent to Confidential AI Network (CAN). CAN applies a similar “protocol + governed execution” idea to multi-party <strong>training</strong>; OCEN applies it to multi-party <strong>credit</strong>. Both sit in the broader India Stack / iSPIRT design lineage (alongside <a href="https://depa.world">DEPA</a>).</em></p>

<hr />

<h2 id="the-bottleneck-why-agentic-software-graphs-hit-an-execution-wall">The bottleneck: why agentic software graphs hit an execution wall</h2>

<p>When developers build agentic workflows in code frameworks (LangGraph, AutoGen, CrewAI), they define execution nodes, state transitions, and tool calls within a <strong>single software environment</strong>.</p>

<p>The moment an AI agent attempts to execute a financial workflow across <strong>independent companies</strong>, it hits an interoperability wall:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>                  [ SOFTWARE AGENTIC GRAPH ]
                     (LangGraph / AutoGen)
                     Conversational Intent
                             │
                             ▼
  ┌──────────────────────────┼──────────────────────────┐
  │                          │                          │
  ▼                          ▼                          ▼
[Data Extraction]     [Risk Scoring]         [Offer Matching]
  │                          │                          │
  └──────────────────────────┼──────────────────────────┘
                             │
                             ▼
                     [ EXECUTION WALL ]
          (No standard APIs to talk to external banks,
           consent platforms, or repayment rails)
</code></pre></div></div>

<p>Without a unified network protocol:</p>

<ul>
  <li>An agent cannot pull verified, real-time cash-flow data without manual document uploads.</li>
  <li>It cannot broadcast structured loan requests to multiple independent lenders simultaneously.</li>
  <li>It lacks a universal settlement rail to execute e-signatures and automated repayment mandates.</li>
</ul>

<p>An agentic software graph is only as powerful as the <strong>network protocol</strong> it can invoke outside its own environment.</p>

<hr />

<h2 id="bridging-silicon-valley-brains-with-dpi-rails">Bridging Silicon Valley “brains” with DPI “rails”</h2>

<p>The key to solving this execution bottleneck is synthesizing two different technology philosophies:</p>

<table>
  <thead>
    <tr>
      <th>Layer</th>
      <th>Strength</th>
      <th>Examples</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Silicon Valley intelligence</strong></td>
      <td>Think, plan, adapt</td>
      <td>Frontier LLMs, multi-modal reasoning, agentic orchestration</td>
    </tr>
    <tr>
      <td><strong>India DPI protocol</strong></td>
      <td>Open rails to <em>act</em> at population scale</td>
      <td>Aadhaar, UPI, Account Aggregator, <strong>OCEN</strong>, ONDC</td>
    </tr>
  </tbody>
</table>

<p>Without open protocols, AI agents risk becoming “brains in a jar”—strong at reasoning, blocked whenever they touch banking, identity, or settlement.</p>

<p>Without agents on the edges, open protocols remain static rails waiting for human-driven software. The breakthrough is connecting the two: <strong>autonomous reasoning at the edges driving deterministic, protocol-based execution at the core.</strong></p>

<hr />

<h2 id="why-ocen-can-be-read-as-a-protocol-answer-to-workflow-graphs">Why OCEN can be read as a protocol answer to workflow graphs</h2>

<p>Developed as part of India’s DPI (by <a href="https://ispirt.in/">iSPIRT</a>), <strong>OCEN 4.0</strong> takes the core components of a workflow graph and codifies them into an open, multi-party network protocol.</p>

<h3 id="1-a-protocol-is-a-network-level-graph">1. A protocol <em>is</em> a network-level graph</h3>

<p>In software, a graph consists of nodes, edges, and state objects. OCEN standardizes those primitives across independent market participants:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>                            ┌────────────────────────────────┐
                            │     Participant Registry       │
                            │  (Identity &amp; Public Key Auth)  │
                            └───────────────┬────────────────┘
                                            │
                                            ▼
┌──────────────────┐               ┌─────────────────┐               ┌──────────────────┐
│ Loan Agent (LA)  │ ────────────► │  Product Reg.   │ ◄──────────── │ Lenders (Banks)  │
│ (Embeds Credit)  │  Offer Req.   │  (Offer Bids)   │  Publishes    │ (Capital Engine) │
└────────┬─────────┘               └─────────────────┘               └────────┬─────────┘
         │                                                                    │
         │               ┌────────────────────────────────────┐               │
         ├─────────────► │  Derived Data Partner / AA (Data)  │ ◄─────────────┤
         │               └────────────────────────────────────┘               │
         │               ┌────────────────────────────────────┐               │
         └─────────────► │ Disbursement &amp; Collections Partner │ ◄─────────────┘
                         └────────────────────────────────────┘
</code></pre></div></div>

<ul>
  <li><strong>Nodes (actors):</strong> Loan Agents (borrower interfaces), Derived Data Partners (consent / derived credit inputs), Lenders (capital), Collections Partners.</li>
  <li><strong>Edges (transitions):</strong> Open, standardized REST/JSON APIs for offer request, evaluate, e-sign, e-NACH.</li>
  <li><strong>Graph state:</strong> Standardized objects that track a loan deterministically from intent to collection.</li>
</ul>

<h3 id="2-deterministic-protocol-core--agentic-edges">2. Deterministic protocol core + agentic edges</h3>

<p>Financial regulators demand strict auditability—an LLM cannot invent interest rates or skip compliance steps.</p>

<p>OCEN-style designs decouple reasoning from execution:</p>

<ul>
  <li><strong>Protocol core (deterministic):</strong> Enforces state machines for origination, consent verification, and repayment setup.</li>
  <li><strong>Network edges (agentic):</strong> Agents translate unstructured voice, regional language, or invoice scans into the precise JSON the protocol graph requires.</li>
</ul>

<p>That pattern—<strong>deterministic core, agentic edges</strong>—is the architectural lesson beyond India credit.</p>

<h3 id="3-walkthrough-intent--ocen-json--e-sign--e-nach">3. Walkthrough: intent → OCEN JSON → e-sign / e-NACH</h3>

<p>Take a GeM-style working-capital ask—the kind of flow OCEN was actually built to carry:</p>

<blockquote>
  <p>“Purchase order GEMC-5116877-5754010-1, ₹4.2 lakh, need funds in 48 hours against the PO.”</p>
</blockquote>

<p>An LLM at the Loan Agent edge can parse GSTIN, amount, tenure, and product-network membership. It cannot invent an interest rate, skip Account Aggregator consent, or mark the loan disbursed. Those steps belong to the protocol.</p>

<p><strong>Step 1 — the agent emits a <code class="language-plaintext highlighter-rouge">CreateLoanApplicationRequest</code>.</strong> Fields below are an illustrative subset of <a href="https://ocen.dev/docs/api_design_principles/">OCEN 4.0</a>; live calls are async, JWS-signed, and keyed by <code class="language-plaintext highlighter-rouge">requestId</code> for idempotency.</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"metadata"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"version"</span><span class="p">:</span><span class="w"> </span><span class="s2">"4.0.0"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"originatorOrgId"</span><span class="p">:</span><span class="w"> </span><span class="s2">"org-loan-agent-gem"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"originatorParticipantId"</span><span class="p">:</span><span class="w"> </span><span class="s2">"la-gem-sahay"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"timestamp"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2026-08-24T12:01:00Z"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"traceId"</span><span class="p">:</span><span class="w"> </span><span class="s2">"trc-9f3a…"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"requestId"</span><span class="p">:</span><span class="w"> </span><span class="s2">"req-e2e-001"</span><span class="w">
  </span><span class="p">},</span><span class="w">
  </span><span class="nl">"productData"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"productId"</span><span class="p">:</span><span class="w"> </span><span class="s2">"po-working-capital-30d"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"productNetworkId"</span><span class="p">:</span><span class="w"> </span><span class="s2">"pn-gem-sahay"</span><span class="w">
  </span><span class="p">},</span><span class="w">
  </span><span class="nl">"loanApplications"</span><span class="p">:</span><span class="w"> </span><span class="p">[{</span><span class="w">
    </span><span class="nl">"borrower"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"primaryId"</span><span class="p">:</span><span class="w"> </span><span class="s2">"AAACU1234F"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"primaryIdType"</span><span class="p">:</span><span class="w"> </span><span class="s2">"PAN"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"category"</span><span class="p">:</span><span class="w"> </span><span class="s2">"ORGANIZATION"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Usha Components Pvt Ltd"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"aaIdentifier"</span><span class="p">:</span><span class="w"> </span><span class="s2">"aa-id-…"</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="nl">"terms"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"requestedAmount"</span><span class="p">:</span><span class="w"> </span><span class="mi">420000</span><span class="p">,</span><span class="w">
      </span><span class="nl">"currency"</span><span class="p">:</span><span class="w"> </span><span class="s2">"INR"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"tenure"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"duration"</span><span class="p">:</span><span class="w"> </span><span class="mi">30</span><span class="p">,</span><span class="w"> </span><span class="nl">"unit"</span><span class="p">:</span><span class="w"> </span><span class="s2">"DAY"</span><span class="w"> </span><span class="p">}</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="nl">"pledgedDocuments"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"source"</span><span class="p">:</span><span class="w"> </span><span class="s2">"GSTN"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"GSTN_B2B_INVOICE"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"format"</span><span class="p">:</span><span class="w"> </span><span class="s2">"JSON"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"reference"</span><span class="p">:</span><span class="w"> </span><span class="s2">"GEMC-5116877-5754010-1"</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">}]</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p><strong>Step 2 — the network, not the model, advances state.</strong> The Loan Agent fans the application to every lender in the product network. Each lender returns <code class="language-plaintext highlighter-rouge">CreateLoanApplicationResponse</code> (<code class="language-plaintext highlighter-rouge">PROCESSING</code> or reject). Consent APIs collect one AA consent and forward it. Offer APIs return machine-readable bids. After the borrower accepts, the conversation collapses from many lenders to one, and the application walks a published status machine:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>intent (voice / PO / invoice)
        │  agent → structured JSON
        ▼
CreateLoanApplicationRequest  ──►  lenders in product network
        │  async ack (requestId)
        ▼
AA consent  →  offers  →  accept offer
        ▼
KYC  →  loan agreement (e-sign)
        ▼
repayment setup (e-NACH / UPI mandate)
        ▼
disbursement account  →  grant  →  disburse
</code></pre></div></div>

<p>Statuses the graph already knows: <code class="language-plaintext highlighter-rouge">CREATED</code> → <code class="language-plaintext highlighter-rouge">CONSENT_RECEIVED</code> → <code class="language-plaintext highlighter-rouge">OFFERED</code> → <code class="language-plaintext highlighter-rouge">OFFER_ACCEPTED</code> → <code class="language-plaintext highlighter-rouge">KYC_COMPLETED</code> → <code class="language-plaintext highlighter-rouge">LOAN_AGREEMENT_COMPLETED</code> → <code class="language-plaintext highlighter-rouge">REPAYMENT_SETUP_COMPLETED</code> → <code class="language-plaintext highlighter-rouge">GRANTED</code> → <code class="language-plaintext highlighter-rouge">DISBURSEMENT_COMPLETED</code>.</p>

<p>The agent’s job is to fill JSON the state machine will accept. The lender’s job is to underwrite. The protocol’s job is to refuse illegal transitions—no model is allowed to jump from <code class="language-plaintext highlighter-rouge">OFFERED</code> to <code class="language-plaintext highlighter-rouge">DISBURSEMENT_COMPLETED</code>.</p>

<hr />

<h2 id="why-ocen-is-a-blueprint-not-upi-for-credit">Why OCEN is a blueprint, not UPI for credit</h2>

<p>OCEN has not become UPI, and pretending otherwise makes the architecture claim weaker. UPI is a payment instruction with an operator (NPCI), monthly public volumes, an existing bank participant set, and years of fiscal support for adoption. A loan is an underwriting decision every lender wants to keep proprietary; a protocol can standardise the <em>pipes</em> (application, consent, offer, e-sign, e-NACH) and cannot standardise the <em>yes</em>. OCEN is a specification with no NPCI-equivalent switch, so it has no public origination dashboard. Its data layer—Account Aggregator—took until the mid-2020s to reach reliable bank coverage, years after the 2020 launch. What actually shipped at scale is still mostly government-anchored working capital (GeM Sahay, GST Sahay), not an open marketplace where any Loan Agent talks to any lender the way any UPI app talks to any bank. Lenders still prefer bilateral NBFC/fintech contracts where risk-sharing and default-loss guarantees are negotiated once, not left implicit in a shared spec.</p>

<p>That gap is the point for agentic systems: <strong>the protocol shape is usable even when the market is not UPI-scale.</strong> Agents need a deterministic graph they can call. OCEN already wrote that graph down. Adoption is a separate, harder problem—and it is why “blueprint” is the right word, not “the missing rail.”</p>

<hr />

<h2 id="how-could-the-us-implement-this-blueprint">How could the US implement this blueprint?</h2>

<p>Replicating a state-backed network protocol in the US faces structural hurdles: the market runs on <strong>private abstraction layers</strong> rather than public infrastructure.</p>

<table>
  <thead>
    <tr>
      <th>Concern</th>
      <th>India (public rail)</th>
      <th>US (private layer)</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Data consent</td>
      <td>Account Aggregator</td>
      <td>Plaid, MX</td>
    </tr>
    <tr>
      <td>Identity</td>
      <td>Aadhaar</td>
      <td>Alloy, Persona, etc.</td>
    </tr>
    <tr>
      <td>Capital execution</td>
      <td>OCEN lender registry</td>
      <td>BaaS APIs (Column, Cross River, …)</td>
    </tr>
  </tbody>
</table>

<h3 id="a-composable-private-graph-in-the-us">A composable private graph in the US</h3>

<p>US builders do not need a public mandate to <em>test</em> the pattern. They do need the part OCEN actually contributed—a shared schema and registry—not just three vendor SDKs in one agent:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>                              ┌──────────────────────┐
                              │  US Borrower Agent   │  (LLM reasoning node)
                              │ (LangGraph / AutoGen)│
                              └──────────┬───────────┘
                                         │ Structured API payloads
       ┌─────────────────────────────────┼─────────────────────────────────┐
       ▼                                 ▼                                 ▼
┌──────────────┐                 ┌──────────────┐                 ┌──────────────┐
│ Data Consent │                 │ Risk Engine  │                 │ BaaS Lenders │
│ (Plaid / MX) │ ──────────────► │ (Alloy / …)  │ ──────────────► │ (Column / …) │
└──────────────┘                 └──────────────┘                 └──────────────┘
</code></pre></div></div>

<p>Composing Plaid + Alloy + Column is ordinary bilateral integration. The OCEN lesson is a <strong>shared</strong> participant/product registry and one loan-application schema every lender in the network accepts. Without that, each edge is a custom deal—and the agent is back at the execution wall. The US can test the pattern privately; it does not get the pattern for free by wiring three vendor APIs into LangGraph.</p>

<hr />

<h2 id="takeaway">Takeaway</h2>

<p>OCEN is not the only way to build agentic financial systems, and it has not won the way UPI did. It is still the clearest public spec of a pattern agents actually need:</p>

<p><strong>Reasoning at the edges, a deterministic multi-party protocol at the core, and a state machine that will not let the model skip e-sign or e-NACH.</strong> Without that graph, “workflow redesign” stops at the first bank that does not speak the agent’s tools.</p>

<hr />

<h2 id="glossary">Glossary</h2>

<table>
  <thead>
    <tr>
      <th>Term</th>
      <th>Meaning</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Aadhaar</strong></td>
      <td>India’s national biometric digital identity used for e-KYC.</td>
    </tr>
    <tr>
      <td><strong>Account Aggregator (AA)</strong></td>
      <td>RBI-regulated DPI for consent-based financial data streaming.</td>
    </tr>
    <tr>
      <td><strong>Agentic graph</strong></td>
      <td>Architecture where agents use routing, memory, and tool loops for multi-step work.</td>
    </tr>
    <tr>
      <td><strong>BaaS</strong></td>
      <td>Banking-as-a-Service—licensed bank APIs for accounts, lending, payments.</td>
    </tr>
    <tr>
      <td><strong>Derived Data Partner (DDP)</strong></td>
      <td>OCEN node that turns raw telemetry (e.g. GST, cash flow) into underwriting inputs.</td>
    </tr>
    <tr>
      <td><strong>DPI</strong></td>
      <td>Digital Public Infrastructure—open interoperable rails at national scale.</td>
    </tr>
    <tr>
      <td><strong>e-NACH</strong></td>
      <td>NPCI electronic auto-debit mandates for recurring repayment.</td>
    </tr>
    <tr>
      <td><strong>iSPIRT</strong></td>
      <td>Think tank that helped design India Stack components including OCEN.</td>
    </tr>
    <tr>
      <td><strong>Loan Agent (LA)</strong></td>
      <td>Embeds credit in a product surface as borrower advocate.</td>
    </tr>
    <tr>
      <td><strong>OCEN</strong></td>
      <td>Open Credit Enablement Network—unbundles credit into standardized APIs.</td>
    </tr>
    <tr>
      <td><strong>ONDC</strong></td>
      <td>Open Network for Digital Commerce (Beckn-based commerce protocol).</td>
    </tr>
    <tr>
      <td><strong>Product Network</strong></td>
      <td>OCEN grouping of lenders and other roles around a product; the LA auctions an application across it.</td>
    </tr>
    <tr>
      <td><strong>Product Registry</strong></td>
      <td>Where lenders publish machine-readable credit products.</td>
    </tr>
    <tr>
      <td><strong>UPI</strong></td>
      <td>India’s real-time interoperable payment network (NPCI).</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="references">References</h2>

<ul>
  <li>Ng, Andrew. (2026). <em>Winning in the Agentic Era</em> — Bain &amp; Company Insights.</li>
  <li>Ng, Andrew. (2026). <em>AI Won’t Replace Workers. It Will Redesign Work</em> — keynote.</li>
  <li>iSPIRT Foundation. <a href="https://ocen.dev">OCEN 4.0</a> — <a href="https://ocen.dev/docs/api_design_principles/">API design principles</a> (async <code class="language-plaintext highlighter-rouge">CreateLoanApplicationRequest</code> / <code class="language-plaintext highlighter-rouge">Response</code>, idempotent <code class="language-plaintext highlighter-rouge">requestId</code>, JWS).</li>
  <li>iSPIRT. <a href="https://github.com/iSPIRT/OCEN-Documentation/blob/main/docs/9-loan_journey/4-auction_and_offer.md">Loan journey: auction and offer</a> — one-to-many create / consent / offer, then collapse to one lender.</li>
  <li>iSPIRT / ProductNation. <a href="https://pn.ispirt.in/open-credit-enablement-network-ocen/">Open Credit Enablement Network</a> — roles (LA, lender, DDP) and GeM Sahay as PO cash-flow pilot.</li>
  <li>Sahamati. Account Aggregator architecture and ecosystem reporting.</li>
  <li>NPCI. UPI product statistics — contrast: operator + public monthly volumes, which OCEN as a spec does not have.</li>
</ul>]]></content><author><name></name></author><category term="architecture" /><category term="agents" /><category term="dpi" /><category term="ocen" /><category term="agentic-ai" /><category term="dpi" /><category term="india-stack" /><category term="andrew-ng" /><category term="fintech" /><category term="protocols" /><summary type="html"><![CDATA[Andrew Ng’s workflow-redesign thesis meets OCEN 4.0: a concrete loan-application state machine (intent → JSON → offer → e-sign → e-NACH)—and an honest look at why that protocol has not become UPI.]]></summary></entry><entry><title type="html">Azure confidential computing for CAN — threat model, Key Vault, Secure Key Release, and e2e training</title><link href="https://dpi-apps.space/security/2026/08/17/azure-confidential-computing-deep-dive/" rel="alternate" type="text/html" title="Azure confidential computing for CAN — threat model, Key Vault, Secure Key Release, and e2e training" /><published>2026-08-17T00:00:00+00:00</published><updated>2026-08-17T00:00:00+00:00</updated><id>https://dpi-apps.space/security/2026/08/17/azure-confidential-computing-deep-dive</id><content type="html" xml:base="https://dpi-apps.space/security/2026/08/17/azure-confidential-computing-deep-dive/"><![CDATA[<p><em>On Azure, “confidential training” is not a checkbox on a VM SKU. It is a threat model, a key custody story, an attestation policy, and a destroy path—bound to a signed Ricardian contract.</em></p>

<p><strong>Related:</strong> <a href="/product-tour/">Product tour</a> · <a href="/product/2026/08/16/azure-e2e-product-tour-deck/">Azure product tour deck</a> · <a href="/security/2026/08/17/spiffe-spire-azure-wif/">SPIFFE/SPIRE on Azure</a> · <a href="/product/2026/08/17/can-contract-management-signing/">Contract signing &amp; keys</a> · <a href="/security/2026/08/16/can-kms-dek-mek-escrow/">KMS DEK/MEK</a> · <a href="/security/2026/08/16/can-tee-attest-decrypt-train/">TEE attest → decrypt</a> · <a href="/security/2026/07/28/azure-entra-security-architecture/">Entra architecture note</a> · In-repo: <a href="https://github.com/gitmujoshi/Confidential-AI-Network/blob/main/docs/production/AZURE_SECURITY_ARCHITECTURE.md">AZURE_SECURITY_ARCHITECTURE.md</a> · <a href="https://github.com/gitmujoshi/Confidential-AI-Network/blob/main/docs/deployment/AZURE_FEATURES_AND_CONFIGURATION.md">AZURE_FEATURES_AND_CONFIGURATION.md</a> · <a href="https://github.com/gitmujoshi/Confidential-AI-Network/blob/main/docs/deployment/AZURE_SPIFFE_SPIRE_WIF.md">AZURE_SPIFFE_SPIRE_WIF.md</a></p>

<blockquote>
  <p><strong>Status:</strong> <a href="/product-tour/#local">Local Docker product tour</a> covers contracts → train → infer → Auditor (not a hardware TEE). Azure platform IaC includes Key Vault, Blob, and AKS Workload Identity (<a href="https://github.com/gitmujoshi/Confidential-AI-Network/blob/main/deployment/azure/terraform/README.md">Terraform README</a>). Confidential compute + <strong>Secure Key Release (SKR)</strong> are the clean-room target: JCS attestation is often <strong>simulated</strong>; DCsv3 / confidential containers + real SKR are <strong>Design / Phase 3</strong>.</p>
</blockquote>

<hr />

<h2 id="1-control-requirements-on-azure">1. Control requirements on Azure</h2>

<ol>
  <li>Can Microsoft operators, or TSP/CCRP operators, read dataset or model plaintext?</li>
  <li>Can the CAN control plane (Node API) hold DEK/MEK?</li>
  <li>What evidence shows <em>this</em> job ran in <em>this</em> attested environment under <em>this</em> contract?</li>
  <li>What happens when escrow times out or attestation fails?</li>
</ol>

<p>Layered answer:</p>

<table>
  <thead>
    <tr>
      <th>Layer</th>
      <th>Azure building block</th>
      <th>CAN rule</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Human identity</td>
      <td>Microsoft Entra ID + Conditional Access</td>
      <td>No Keycloak in Azure RGs</td>
    </tr>
    <tr>
      <td>App / party roles</td>
      <td>Entra app roles / groups (<code class="language-plaintext highlighter-rouge">TDC</code> · <code class="language-plaintext highlighter-rouge">TDP</code> · <code class="language-plaintext highlighter-rouge">TSP</code>/<code class="language-plaintext highlighter-rouge">CCRP</code> · <code class="language-plaintext highlighter-rouge">AppAdmin</code> · <code class="language-plaintext highlighter-rouge">Auditor</code>)</td>
      <td>Least privilege on APIs</td>
    </tr>
    <tr>
      <td>Ciphertext store</td>
      <td>Blob (private endpoints; CMK from Key Vault)</td>
      <td>Ciphertext only outside TEE</td>
    </tr>
    <tr>
      <td>Platform secrets</td>
      <td>Azure Key Vault</td>
      <td>Ops secrets ≠ DEK/MEK</td>
    </tr>
    <tr>
      <td>Principal keys</td>
      <td>Customer Key Vault / MHSM + SKR or attested TLS</td>
      <td>Platform never plaintext DEK/MEK</td>
    </tr>
    <tr>
      <td>Clean room</td>
      <td>Confidential VM (e.g. DCsv3 / SEV-SNP) or confidential containers</td>
      <td>Decrypt in memory only</td>
    </tr>
    <tr>
      <td>Evidence</td>
      <td>Azure Attestation + SCITT / provenance / Merkle</td>
      <td>Job-bound audit trail</td>
    </tr>
  </tbody>
</table>

<p>Microsoft docs worth keeping open: <a href="https://learn.microsoft.com/azure/attestation/">Azure Attestation</a> · <a href="https://learn.microsoft.com/azure/key-vault/managed-hsm/secure-key-release-overview">Secure Key Release overview</a> · <a href="https://learn.microsoft.com/azure/key-vault/">Azure Key Vault</a>.</p>

<hr />

<h2 id="2-threat-model-azure-clean-room-training">2. Threat model (Azure clean-room training)</h2>

<h3 id="21-assets">2.1 Assets</h3>

<table>
  <thead>
    <tr>
      <th>Asset</th>
      <th>Sensitivity</th>
      <th>Where it should live</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Dataset plaintext</td>
      <td>Critical</td>
      <td>TEE memory only, job window</td>
    </tr>
    <tr>
      <td>Base-model / weights plaintext</td>
      <td>Critical</td>
      <td>TEE memory only, job window</td>
    </tr>
    <tr>
      <td><strong>DEK</strong> / <strong>MEK</strong></td>
      <td>Critical</td>
      <td>Principal custody → released into TEE (never Node)</td>
    </tr>
    <tr>
      <td>Contract terms + signatures</td>
      <td>High</td>
      <td>App DB + optional SCITT; signing keys → Key Vault/MHSM target</td>
    </tr>
    <tr>
      <td>Blob ciphertext</td>
      <td>High</td>
      <td>Private Blob + CMK</td>
    </tr>
    <tr>
      <td>Portal / API tokens</td>
      <td>High</td>
      <td>Entra; short-lived</td>
    </tr>
    <tr>
      <td>Infra secrets (DB, TLS)</td>
      <td>High</td>
      <td>Platform Key Vault</td>
    </tr>
  </tbody>
</table>

<h3 id="22-adversaries-what-we-design-against">2.2 Adversaries (what we design against)</h3>

<table>
  <thead>
    <tr>
      <th>Adversary</th>
      <th>Goal</th>
      <th>Primary controls</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Curious cloud admin / host hypervisor</strong></td>
      <td>Read guest memory / disks</td>
      <td>Confidential VM memory encryption (e.g. AMD SEV-SNP); no plaintext on disk</td>
    </tr>
    <tr>
      <td><strong>Malicious or compromised TSP/CCRP operator</strong></td>
      <td>Exfiltrate via logs, sidecars, mis-SKU</td>
      <td>Attestation policy + SKR; fail closed if measurement wrong; no long-lived keys in pods</td>
    </tr>
    <tr>
      <td><strong>Compromised CAN control plane</strong></td>
      <td>Steal keys via API</td>
      <td>Node accepts <strong>signals</strong> / wrapped material only—<strong>rejects raw DEK/MEK bytes</strong></td>
    </tr>
    <tr>
      <td><strong>Rogue party / insider TDC or TDP</strong></td>
      <td>Train outside agreement</td>
      <td>Contract <strong>SIGNED</strong> gate; Open-GMASE side-effect deny; purpose / region bindings</td>
    </tr>
    <tr>
      <td><strong>Network attacker</strong></td>
      <td>Intercept keys or ciphertext</td>
      <td>Private endpoints, TLS, no public DB/Blob</td>
    </tr>
    <tr>
      <td><strong>Replay / confused deputy</strong></td>
      <td>Reuse old attestation or job id</td>
      <td>Fresh quotes; job-bound escrow deadline; destroy on expiry</td>
    </tr>
  </tbody>
</table>

<h3 id="23-what-confidential-computing-does-not-cover">2.3 What confidential computing does <em>not</em> cover</h3>

<ul>
  <li>It does <strong>not</strong> make bad contract terms safe.</li>
  <li>It does <strong>not</strong> prove the model is fair, accurate, or free of poisoning (see Auditor / Merkle for <em>lineage</em>, not ethics).</li>
  <li>It does <strong>not</strong> replace Entra MFA, WAF, or network segmentation.</li>
  <li>Local Docker demos deliberately sit <strong>outside</strong> this threat model—label them as UX, not TEE.</li>
</ul>

<pre><code class="language-mermaid">flowchart LR
  subgraph Outside["Outside TEE — ciphertext + policy"]
    Blob["Blob ciphertext"]
    CAN["CAN API / escrow signals"]
    Entra["Entra SSO"]
    KV["Key Vault / MHSM"]
  end
  subgraph TEE["Confidential VM / container"]
    Att["Attestation evidence"]
    Mem["Decrypt in memory"]
    Train["Train"]
    Out["Re-encrypt outputs · zeroize"]
  end
  Entra --&gt; CAN
  CAN --&gt;|"SIGNED + job"| TEE
  Att --&gt;|"SKR policy match"| KV
  KV --&gt;|"release DEK/MEK or unwrap"| Mem
  Blob --&gt; Mem
  Mem --&gt; Train --&gt; Out
</code></pre>

<hr />

<h2 id="3-azure-key-vault-layout-for-can">3. Azure Key Vault layout for CAN</h2>

<p>Do not collapse every secret into one vault key. Separate <strong>infra</strong>, <strong>signing</strong>, and <strong>principal crypto</strong>.</p>

<table>
  <thead>
    <tr>
      <th>Class</th>
      <th>Example name pattern</th>
      <th>Content</th>
      <th>Who uses it</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Platform secrets</td>
      <td><code class="language-plaintext highlighter-rouge">can-{env}-db-connection</code>, Entra client secret</td>
      <td>Ops</td>
      <td>Backend MSI / External Secrets</td>
    </tr>
    <tr>
      <td>Blob / PG CMK</td>
      <td>env-scoped CMK</td>
      <td>Disk/object encryption</td>
      <td>Storage / PostgreSQL</td>
    </tr>
    <tr>
      <td>Signing (target)</td>
      <td><code class="language-plaintext highlighter-rouge">can-{env}-user-sign-{depaId}</code></td>
      <td>Party signing key in HSM</td>
      <td>Sign via KV crypto ops; DB stores key id + public only</td>
    </tr>
    <tr>
      <td>Wrap / KEK (optional)</td>
      <td>Customer or platform wrap key</td>
      <td>Wrap session material</td>
      <td>Never a substitute for principal DEK/MEK</td>
    </tr>
    <tr>
      <td>Principal DEK/MEK</td>
      <td>In <strong>customer</strong> vault / MHSM or client HSM</td>
      <td>Dataset / model keys</td>
      <td>Released only under attestation + contract</td>
    </tr>
  </tbody>
</table>

<p>Contract JSON <code class="language-plaintext highlighter-rouge">kmsConfigs</code> should bind the Azure path parties expect, for example:</p>

<table>
  <thead>
    <tr>
      <th>Field</th>
      <th>Example</th>
      <th>Role</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">provider</code></td>
      <td><code class="language-plaintext highlighter-rouge">AZURE_KEY_VAULT</code> / MHSM</td>
      <td>Which key service</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">vaultUrl</code></td>
      <td><code class="language-plaintext highlighter-rouge">https://….vault.azure.net/</code></td>
      <td>Vault URI</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">keyId</code> / key name</td>
      <td>env-scoped</td>
      <td>Key reference principals agreed</td>
    </tr>
    <tr>
      <td>Region / residency</td>
      <td>contract <code class="language-plaintext highlighter-rouge">environmentSpecs</code></td>
      <td>Binding for audit</td>
    </tr>
  </tbody>
</table>

<p><strong>Maturity:</strong> configs are persisted today; training does not yet fully enforce live Key Vault calls on every path. Live resolve-at-train is a go-live checklist item (<a href="https://github.com/gitmujoshi/Confidential-AI-Network/blob/main/docs/deployment/AZURE_FEATURES_AND_CONFIGURATION.md">features catalog</a>).</p>

<hr />

<h2 id="4-secure-key-release-skr-policy">4. Secure Key Release (SKR) policy</h2>

<p><a href="https://learn.microsoft.com/azure/key-vault/managed-hsm/secure-key-release-overview">Secure Key Release</a> is Azure’s way to say: <em>this HSM-backed key may be released only to a workload that presents attestation claims matching a release policy</em>.</p>

<p>For CAN, SKR is the Azure-native twin of “attested TLS delivery of DEK/MEK into the TEE.”</p>

<h3 id="41-policy-intent-what-the-policy-should-encode">4.1 Policy intent (what the policy should encode)</h3>

<p>A useful SKR / attestation policy for a CAN job asserts roughly:</p>

<table>
  <thead>
    <tr>
      <th>Claim</th>
      <th>Why</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Confidential compute SKU / TEE type</td>
      <td>Not a normal node pool pretending to be clean</td>
    </tr>
    <tr>
      <td>Measurement / image / signer claims</td>
      <td>Trainer image matches what parties approved</td>
    </tr>
    <tr>
      <td>Attestation authority</td>
      <td>Azure Attestation (or agreed authority)</td>
    </tr>
    <tr>
      <td>Optional: environment / geography</td>
      <td>Residency bindings from the contract</td>
    </tr>
    <tr>
      <td>Optional: workload identity</td>
      <td>MSI / federated identity that may request release</td>
    </tr>
  </tbody>
</table>

<p>If claims fail → <strong>no key</strong>. Fail closed.</p>

<h3 id="42-how-skr-fits-dual-key-escrow">4.2 How SKR fits dual-key escrow</h3>

<p>CAN still needs <strong>both</strong> DEK and MEK (TDP + TDC). SKR does not remove dual-key escrow; it hardens <em>how</em> each key (or a wrap key) leaves the HSM:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Contract SIGNED
  → CCRP provisions confidential environment
  → TEE obtains attestation token (Azure Attestation)
  → Escrow OPEN (deadline)
  → TDP path: DEK (or wrap) released only if SKR/attestation policy OK
  → TDC path: MEK (or wrap) released only if SKR/attestation policy OK
  → BOTH_READY → decrypt in memory → train
  → Re-encrypt outputs · zeroize · DESTROY
</code></pre></div></div>

<p><strong>Alternate delivery:</strong> principals push DEK/MEK over <strong>attested TLS</strong> into the TEE without SKR, still never through the Node API. SKR is preferred when keys live in Azure Managed HSM / Key Vault with release policy.</p>

<h3 id="43-anti-patterns">4.3 Anti-patterns</h3>

<table>
  <thead>
    <tr>
      <th>Anti-pattern</th>
      <th>Why it fails the threat model</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Release key to AKS pod without confidential SKU</td>
      <td>Host admin / node compromise reads key</td>
    </tr>
    <tr>
      <td>Same SKR policy for all contracts</td>
      <td>Cross-job / cross-tenant confused deputy</td>
    </tr>
    <tr>
      <td>Log attestation tokens or key material</td>
      <td>Sentinel gold for attackers</td>
    </tr>
    <tr>
      <td>Soft-fail attestation “for demo” in prod</td>
      <td>Converts TEE into theater</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="5-end-to-end-training-on-azure">5. End-to-end training on Azure</h2>

<p>Two flows share the same product UX; only the <strong>crypto boundary</strong> differs.</p>

<h3 id="51-flow-a--portal-train-on-azure-compute-phase-1-pilot">5.1 Flow A — Portal train on Azure compute (Phase 1 pilot)</h3>

<p>Stakeholder path aligned with the <a href="/product/2026/08/16/azure-e2e-product-tour-deck/">Azure product tour deck</a>:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Entra SSO (MSAL) → Portal + APIM JWT
  → TDP publishes dataset (ciphertext preferred; demo clear only in non-prod)
  → TDC creates Ricardian contract (Azure env + Key Vault kmsConfigs)
  → TDP then TSP/CCRP sign
  → Optional SCITT claim
  → TDC starts training (ACI / AKS Job target)
  → Register artifact → deploy → predict (Open-GMASE gate when wired)
  → Auditor: Merkle tree + contract review
</code></pre></div></div>

<table>
  <thead>
    <tr>
      <th>Step</th>
      <th>Azure control</th>
      <th>Status</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Login</td>
      <td>Entra + Conditional Access</td>
      <td>Design → production</td>
    </tr>
    <tr>
      <td>Roles</td>
      <td>Entra app roles</td>
      <td>Design</td>
    </tr>
    <tr>
      <td>Sign</td>
      <td>Authz + Key Vault–backed keys (target)</td>
      <td>Partial / Design</td>
    </tr>
    <tr>
      <td>Train</td>
      <td>ACI / AKS Job / later DCsv3</td>
      <td>Partial scaffolding</td>
    </tr>
    <tr>
      <td>Artifacts</td>
      <td>Private Blob + CMK</td>
      <td>Design</td>
    </tr>
  </tbody>
</table>

<p>Use this when you need Azure tenancy smoke without full TEE custody on every path.</p>

<h3 id="52-flow-b--dual-key-escrow--confidential-clean-room-production-target">5.2 Flow B — Dual-key escrow → confidential clean room (production target)</h3>

<pre><code class="language-mermaid">sequenceDiagram
  participant Entra
  participant TDP
  participant TDC
  participant TSP as TSP / CCRP
  participant CAN as CAN + JCS
  participant AA as Azure Attestation
  participant KV as Key Vault / MHSM
  participant TEE as Confidential VM
  participant Blob

  Entra-&gt;&gt;CAN: Authenticated parties
  TDC-&gt;&gt;CAN: Create contract (Azure + kmsConfigs)
  TDP-&gt;&gt;CAN: Sign
  TSP-&gt;&gt;CAN: Sign → SIGNED
  TDC-&gt;&gt;CAN: Start training job
  TSP-&gt;&gt;TEE: Provision confidential SKU
  TEE-&gt;&gt;AA: Attestation evidence
  AA--&gt;&gt;TEE: Attestation token
  TEE-&gt;&gt;CAN: Attestation bundle (job-bound)
  TDP-&gt;&gt;TDP: Verify attestation ∧ contract
  TDC-&gt;&gt;TDC: Verify attestation ∧ contract
  TDP-&gt;&gt;KV: Authorize DEK / SKR
  TDC-&gt;&gt;KV: Authorize MEK / SKR
  KV-&gt;&gt;TEE: Release under policy (or attested TLS)
  Blob-&gt;&gt;TEE: Pull ciphertext
  TEE-&gt;&gt;TEE: Decrypt in memory → train
  TEE-&gt;&gt;Blob: Encrypted outputs
  TEE-&gt;&gt;TEE: Zeroize keys · destroy session
  TEE-&gt;&gt;CAN: Provenance / SCITT events
</code></pre>

<p>Same story as the multi-cloud <a href="/security/2026/08/16/can-tee-attest-decrypt-train/">TEE post</a>, with Azure-specific roots of trust (Attestation + SKR).</p>

<h3 id="53-provenance-events-grc-should-expect">5.3 Provenance events GRC should expect</h3>

<ul>
  <li>Contract signed (parties, hash, Key Vault refs)</li>
  <li>Job created (bound to <code class="language-plaintext highlighter-rouge">contractId</code>)</li>
  <li>Attestation presented / verified</li>
  <li>DEK released · MEK released (signals and/or SKR audit)</li>
  <li>Training started / completed / failed</li>
  <li>Session destroyed / keys zeroized</li>
  <li>Optional SCITT receipt + Auditor Merkle inclusion</li>
</ul>

<p>Timeout without both keys → <strong>EXPIRED / DESTROYED</strong>, not “retry forever with soft keys.”</p>

<hr />

<h2 id="6-maturity-matrix">6. Maturity matrix</h2>

<table>
  <thead>
    <tr>
      <th>Capability</th>
      <th>Local Docker tour</th>
      <th>Azure Phase 1</th>
      <th>Azure CAN prod</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Entra SSO</td>
      <td>Keycloak</td>
      <td>Required</td>
      <td>Required</td>
    </tr>
    <tr>
      <td>Contract → SIGNED → train UX</td>
      <td><strong>Live</strong></td>
      <td>Live / pilot</td>
      <td>Live</td>
    </tr>
    <tr>
      <td>Key Vault for infra secrets</td>
      <td>N/A / local</td>
      <td>Partial</td>
      <td>Required</td>
    </tr>
    <tr>
      <td>Signing keys in HSM</td>
      <td>No</td>
      <td>Design</td>
      <td>Required</td>
    </tr>
    <tr>
      <td>DEK/MEK principal custody</td>
      <td>Partial</td>
      <td>Design</td>
      <td>Required</td>
    </tr>
    <tr>
      <td>Dual-key escrow signals</td>
      <td>MVP</td>
      <td>Wire to Azure CCR</td>
      <td>Required</td>
    </tr>
    <tr>
      <td>Azure Attestation + SKR</td>
      <td>No</td>
      <td>Design</td>
      <td>Required</td>
    </tr>
    <tr>
      <td>Confidential VM / container train</td>
      <td><strong>No</strong></td>
      <td>Spike</td>
      <td>Required for CAN claims</td>
    </tr>
    <tr>
      <td>Auditor Merkle review</td>
      <td><strong>Live</strong></td>
      <td>Live</td>
      <td>Live</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="7-operator-checklist-crypto-go-live">7. Operator checklist (crypto go-live)</h2>

<ul class="task-list">
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Signing keys off DB plaintext → Key Vault / MHSM; verify on sign</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Blob containers <strong>ciphertext only</strong>; CMK on</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />DEK/MEK never logged; Node rejects raw key material</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Confidential SKU + attestation policy + SKR (or attested TLS) for CCR path</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Escrow timeout destroys compute; alert on late key attempts</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Provenance/SCITT for signed → attested → released → started → completed → destroyed</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />No Keycloak in Azure resource groups</li>
</ul>

<p>Full architecture and RBAC tables: <a href="https://github.com/gitmujoshi/Confidential-AI-Network/blob/main/docs/production/AZURE_SECURITY_ARCHITECTURE.md">AZURE_SECURITY_ARCHITECTURE.md §16</a>.</p>

<hr />

<h2 id="8-takeaways">8. Takeaways</h2>

<ol>
  <li><strong>Threat model first</strong> — confidential SKUs defeat host memory snooping; they do not replace contract gates or Entra.</li>
  <li><strong>Key Vault is layered</strong> — platform secrets, CMK, signing HSM, and principal DEK/MEK are different jobs.</li>
  <li><strong>SKR is policy-as-key-custody</strong> — release only to attested measurements the contract allows.</li>
  <li><strong>E2E train on Azure</strong> = Entra → SIGNED contract → attested environment → dual-key release → decrypt-in-memory → zeroize → provenance.</li>
  <li>Local product tour = runnable UX; this post = Azure confidential-compute target.</li>
</ol>

<p><strong>One sentence:</strong> On Azure, CAN treats training as decrypt-in-enclave under Entra identity, Key Vault custody, and Secure Key Release / attestation policy—never as “trust the TSP’s disk.”</p>]]></content><author><name></name></author><category term="security" /><category term="azure" /><category term="azure" /><category term="confidential-computing" /><category term="key-vault" /><category term="skr" /><category term="attestation" /><category term="dek" /><category term="mek" /><category term="aks" /><category term="tee" /><summary type="html"><![CDATA[How Confidential AI Network maps to Azure confidential VMs, Azure Attestation, Key Vault / Managed HSM, Secure Key Release policy, and the end-to-end train path from Entra sign-in to attested decrypt-in-memory.]]></summary></entry><entry><title type="html">Contract management in CAN — party signing keys, sign gates, and verification</title><link href="https://dpi-apps.space/product/2026/08/17/can-contract-management-signing/" rel="alternate" type="text/html" title="Contract management in CAN — party signing keys, sign gates, and verification" /><published>2026-08-17T00:00:00+00:00</published><updated>2026-08-17T00:00:00+00:00</updated><id>https://dpi-apps.space/product/2026/08/17/can-contract-management-signing</id><content type="html" xml:base="https://dpi-apps.space/product/2026/08/17/can-contract-management-signing/"><![CDATA[<p><em>Contracts in CAN are not “upload a PDF.” They are lifecycle state: create → party signs → <strong>SIGNED</strong> → train may start. Signing keys are a separate custody story from DEK/MEK.</em></p>

<p><strong>Related:</strong> <a href="/product/2026/08/16/ricardian-contracts-in-can/">Ricardian contracts</a> · <a href="/product/2026/08/14/can-contract-to-prediction/">Contract → prediction</a> · <a href="/security/2026/08/16/can-kms-dek-mek-escrow/">KMS DEK/MEK</a> · <a href="/security/2026/08/17/azure-confidential-computing-deep-dive/">Azure CC / Key Vault</a> · <a href="/security/2026/08/16/merkle-trees-model-audit/">Merkle / Auditor</a> · <a href="/product-tour/">Product tour</a> · In-repo: <a href="https://github.com/gitmujoshi/Confidential-AI-Network/blob/main/docs/features/contract-signing/CONTRACT_SIGNING_TECHNICAL_REFERENCE.md">CONTRACT_SIGNING_TECHNICAL_REFERENCE.md</a> · <a href="https://github.com/gitmujoshi/Confidential-AI-Network/blob/main/docs/features/contract-signing/CONTRACT_SIGNING_USER_GUIDE.md">CONTRACT_SIGNING_USER_GUIDE.md</a></p>

<blockquote>
  <p><strong>Status:</strong> Sign authorization (who may set <code class="language-plaintext highlighter-rouge">tdpSigned</code> / <code class="language-plaintext highlighter-rouge">tspSigned</code> and reach <code class="language-plaintext highlighter-rouge">SIGNED</code>) is <strong>live</strong>. Cryptographic verification against HSM-backed keys is <strong>target</strong> (<code class="language-plaintext highlighter-rouge">SIGNING_REQUIRE_CRYPTO_VERIFY</code> / Key Vault). Contract Detail often submits a hash or placeholder as <code class="language-plaintext highlighter-rouge">signature</code>. Party <strong>signing keys</strong> are distinct from DEK/MEK.</p>
</blockquote>

<hr />

<h2 id="1-two-key-classes-do-not-conflate">1. Two key classes (do not conflate)</h2>

<table>
  <thead>
    <tr>
      <th>Key class</th>
      <th>Purpose</th>
      <th>Owner</th>
      <th>Lives where (target)</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Party signing key</strong></td>
      <td>Bind a human/org to the Ricardian agreement</td>
      <td>Each party (TDC / TDP / TSP)</td>
      <td>Key Vault / MHSM (or client wallet); public material in app</td>
    </tr>
    <tr>
      <td><strong>DEK</strong></td>
      <td>Encrypt dataset ciphertext</td>
      <td><strong>TDP</strong></td>
      <td>Customer vault / HSM → TEE only after attestation</td>
    </tr>
    <tr>
      <td><strong>MEK</strong></td>
      <td>Encrypt base model ciphertext</td>
      <td><strong>TDC</strong></td>
      <td>Same pattern</td>
    </tr>
  </tbody>
</table>

<p>Signing keys answer: <em>Did this party approve <strong>these</strong> terms?</em><br />
DEK/MEK answer: <em>May plaintext exist in the clean room for this job?</em></p>

<p>Mixing them in one “KMS” slide confuses CISOs.</p>

<hr />

<h2 id="2-contract-management-lifecycle">2. Contract management lifecycle</h2>

<pre><code class="language-mermaid">stateDiagram-v2
  [*] --&gt; PENDING_TDP_APPROVAL: TDC creates Ricardian
  PENDING_TDP_APPROVAL --&gt; PENDING_TSP_APPROVAL: Linked TDP signs
  PENDING_TSP_APPROVAL --&gt; SIGNED: Assigned TSP signs
  SIGNED --&gt; Training: TDC starts job (gate)
  SIGNED --&gt; Inference: Deploy under contractId
  SIGNED --&gt; Audit: Auditor Merkle + contract review
</code></pre>

<table>
  <thead>
    <tr>
      <th>Stage</th>
      <th>What happens</th>
      <th>Primary APIs / artifacts</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Create</strong></td>
      <td>Wizard → legal template + machine bindings → <code class="language-plaintext highlighter-rouge">legalDocumentHash</code></td>
      <td><code class="language-plaintext highlighter-rouge">POST /api/contracts/ricardian</code></td>
    </tr>
    <tr>
      <td><strong>Notify</strong></td>
      <td>Linked TDPs / assigned TSP get signature requests</td>
      <td>Notifications</td>
    </tr>
    <tr>
      <td><strong>Sign</strong></td>
      <td>Party posts signature payload; status advances</td>
      <td><code class="language-plaintext highlighter-rouge">GET …/signing-data</code> · <code class="language-plaintext highlighter-rouge">POST …/sign</code></td>
    </tr>
    <tr>
      <td><strong>SIGNED</strong></td>
      <td>Training allowed</td>
      <td><code class="language-plaintext highlighter-rouge">status === 'SIGNED'</code> (TSP completion in current flow)</td>
    </tr>
    <tr>
      <td><strong>Evidence</strong></td>
      <td>SCITT <code class="language-plaintext highlighter-rouge">contract_approval</code>, Merkle <strong>contract</strong> leaf, provenance</td>
      <td>Auditor UI</td>
    </tr>
  </tbody>
</table>

<p>Human-readable terms + machine fields are covered in the <a href="/product/2026/08/16/ricardian-contracts-in-can/">Ricardian post</a>. This post focuses on <strong>keys, sign, and verify</strong>.</p>

<hr />

<h2 id="3-how-party-signing-keys-are-managed-today">3. How party signing keys are managed today</h2>

<h3 id="31-data-model">3.1 Data model</h3>

<p>Keys are stored as <strong><code class="language-plaintext highlighter-rouge">UserKey</code></strong> rows (<code class="language-plaintext highlighter-rouge">user_keys</code>):</p>

<table>
  <thead>
    <tr>
      <th>Field</th>
      <th>Role</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">userId</code></td>
      <td>Party user who owns the key</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">keyId</code></td>
      <td>Unique key id</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">keyType</code></td>
      <td>e.g. <code class="language-plaintext highlighter-rouge">ECDSA-P256</code>, <code class="language-plaintext highlighter-rouge">RSA-2048</code>, <code class="language-plaintext highlighter-rouge">RSA-4096</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">publicKey</code></td>
      <td>PEM / JWK — what verifiers should use</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">privateKey</code></td>
      <td>Optional TEXT — <strong>should not</strong> be platform plaintext in prod</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">keyStatus</code></td>
      <td><code class="language-plaintext highlighter-rouge">active</code> / <code class="language-plaintext highlighter-rouge">inactive</code> / <code class="language-plaintext highlighter-rouge">revoked</code> / <code class="language-plaintext highlighter-rouge">expired</code></td>
    </tr>
  </tbody>
</table>

<p>APIs under <code class="language-plaintext highlighter-rouge">/api/signing</code> (authenticated):</p>

<table>
  <thead>
    <tr>
      <th>Endpoint</th>
      <th>Behavior</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">GET /api/signing/keys</code></td>
      <td>List active keys (metadata; not private material in list)</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">POST /api/signing/keys/generate</code></td>
      <td>Generate pair via <code class="language-plaintext highlighter-rouge">keyManagementService</code>; persist key metadata</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">POST /api/signing/keys/import</code></td>
      <td>Import key material / public</td>
    </tr>
    <tr>
      <td>Events</td>
      <td><code class="language-plaintext highlighter-rouge">SigningEvent</code> rows for generate / import / use</td>
    </tr>
  </tbody>
</table>

<p>Config is env-driven (<code class="language-plaintext highlighter-rouge">KEY_ALGORITHMS</code>, <code class="language-plaintext highlighter-rouge">DEFAULT_KEY_ALGORITHM</code>, <code class="language-plaintext highlighter-rouge">KEY_ID_PREFIX</code>, …). The service can encrypt private PEM with a password helper; production design is <strong>not</strong> “store raw PEM forever in Postgres.”</p>

<h3 id="32-what-the-live-contract-detail-path-actually-does">3.2 What the live Contract Detail path actually does</h3>

<p>On the primary UI path (<code class="language-plaintext highlighter-rouge">ContractDetail</code>):</p>

<ol>
  <li><code class="language-plaintext highlighter-rouge">GET /api/contracts/:id/signing-data</code> → builds a <strong>message</strong> and <strong>SHA-256 <code class="language-plaintext highlighter-rouge">contractHash</code></strong>.</li>
  <li>UI sets <code class="language-plaintext highlighter-rouge">signature</code> to that hash <strong>or</strong> a <code class="language-plaintext highlighter-rouge">ui-{party}-…</code> placeholder.</li>
  <li><code class="language-plaintext highlighter-rouge">POST /api/contracts/:id/sign</code> with <code class="language-plaintext highlighter-rouge">{ signature, partyType, did?, walletAddress? }</code>.</li>
  <li>Backend checks <strong>auth</strong>: JWT party type, linked TDP / assigned TSP (<code class="language-plaintext highlighter-rouge">contractSigningGate</code>).</li>
  <li>Appends entry to <code class="language-plaintext highlighter-rouge">legalDocument.signatures[]</code>, sets <code class="language-plaintext highlighter-rouge">tdpSigned</code> / <code class="language-plaintext highlighter-rouge">tspSigned</code>, advances status.</li>
  <li>Best-effort SCITT <code class="language-plaintext highlighter-rouge">contract_approval</code> claim.</li>
</ol>

<p>So today the gate that matters for training is: <strong>authenticated party allowed to sign + status machine</strong>. It is <strong>not</strong> yet “ECDSA verify over <code class="language-plaintext highlighter-rouge">legalDocumentHash</code> with Key Vault key, fail closed.”</p>

<h3 id="33-richer-signing-surfaces-partial">3.3 Richer signing surfaces (partial)</h3>

<p>There are additional components (<code class="language-plaintext highlighter-rouge">ContractSigning</code>, DID modal, <code class="language-plaintext highlighter-rouge">es256sign.js</code> WebCrypto, <code class="language-plaintext highlighter-rouge">/api/signing/sign</code>) aimed at stronger crypto/DID flows. Additional scaffolding for stronger crypto/DID; product-tour clicks are not HSM-verified end-to-end.</p>

<hr />

<h2 id="4-sign-authorization-what-is-enforced">4. Sign authorization (what is enforced)</h2>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Authenticated user
  → partyType must match claimed partyType (rolesAllowSigning)
  → TDP: must be linked dataset owner (unless AppAdmin)
  → TSP: must be contract.tspId (unless AppAdmin)
  → Append legalDocument.signatures[]
  → TDP → PENDING_TSP_APPROVAL (typical)
  → TSP → SIGNED
</code></pre></div></div>

<p><strong>Runtime note:</strong> Training checks <strong><code class="language-plaintext highlighter-rouge">status === 'SIGNED'</code></strong>, reached when the <strong>assigned TSP</strong> completes the current flow. A <code class="language-plaintext highlighter-rouge">tdcSigned</code> column may exist; do not assume “all three roles must crypto-sign” is what local train enforces. Prefer the live path above (<a href="/product/2026/08/16/ricardian-contracts-in-can/">Ricardian §4.2</a>).</p>

<p><strong>Auditor</strong> never signs — read-only Merkle + contract review.</p>

<hr />

<h2 id="5-verification--today-vs-target">5. Verification — today vs target</h2>

<h3 id="51-today">5.1 Today</h3>

<table>
  <thead>
    <tr>
      <th>Check</th>
      <th>Status</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Role / linkage authz on <code class="language-plaintext highlighter-rouge">POST …/sign</code></td>
      <td><strong>Met</strong></td>
    </tr>
    <tr>
      <td>Persist signature blob + metadata</td>
      <td><strong>Met</strong> (in <code class="language-plaintext highlighter-rouge">legalDocument.signatures</code>)</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">verifyDIDSignature</code> helper (<code class="language-plaintext highlighter-rouge">didService.verifySignature</code>)</td>
      <td><strong>Exists</strong> — <strong>not wired</strong> into the main sign route</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">SIGNING_REQUIRE_CRYPTO_VERIFY</code> / <code class="language-plaintext highlighter-rouge">SIGNING_REQUIRE_DID_VERIFY</code></td>
      <td>Documented for prod; examples often <code class="language-plaintext highlighter-rouge">false</code> until Key Vault signing ships</td>
    </tr>
    <tr>
      <td>Independent re-verify of all signatures before train</td>
      <td><strong>Not</strong> the hard gate today — <strong>status</strong> is</td>
    </tr>
  </tbody>
</table>

<h3 id="52-target-azure--enterprise">5.2 Target (Azure / enterprise)</h3>

<table>
  <thead>
    <tr>
      <th>Step</th>
      <th>Behavior</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Generate</td>
      <td>Create ECDSA/RSA key in <strong>Key Vault / Managed HSM</strong>; app DB stores <strong>key id + public only</strong></td>
    </tr>
    <tr>
      <td>Sign</td>
      <td>Client or backend calls Key Vault <strong>sign</strong> over a stable message (ideally digest of <code class="language-plaintext highlighter-rouge">legalDocumentHash</code> + party + nonce)</td>
    </tr>
    <tr>
      <td>Verify</td>
      <td>On <code class="language-plaintext highlighter-rouge">POST …/sign</code> (and optionally at train start): verify signature with public key / DID document; fail closed if flags on</td>
    </tr>
    <tr>
      <td>Audit</td>
      <td>SCITT claim + Merkle contract leaf include hash + signature metadata</td>
    </tr>
  </tbody>
</table>

<p>Naming pattern (Azure): <code class="language-plaintext highlighter-rouge">can-{env}-user-sign-{depaId}</code> — see <a href="https://github.com/gitmujoshi/Confidential-AI-Network/blob/main/docs/production/AZURE_SECURITY_ARCHITECTURE.md">Azure security architecture §16.4</a>.</p>

<pre><code class="language-mermaid">sequenceDiagram
  participant Party
  participant UI
  participant CAN as CAN API
  participant KV as Key Vault / MHSM
  participant DB

  Party-&gt;&gt;UI: Approve terms
  UI-&gt;&gt;CAN: GET signing-data (message / hash)
  UI-&gt;&gt;KV: Sign digest (target)
  KV--&gt;&gt;UI: Signature
  UI-&gt;&gt;CAN: POST sign (signature, partyType, keyId/did)
  CAN-&gt;&gt;CAN: Authz gate
  CAN-&gt;&gt;CAN: Crypto verify (target / flag)
  CAN-&gt;&gt;DB: signatures[] + status
  CAN--&gt;&gt;UI: SIGNED or next pending
</code></pre>

<hr />

<h2 id="6-what-verification-means-for-auditors">6. What “verification” means for auditors</h2>

<table>
  <thead>
    <tr>
      <th>Question</th>
      <th>Mechanism</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Was this party allowed to approve?</td>
      <td>Authz + linkage at sign time</td>
    </tr>
    <tr>
      <td>What exact legal bytes?</td>
      <td><code class="language-plaintext highlighter-rouge">legalDocumentHash</code></td>
    </tr>
    <tr>
      <td>Who recorded approval?</td>
      <td><code class="language-plaintext highlighter-rouge">legalDocument.signatures[]</code> + SCITT <code class="language-plaintext highlighter-rouge">contract_approval</code></td>
    </tr>
    <tr>
      <td>Is the hash in the audit tree?</td>
      <td>Auditor <strong>Verify</strong> = Merkle <strong>inclusion</strong> under published root — not “model was ethical” (<a href="/security/2026/08/16/merkle-trees-model-audit/">Merkle post</a>)</td>
    </tr>
    <tr>
      <td>Was the ECDSA/DID signature valid?</td>
      <td><strong>Target</strong> crypto verify; Phase 1 UI is authz-gated</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="7-maturity-matrix">7. Maturity matrix</h2>

<table>
  <thead>
    <tr>
      <th>Capability</th>
      <th>Local demo today</th>
      <th>Azure / prod target</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Create Ricardian + hash</td>
      <td>Live</td>
      <td>Live</td>
    </tr>
    <tr>
      <td>Multi-party sign → SIGNED</td>
      <td>Live (authz)</td>
      <td>Live + crypto verify</td>
    </tr>
    <tr>
      <td>Party keys in <code class="language-plaintext highlighter-rouge">UserKey</code></td>
      <td>Live (public / partial private)</td>
      <td>Key id + public only</td>
    </tr>
    <tr>
      <td>Private key in Postgres</td>
      <td>Gap / demo risk</td>
      <td><strong>Forbidden</strong> — HSM only</td>
    </tr>
    <tr>
      <td>WebCrypto / DID verify on sign</td>
      <td>Partial / not main UI</td>
      <td>Required when claimed</td>
    </tr>
    <tr>
      <td>Key Vault sign ops</td>
      <td>Design</td>
      <td>Required</td>
    </tr>
    <tr>
      <td>Train gated on SIGNED</td>
      <td>Live</td>
      <td>Live</td>
    </tr>
    <tr>
      <td>DEK/MEK escrow</td>
      <td>Separate path</td>
      <td>Separate path + SKR</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="8-operator-checklist-signing-go-live">8. Operator checklist (signing go-live)</h2>

<ul class="task-list">
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" /><code class="language-plaintext highlighter-rouge">SIGNING_KEY_BACKEND=azure-keyvault</code> (or MHSM); no private PEM in DB</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" /><code class="language-plaintext highlighter-rouge">SIGNING_REQUIRE_CRYPTO_VERIFY=true</code></li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" /><code class="language-plaintext highlighter-rouge">SIGNING_REQUIRE_DID_VERIFY=true</code> when DID is present</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Sign message binds <strong><code class="language-plaintext highlighter-rouge">legalDocumentHash</code></strong> (not only a timestamp string)</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Train start optionally re-checks signature set / status</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Pen test: forged signature blob with wrong role / wrong party rejected</li>
  <li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />Keep DEK/MEK release APIs free of signing-key material and vice versa</li>
</ul>

<hr />

<h2 id="9-takeaways">9. Takeaways</h2>

<ol>
  <li><strong>Party signing keys</strong> prove agreement; <strong>DEK/MEK</strong> unlock clean-room plaintext — different custody.</li>
  <li><strong>Contract management</strong> is a state machine: create → TDP → TSP → <strong>SIGNED</strong> → train/infer/audit.</li>
  <li><strong>Today</strong> the hard gate is <strong>authenticated authorization + status</strong>; stored “signatures” may be hashes/placeholders on the main UI path.</li>
  <li><strong>Target</strong> is HSM/Key Vault sign + verify-on-submit (and optional verify-on-train), with public keys / DIDs in the app.</li>
  <li>Auditors verify <strong>lineage under Merkle</strong> and read the Ricardian; they do not get cryptographic signature verification until verify flags and Key Vault signing are enabled.</li>
</ol>

<p><strong>One sentence:</strong> CAN manages contracts as enforceable lifecycle state; party signing keys should live in Key Vault/HSM and be verified on sign—while today’s demos correctly gate training on who is allowed to mark the contract <strong>SIGNED</strong>.</p>]]></content><author><name></name></author><category term="product" /><category term="security" /><category term="can" /><category term="contracts" /><category term="signing" /><category term="keys" /><category term="ricardian" /><category term="verification" /><category term="key-vault" /><category term="depa" /><summary type="html"><![CDATA[How Confidential AI Network manages Ricardian contracts end to end: party signing keys, multi-party sign gates, what is cryptographically verified today versus the Key Vault / DID target, and how that differs from DEK/MEK.]]></summary></entry><entry><title type="html">SPIFFE/SPIRE with Azure — AKS Workload Identity and Entra federation</title><link href="https://dpi-apps.space/security/2026/08/17/spiffe-spire-azure-wif/" rel="alternate" type="text/html" title="SPIFFE/SPIRE with Azure — AKS Workload Identity and Entra federation" /><published>2026-08-17T00:00:00+00:00</published><updated>2026-08-17T00:00:00+00:00</updated><id>https://dpi-apps.space/security/2026/08/17/spiffe-spire-azure-wif</id><content type="html" xml:base="https://dpi-apps.space/security/2026/08/17/spiffe-spire-azure-wif/"><![CDATA[<p><em>Humans use Entra. Pods must not share a node’s credentials forever. Peers prove who they are with SPIFFE. Azure APIs get short-lived tokens—natively on AKS or by exchanging a SPIFFE JWT-SVID.</em></p>

<p><strong>Related:</strong> <a href="/security/2026/07/28/three-identity-planes/">Three identity planes</a> · <a href="/security/2026/07/28/spiffe-spire-oci-wif/">SPIFFE on OCI</a> · <a href="/security/2026/08/17/azure-confidential-computing-deep-dive/">Azure confidential computing</a> · <a href="/security/2026/07/28/azure-entra-security-architecture/">Azure Entra architecture</a> · <a href="/product/2026/08/17/can-contract-management-signing/">Contract signing keys</a> · In-repo: <a href="https://github.com/gitmujoshi/Confidential-AI-Network/blob/main/docs/deployment/AZURE_SPIFFE_SPIRE_WIF.md">AZURE_SPIFFE_SPIRE_WIF.md</a> · <a href="https://github.com/gitmujoshi/Confidential-AI-Network/blob/main/deployment/azure/terraform/README.md">Azure Terraform README</a></p>

<blockquote>
  <p><strong>Status:</strong> <strong>Path N is in Terraform</strong> (<code class="language-plaintext highlighter-rouge">enable_workload_identity</code>, default on): AKS OIDC issuer, user-assigned identities, federated credentials, Key Vault Secrets User + Blob Data Contributor for <code class="language-plaintext highlighter-rouge">backend</code> / <code class="language-plaintext highlighter-rouge">training-job</code> / <code class="language-plaintext highlighter-rouge">external-secrets</code>. <strong>SPIRE</strong> is scaffolded (<code class="language-plaintext highlighter-rouge">enable_spire</code> + Helm values)—full mesh and <strong>Path F</strong> (SPIFFE JWT → Entra) remain phased. Microsoft Path F tutorial: <a href="https://learn.microsoft.com/entra/workload-id/workload-identity-federation-spiffe-spire">Federate SPIFFE/SPIRE with Entra ID</a>.</p>
</blockquote>

<hr />

<h2 id="1-the-three-planes-on-azure-again">1. The three planes on Azure (again)</h2>

<table>
  <thead>
    <tr>
      <th>Plane</th>
      <th>Mechanism</th>
      <th>CAN use</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Humans</strong></td>
      <td>Microsoft Entra ID</td>
      <td>Portal / API roles (TDC, TDP, TSP, …)</td>
    </tr>
    <tr>
      <td><strong>Workloads → Azure APIs</strong></td>
      <td>AKS Workload Identity <strong>or</strong> Entra WIF via SPIFFE JWT</td>
      <td>Key Vault, Blob, ACR — no static SP secrets in pods</td>
    </tr>
    <tr>
      <td><strong>Workload → workload</strong></td>
      <td>SPIFFE/SPIRE X.509 SVID + mTLS</td>
      <td>Backend ↔ trainer ↔ CAN escrow / CCR</td>
    </tr>
  </tbody>
</table>

<p>SPIFFE does <strong>not</strong> replace <a href="/security/2026/08/17/azure-confidential-computing-deep-dive/">TEE attestation / SKR</a> for DEK/MEK release. It answers <em>which process</em>; the enclave answers <em>what hardware measurement</em>.</p>

<hr />

<h2 id="2-two-azure-paths">2. Two Azure paths</h2>

<h3 id="path-n--native-aks-workload-identity-iac-ready">Path N — native AKS Workload Identity (<strong>IaC ready</strong>)</h3>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Pod SA → federated Entra identity → Azure RBAC → Key Vault / Blob
(+ later: SPIRE X.509 SVID for east-west mTLS)
</code></pre></div></div>

<p>Best for pods that stay on AKS and only need Azure APIs. Wired in <code class="language-plaintext highlighter-rouge">deployment/azure/terraform/modules/workload_identity</code>.</p>

<h3 id="path-f--spire-jwt--entra-federation-design">Path F — SPIRE JWT → Entra federation (<strong>design</strong>)</h3>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>SPIRE JWT-SVID (aud = api://AzureADTokenExchange)
  → Entra federated identity credential (issuer = SPIRE OIDC, subject = exact SPIFFE ID)
  → Access token → Azure SDK (ClientAssertionCredential)
</code></pre></div></div>

<p>Best when the <strong>same SPIFFE ID</strong> must work off-cluster (CI, multi-cloud CCR) or you want one portable identity mapped into Entra.</p>

<pre><code class="language-mermaid">flowchart TB
  subgraph Humans["Plane A"]
    EntraH[Entra SSO]
  end
  subgraph Peers["Plane C — SPIFFE"]
    SPIRE[SPIRE Server]
    Backend[Backend]
    Trainer[Trainer Job]
    CCR[CCR / confidential]
    SPIRE --&gt; Backend
    SPIRE --&gt; Trainer
    SPIRE --&gt; CCR
    Backend &lt;--&gt;|mTLS X.509 SVID| Trainer
    Trainer &lt;--&gt;|mTLS| CCR
  end
  subgraph AzureAPIs["Plane B — Azure"]
    KV[Key Vault]
    Blob[Blob]
    PathN[AKS Workload Identity]
    PathF[Entra WIF via JWT-SVID]
    PathN --&gt; KV
    PathN --&gt; Blob
    PathF --&gt; KV
    PathF --&gt; Blob
  end
  EntraH --&gt; Backend
  Backend --&gt; PathN
  Trainer --&gt; PathN
  CCR --&gt; PathF
</code></pre>

<hr />

<h2 id="3-spiffe-ids-for-can-on-azure">3. SPIFFE IDs for CAN on Azure</h2>

<p>Trust domain example: <code class="language-plaintext highlighter-rouge">spiffe://can.{env}.azure.example</code></p>

<table>
  <thead>
    <tr>
      <th>Workload</th>
      <th>Path example</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Backend</td>
      <td><code class="language-plaintext highlighter-rouge">/ns/contract-management/sa/backend</code></td>
    </tr>
    <tr>
      <td>Training Job</td>
      <td><code class="language-plaintext highlighter-rouge">/ns/cms-training/sa/training-job</code></td>
    </tr>
    <tr>
      <td>CAN JCS</td>
      <td><code class="language-plaintext highlighter-rouge">/ns/cms-can/sa/can-jcs</code></td>
    </tr>
    <tr>
      <td>CCR agent</td>
      <td><code class="language-plaintext highlighter-rouge">/ns/cms-can/sa/can-ccr</code></td>
    </tr>
    <tr>
      <td>External Secrets</td>
      <td><code class="language-plaintext highlighter-rouge">/ns/external-secrets/sa/eso</code></td>
    </tr>
  </tbody>
</table>

<p><strong>Prod rule:</strong> Entra federated credential <code class="language-plaintext highlighter-rouge">subject</code> = <strong>exact</strong> SPIFFE ID — no wildcards.</p>

<hr />

<h2 id="4-what-ships-when">4. What ships when</h2>

<table>
  <thead>
    <tr>
      <th>Phase</th>
      <th>Outcome</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Design</strong></td>
      <td>This post + <a href="https://github.com/gitmujoshi/Confidential-AI-Network/blob/main/docs/deployment/AZURE_SPIFFE_SPIRE_WIF.md">AZURE_SPIFFE_SPIRE_WIF.md</a></td>
    </tr>
    <tr>
      <td><strong>Path N (done)</strong></td>
      <td>AKS OIDC + UAMI + FIC + KV/Blob RBAC — <code class="language-plaintext highlighter-rouge">enable_workload_identity</code></td>
    </tr>
    <tr>
      <td><strong>Key Vault + Blob (done)</strong></td>
      <td><code class="language-plaintext highlighter-rouge">enable_key_vault</code> / <code class="language-plaintext highlighter-rouge">enable_storage</code> (default on)</td>
    </tr>
    <tr>
      <td><strong>SPIRE scaffold (partial)</strong></td>
      <td><code class="language-plaintext highlighter-rouge">enable_spire</code> + <code class="language-plaintext highlighter-rouge">deployment/azure/helm/spire/values.yaml</code></td>
    </tr>
    <tr>
      <td><strong>Path F</strong></td>
      <td>SPIRE OIDC Discovery + Entra FICs for SPIFFE subjects</td>
    </tr>
    <tr>
      <td><strong>CCR + SKR</strong></td>
      <td>Session IDs bound to Attestation / Secure Key Release</td>
    </tr>
  </tbody>
</table>

<p>Local Docker still has no hardware SPIRE story. Azure pilot can claim <strong>Path N short-lived cloud access</strong> without claiming a full SPIFFE mesh.</p>

<hr />

<h2 id="5-takeaways">5. Takeaways</h2>

<ol>
  <li><strong>Entra for people; SPIFFE for peers; AKS WI / Entra WIF for Azure APIs.</strong></li>
  <li>Prefer <strong>Path N</strong> on AKS (now in TF); use <strong>Path F</strong> for portable / off-cluster SPIFFE.</li>
  <li><strong>Exact</strong> SPIFFE subjects on federated credentials.</li>
  <li>Pair with <strong>Attestation + SKR</strong> for DEK/MEK — SPIFFE alone is not a clean-room.</li>
  <li>Apply with <a href="https://github.com/gitmujoshi/Confidential-AI-Network/blob/main/deployment/azure/terraform/README.md">Azure Terraform README</a>; optional SPIRE via Helm after <code class="language-plaintext highlighter-rouge">enable_spire=true</code>.</li>
</ol>

<p><strong>One sentence:</strong> On Azure, CAN’s Zero Trust plan is SPIRE for east-west identity and either AKS Workload Identity or SPIFFE→Entra token exchange for northbound cloud APIs—never long-lived keys in the training pod.</p>]]></content><author><name></name></author><category term="security" /><category term="azure" /><category term="identity" /><category term="spiffe" /><category term="spire" /><category term="azure" /><category term="aks" /><category term="entra" /><category term="workload-identity" /><category term="zero-trust" /><summary type="html"><![CDATA[How Confidential AI Network combines SPIFFE/SPIRE peer identity with AKS Workload Identity and Entra Workload Identity Federation—Path N is in Terraform; Path F and full SPIRE mesh remain phased.]]></summary></entry><entry><title type="html">Azure product tour deck — Entra to governed prediction</title><link href="https://dpi-apps.space/product/2026/08/16/azure-e2e-product-tour-deck/" rel="alternate" type="text/html" title="Azure product tour deck — Entra to governed prediction" /><published>2026-08-16T00:00:00+00:00</published><updated>2026-08-16T00:00:00+00:00</updated><id>https://dpi-apps.space/product/2026/08/16/azure-e2e-product-tour-deck</id><content type="html" xml:base="https://dpi-apps.space/product/2026/08/16/azure-e2e-product-tour-deck/"><![CDATA[<p><a href="/assets/decks/azure-e2e-product-tour.html">Open the Azure E2E product tour deck</a> (←/→ or on-screen buttons).</p>

<p>Narrative: Entra → Ricardian contract → Key Vault / confidential compute (attest → DEK/MEK → decrypt-in-memory → train) → provenance → deploy/predict under Open-GMASE, with CompliancePulse on the decision path. Design/pilot slides are labeled as such in the deck.</p>

<table>
  <thead>
    <tr>
      <th>Resource</th>
      <th>Link</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Interactive deck</strong></td>
      <td><a href="/assets/decks/azure-e2e-product-tour.html">azure-e2e-product-tour.html</a></td>
    </tr>
    <tr>
      <td>Speaker notes</td>
      <td><a href="https://github.com/gitmujoshi/Confidential-AI-Network/blob/main/docs/marketing/AZURE_E2E_PRODUCT_TOUR_DECK.md">AZURE_E2E_PRODUCT_TOUR_DECK.md</a></td>
    </tr>
    <tr>
      <td>UI tour</td>
      <td><a href="/product-tour/">Product tour</a> (Local; swap Azure captures when available)</td>
    </tr>
    <tr>
      <td>Entra architecture</td>
      <td><a href="/security/2026/07/28/azure-entra-security-architecture/">Azure security architecture</a></td>
    </tr>
    <tr>
      <td>Confidential computing</td>
      <td><a href="/security/2026/08/17/azure-confidential-computing-deep-dive/">Threat model · Key Vault · SKR · e2e</a></td>
    </tr>
    <tr>
      <td>SPIFFE / WI</td>
      <td><a href="/security/2026/08/17/spiffe-spire-azure-wif/">SPIFFE/SPIRE on Azure</a></td>
    </tr>
    <tr>
      <td>Terraform (pilot)</td>
      <td><a href="https://github.com/gitmujoshi/Confidential-AI-Network/blob/main/deployment/azure/terraform/README.md">deployment/azure/terraform</a></td>
    </tr>
    <tr>
      <td>KMS / TEE</td>
      <td><a href="/security/2026/08/16/can-kms-dek-mek-escrow/">DEK·MEK</a> · <a href="/security/2026/08/16/can-tee-attest-decrypt-train/">TEE attest → decrypt</a></td>
    </tr>
  </tbody>
</table>

<p>DEPA context: <a href="https://depa.world">depa.world</a>.</p>]]></content><author><name></name></author><category term="product" /><category term="azure" /><category term="azure" /><category term="entra" /><category term="product-tour" /><category term="deck" /><category term="can" /><category term="kms" /><category term="tee" /><summary type="html"><![CDATA[Stakeholder slide deck for the Confidential AI Network end-to-end narrative on Microsoft Azure — open in the browser and present with arrow keys.]]></summary></entry><entry><title type="html">KMS for Confidential AI Network — DEK, MEK, and dual-key escrow</title><link href="https://dpi-apps.space/security/2026/08/16/can-kms-dek-mek-escrow/" rel="alternate" type="text/html" title="KMS for Confidential AI Network — DEK, MEK, and dual-key escrow" /><published>2026-08-16T00:00:00+00:00</published><updated>2026-08-16T00:00:00+00:00</updated><id>https://dpi-apps.space/security/2026/08/16/can-kms-dek-mek-escrow</id><content type="html" xml:base="https://dpi-apps.space/security/2026/08/16/can-kms-dek-mek-escrow/"><![CDATA[<p><em>Key management for multi-party training: ciphertext everywhere outside the clean room, dual-key escrow before train, cloud KMS as the outer key service—not a shared “god key” for the lake.</em></p>

<p><strong>Companion:</strong> <a href="/security/2026/08/16/can-tee-attest-decrypt-train/">TEE execution — attest, verify contract, then decrypt</a> · <a href="/security/2026/08/17/azure-confidential-computing-deep-dive/">Azure confidential computing (SKR / Key Vault)</a> · <strong>Lifecycle source of truth:</strong> <a href="https://github.com/gitmujoshi/Confidential-AI-Network/blob/main/docs/guides/PARTICIPANT_ONBOARDING_AND_E2E_LIFECYCLE.md">Participant onboarding &amp; E2E</a> · <strong>Product loop:</strong> <a href="/product/2026/08/14/can-contract-to-prediction/">Contract to governed prediction</a></p>

<blockquote>
  <p><strong>Status:</strong> Architecture and partial implementation. Local demos often train on staged artifacts without a hardware TEE. CAN/JCS Phase 1 uses <strong>key-release signals</strong> (no key bytes to the Node API). <strong>Attested TLS delivery of DEK/MEK into the enclave</strong> is the Phase 2 target.</p>
</blockquote>

<hr />

<h2 id="1-why-kms-matters-in-can">1. Why KMS matters in CAN</h2>

<p>CAN is inspired by iSPIRT’s <strong><a href="https://depa.world">DEPA</a></strong> (Data Empowerment and Protection Architecture): use-bound, accountable sharing—not a central data lake. Cryptographically that means:</p>

<ol>
  <li>The <strong>platform must not</strong> hold principal-owned dataset or model keys in plaintext.</li>
  <li><strong>Ciphertext</strong> may live in object storage or the catalog path; <strong>plaintext</strong> exists only inside an attested clean room for a bounded job window.</li>
  <li>Training starts only when <strong>both</strong> data and model keys are released under contract + attestation policy (<strong>dual-key escrow</strong>).</li>
</ol>

<p>Without that discipline, “confidential training” collapses to “trust the operator’s disk.”</p>

<hr />

<h2 id="2-two-principal-owned-keys">2. Two principal-owned keys</h2>

<table>
  <thead>
    <tr>
      <th>Key</th>
      <th>Name</th>
      <th>Owner</th>
      <th>Protects</th>
      <th>Typical algorithm</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>DEK</strong></td>
      <td>Data Encryption Key</td>
      <td><strong>TDP</strong> / data principal</td>
      <td>Training dataset</td>
      <td>AES-256-GCM (design)</td>
    </tr>
    <tr>
      <td><strong>MEK</strong></td>
      <td>Model Encryption Key</td>
      <td><strong>TDC</strong> / model owner</td>
      <td>Base model / weights IP</td>
      <td>AES-256-GCM (design)</td>
    </tr>
  </tbody>
</table>

<pre><code class="language-mermaid">flowchart TB
  TDP["TDP"]
  TDC["TDC"]
  Store["Object storage / catalog&lt;br/&gt;ciphertext only"]
  Escrow["CAN / JCS escrow&lt;br/&gt;release signals"]
  TEE["CCR / TEE&lt;br/&gt;plaintext window"]

  TDP --&gt;|"encrypt with DEK"| Store
  TDC --&gt;|"encrypt with MEK"| Store
  TDP -.-&gt;|"DEK release if policy OK"| Escrow
  TDC -.-&gt;|"MEK release if policy OK"| Escrow
  Escrow --&gt;|"both ready"| TEE
  Store --&gt;|"pull ciphertext"| TEE
</code></pre>

<p><strong>Rule of thumb:</strong> DEK and MEK are <strong>not</strong> the same as cloud “customer managed keys” for disk encryption of the portal database. Those are infrastructure. DEK/MEK are <strong>workload secrets for the training job</strong>, owned by parties to the Ricardian contract.</p>

<hr />

<h2 id="3-what-kms-means-in-this-stack">3. What “KMS” means in this stack</h2>

<p>CAN talks to <strong>key services</strong> at two layers:</p>

<table>
  <thead>
    <tr>
      <th>Layer</th>
      <th>Examples</th>
      <th>Role</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Cloud KMS / Vault</strong></td>
      <td>OCI Vault, Azure Key Vault, AWS KMS, GCP KMS</td>
      <td>Wrap/store customer keys, HSM-backed operations, IAM-bound use</td>
    </tr>
    <tr>
      <td><strong>CAN / JCS coordination</strong></td>
      <td><code class="language-plaintext highlighter-rouge">/api/can/jcs/*</code> job escrow</td>
      <td>Record <strong>when</strong> DEK/MEK may be released; bind to contract + CCR session; timeout → destroy</td>
    </tr>
  </tbody>
</table>

<p>Wizard fields such as <code class="language-plaintext highlighter-rouge">kmsConfigs</code> on contracts capture <strong>which provider / region / key id</strong> the parties expect for the clean-room path. The CCRP / TSP offering must be able to run in an environment that can use those keys under IAM and attestation policy.</p>

<p>Deep design notes in-repo:</p>

<ul>
  <li><a href="https://github.com/gitmujoshi/Confidential-AI-Network/blob/main/docs/architecture/KMS_TRAINING_ENVIRONMENT_ARCHITECTURE.md">KMS_TRAINING_ENVIRONMENT_ARCHITECTURE.md</a></li>
  <li><a href="https://github.com/gitmujoshi/Confidential-AI-Network/blob/main/docs/architecture/MULTI_TENANT_KMS_ARCHITECTURE.md">MULTI_TENANT_KMS_ARCHITECTURE.md</a></li>
  <li><a href="https://github.com/gitmujoshi/Confidential-AI-Network/blob/main/docs/architecture/DECENTRALIZED_KMS_ARCHITECTURE.md">DECENTRALIZED_KMS_ARCHITECTURE.md</a></li>
</ul>

<hr />

<h2 id="4-dual-key-escrow-the-gate-before-train">4. Dual-key escrow (the gate before train)</h2>

<p>Target sequence:</p>

<ol>
  <li>Contract is <strong>SIGNED</strong> (all required parties).</li>
  <li>CCRP provisions a clean-room session (TEE / confidential VM / attested K8s job).</li>
  <li>Job enters escrow: waiting for <strong>DEK released</strong> and <strong>MEK released</strong>.</li>
  <li>Each principal releases <strong>only after</strong> verifying attestation + contract binding (see <a href="/security/2026/08/16/can-tee-attest-decrypt-train/">TEE post</a>).</li>
  <li>When <strong>both</strong> signals (and, in Phase 2, key material into the TEE) are present → training may start.</li>
  <li>Hard timeout → session <strong>EXPIRED</strong> / CCR <strong>DESTROYED</strong>; keys must be zeroized in a real enclave.</li>
</ol>

<p><strong>Phase 1 MVP:</strong> principals post <code class="language-plaintext highlighter-rouge">key-released</code> <strong>signals</strong> with <code class="language-plaintext highlighter-rouge">keyType: DEK|MEK</code>. The API <strong>rejects raw key bytes</strong> to the Node process. Coordinates release without accepting key material into the Node API.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Illustrative — see CAN_QUICKSTART in the repo</span>
POST /api/can/jcs/jobs
POST /api/can/jcs/jobs/<span class="o">{</span><span class="nb">id</span><span class="o">}</span>/attestation   <span class="c"># bundle (simulated today)</span>
POST /api/can/jcs/jobs/<span class="o">{</span><span class="nb">id</span><span class="o">}</span>/key-released  <span class="c"># keyType: DEK</span>
POST /api/can/jcs/jobs/<span class="o">{</span><span class="nb">id</span><span class="o">}</span>/key-released  <span class="c"># keyType: MEK</span>
<span class="c"># → release → CCR executor may start</span>
</code></pre></div></div>

<hr />

<h2 id="5-encryption-modes-maturity">5. Encryption modes (maturity)</h2>

<table>
  <thead>
    <tr>
      <th>Mode</th>
      <th>Who encrypts</th>
      <th>Who holds DEK/MEK</th>
      <th>Decrypt where</th>
      <th>Maturity</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Local demo / Docker train</td>
      <td>Often staged plaintext or demo artifacts</td>
      <td>N/A for host path</td>
      <td>Host trainer</td>
      <td><strong>Live</strong> (host path)</td>
    </tr>
    <tr>
      <td>Platform-assisted encrypt</td>
      <td>Platform path</td>
      <td>Risk: platform custody</td>
      <td>Varies</td>
      <td>Partial / legacy paths</td>
    </tr>
    <tr>
      <td>TDP/TDC local encrypt</td>
      <td>Principal before upload</td>
      <td>Principal only</td>
      <td>TEE after attested release</td>
      <td><strong>Design</strong> (<a href="https://github.com/gitmujoshi/Confidential-AI-Network/blob/main/docs/flows/TDP_ENCRYPTED_DATASET_TEE_FLOW.md">TDP flow</a> · <a href="https://github.com/gitmujoshi/Confidential-AI-Network/blob/main/docs/flows/TDC_ENCRYPTED_AI_MODEL_TEE_FLOW.md">TDC flow</a>)</td>
    </tr>
    <tr>
      <td>CAN principal DEK/MEK + attested TLS</td>
      <td>Principal</td>
      <td>Principal</td>
      <td>CCR via attested channel</td>
      <td><strong>Target Phase 2</strong></td>
    </tr>
  </tbody>
</table>

<p>For stakeholder demos of <em>contracts → train → infer</em>, the <a href="/product/2026/08/14/can-contract-to-prediction/">local Docker path</a> is the right story. For <em>keys and clean rooms</em>, see <a href="/security/2026/08/16/can-kms-dek-mek-escrow/">KMS / DEK·MEK</a> and <a href="/security/2026/08/16/can-tee-attest-decrypt-train/">TEE attest → decrypt</a>.</p>

<hr />

<h2 id="6-what-auditors-should-ask">6. What auditors should ask</h2>

<table>
  <thead>
    <tr>
      <th>Question</th>
      <th>Good answer</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Does the SaaS hold DEK/MEK plaintext?</td>
      <td><strong>No</strong> in the target model; Phase 1 API refuses key material.</td>
    </tr>
    <tr>
      <td>When does decrypt happen?</td>
      <td>Only after <strong>contract verification</strong> + <strong>hardware (or simulated) attestation</strong> + <strong>dual release</strong>.</td>
    </tr>
    <tr>
      <td>What if escrow times out?</td>
      <td>Session destroyed; no lingering training window.</td>
    </tr>
    <tr>
      <td>How does this relate to Open-GMASE?</td>
      <td>OPA can gate <strong>start_training</strong> even after keys exist; KMS/TEE answer <em>where plaintext may exist</em>, G-MASE answers <em>whether the side effect may run</em>.</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="7-takeaways">7. Takeaways</h2>

<ol>
  <li><strong>DEK ≠ MEK</strong> — data principal and model owner keep separate custody.</li>
  <li><strong>Dual-key escrow</strong> is the economic and cryptographic AND-gate before train.</li>
  <li><strong>Cloud KMS</strong> wraps infrastructure and customer keys; <strong>CAN/JCS</strong> orchestrates release against the Ricardian contract.</li>
  <li>Local demos cover product UX; <strong>attested key delivery into TEE</strong> is the clean-room target.</li>
</ol>

<p>Next: <a href="/security/2026/08/16/can-tee-attest-decrypt-train/">TEE execution — attestation, contract check, decrypt-in-memory</a>.</p>]]></content><author><name></name></author><category term="security" /><category term="can" /><category term="kms" /><category term="dek" /><category term="mek" /><category term="encryption" /><category term="escrow" /><category term="depa" /><category term="tee" /><summary type="html"><![CDATA[How CAN separates dataset keys (DEK) and model keys (MEK), why the platform must not hold plaintext, and how escrow gates release until contract and attestation conditions are met.]]></summary></entry><entry><title type="html">TEE training in CAN — attest the enclave, verify the contract, then decrypt</title><link href="https://dpi-apps.space/security/2026/08/16/can-tee-attest-decrypt-train/" rel="alternate" type="text/html" title="TEE training in CAN — attest the enclave, verify the contract, then decrypt" /><published>2026-08-16T00:00:00+00:00</published><updated>2026-08-16T00:00:00+00:00</updated><id>https://dpi-apps.space/security/2026/08/16/can-tee-attest-decrypt-train</id><content type="html" xml:base="https://dpi-apps.space/security/2026/08/16/can-tee-attest-decrypt-train/"><![CDATA[<p><em>The clean-room rule: ciphertext may travel; plaintext and keys exist only inside an attested TEE for the training window—and only after the contract says that environment is allowed.</em></p>

<p><strong>Companion:</strong> <a href="/security/2026/08/16/can-kms-dek-mek-escrow/">KMS — DEK, MEK, and dual-key escrow</a> · <a href="/security/2026/08/17/azure-confidential-computing-deep-dive/">Azure confidential computing deep dive</a> · <strong>Flows:</strong> <a href="https://github.com/gitmujoshi/Confidential-AI-Network/blob/main/docs/flows/TDP_ENCRYPTED_DATASET_TEE_FLOW.md">TDP encrypted dataset</a> · <a href="https://github.com/gitmujoshi/Confidential-AI-Network/blob/main/docs/flows/TDC_ENCRYPTED_AI_MODEL_TEE_FLOW.md">TDC encrypted model</a> · <strong>iSPIRT DEPA:</strong> <a href="https://depa.world">depa.world</a></p>

<blockquote>
  <p><strong>Status:</strong> Target for CCRP / confidential-compute paths (Azure confidential computing, OCI confidential VMs, etc.). Local Docker / native training is a host path. CAN/JCS uses <strong>simulated attestation bundles</strong> and <strong>key-release signals</strong>; attested TLS / SKR key delivery is Phase 2+.</p>
</blockquote>

<hr />

<h2 id="1-decrypt-gate">1. Decrypt gate</h2>

<p>Requirement: <em>Can the clean-room operator, or the SaaS, read our data and model?</em></p>

<p>Control: a <strong>decrypt gate</strong> with two locks:</p>

<ol>
  <li><strong>Hardware attestation</strong> — the enclave proves its measurement / identity (CPU/firmware/image claims the cloud vendor supports).</li>
  <li><strong>Contract verification</strong> — the Ricardian agreement names allowed regions, TEE requirements, parties, and use; keys release only for <strong>that</strong> job/session.</li>
</ol>

<p>Only then may <strong>DEK</strong> (dataset) and <strong>MEK</strong> (model) enter the TEE so ciphertext can be decrypted <strong>in memory</strong>, training can run, outputs can be re-encrypted, and keys zeroized when the session ends.</p>

<p>That is DEPA-shaped thinking for enterprises: <strong>use-bound access with evidence</strong>, not bulk export into a lake.</p>

<hr />

<h2 id="2-end-to-end-sequence-target">2. End-to-end sequence (target)</h2>

<pre><code class="language-mermaid">sequenceDiagram
  participant TDP
  participant TDC
  participant CAN as CAN / Contract
  participant CCRP as CCRP / TSP
  participant TEE as TEE / CCR
  participant Store as Ciphertext store

  TDP-&gt;&gt;Store: Upload encrypted dataset
  TDC-&gt;&gt;Store: Upload encrypted model
  TDP-&gt;&gt;CAN: Sign Ricardian contract
  TDC-&gt;&gt;CAN: Sign
  CCRP-&gt;&gt;CAN: Sign / accept offering
  CAN-&gt;&gt;CCRP: Job for SIGNED contract
  CCRP-&gt;&gt;TEE: Provision enclave / confidential VM
  TEE-&gt;&gt;TEE: Ephemeral keypair + attestation quote
  TEE-&gt;&gt;TDP: Attestation bundle
  TEE-&gt;&gt;TDC: Attestation bundle
  TDP-&gt;&gt;TDP: Verify attestation + contract binding
  TDC-&gt;&gt;TDC: Verify attestation + contract binding
  TDP-&gt;&gt;TEE: DEK over attested channel
  TDC-&gt;&gt;TEE: MEK over attested channel
  Store-&gt;&gt;TEE: Pull ciphertext
  TEE-&gt;&gt;TEE: Decrypt in memory → train
  TEE-&gt;&gt;TEE: Re-encrypt outputs · zeroize keys · destroy
  TEE-&gt;&gt;CAN: Provenance / job events
</code></pre>

<p>Same idea in one block (from the lifecycle guide):</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>CCRP provisions TEE
  → TEE generates ephemeral TLS keypair + attestation
  → Principals verify attestation independently
  → CCR pulls encrypted dataset + encrypted base model
  → TDP delivers DEK over attested TLS into TEE
  → TDC delivers MEK over attested TLS into TEE
  → Decrypt in memory → train → re-encrypt outputs
  → Zeroize keys → destroy CCR session
  → Emit provenance (created, attested, keys released, started, completed, destroyed)
</code></pre></div></div>

<hr />

<h2 id="3-what-hardware-attestation-means-here">3. What “hardware attestation” means here</h2>

<table>
  <thead>
    <tr>
      <th>Claim</th>
      <th>Why principals check it</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Enclave / confidential VM measurement</strong></td>
      <td>Code and config match what the contract allowed</td>
    </tr>
    <tr>
      <td><strong>Ephemeral session identity</strong></td>
      <td>Keys are bound to <strong>this</strong> job, not a long-lived shared host</td>
    </tr>
    <tr>
      <td><strong>Freshness</strong></td>
      <td>Replay of an old quote must not unlock new ciphertext</td>
    </tr>
    <tr>
      <td><strong>Cloud root of trust</strong></td>
      <td>Vendor attestation service / cert chain as designed for that cloud</td>
    </tr>
  </tbody>
</table>

<p><strong>SPIFFE/SPIRE</strong> (workload identity for agents and pods) <strong>complements</strong> TEE attestation; it does <strong>not</strong> replace it for DEK/MEK release. See <a href="/security/2026/07/28/three-identity-planes/">Three identity planes</a>.</p>

<hr />

<h2 id="4-what-contract-verification-means-here">4. What “contract verification” means here</h2>

<p>Before a principal releases DEK or MEK, the contract (and job binding) should establish at least:</p>

<table>
  <thead>
    <tr>
      <th>Check</th>
      <th>Example</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Parties</td>
      <td>TDP / TDC / CCRP identities match signers</td>
    </tr>
    <tr>
      <td>Purpose / use</td>
      <td>Training only; no bulk export clause</td>
    </tr>
    <tr>
      <td>Environment</td>
      <td>Region, TEE required, <code class="language-plaintext highlighter-rouge">attestation_required</code>, residency</td>
    </tr>
    <tr>
      <td>KMS / key ids</td>
      <td>Keys referenced in contract <code class="language-plaintext highlighter-rouge">kmsConfigs</code> / encryption metadata</td>
    </tr>
    <tr>
      <td>Escrow window</td>
      <td>Deadline; missed → destroy session</td>
    </tr>
    <tr>
      <td>Isolation</td>
      <td>Offering matches published CCRP capability</td>
    </tr>
  </tbody>
</table>

<p><strong>Open-GMASE</strong> can still <strong>deny <code class="language-plaintext highlighter-rouge">start_training</code></strong> even if keys are present—policy on the side effect is a separate fail-closed gate (<a href="/guides/2026/08/14/can-gmase-demo-slice/">demo slice</a>). TEE answers <em>where plaintext may exist</em>; OPA answers <em>whether the job may start</em>.</p>

<hr />

<h2 id="5-dataset-path-vs-model-path">5. Dataset path vs model path</h2>

<h3 id="tdp--encrypted-dataset-dek">TDP — encrypted dataset (DEK)</h3>

<ol>
  <li>TDP encrypts locally (target) → uploads <strong>ciphertext</strong> + metadata (<code class="language-plaintext highlighter-rouge">tee_only</code>, key id references).</li>
  <li>Contract requires TEE + attestation.</li>
  <li>After attestation + contract OK → DEK into TEE → decrypt dataset in memory.</li>
</ol>

<h3 id="tdc--encrypted-base-model-mek">TDC — encrypted base model (MEK)</h3>

<ol>
  <li>TDC encrypts model IP locally (target) → uploads <strong>ciphertext</strong>.</li>
  <li>Same clean-room session pulls model ciphertext.</li>
  <li>After attestation + contract OK → MEK into TEE → decrypt model in memory → train with dataset.</li>
</ol>

<p>Symmetric stories; <strong>both</strong> keys required. Details: <a href="https://github.com/gitmujoshi/Confidential-AI-Network/blob/main/docs/flows/TDP_ENCRYPTED_DATASET_TEE_FLOW.md">TDP flow</a> · <a href="https://github.com/gitmujoshi/Confidential-AI-Network/blob/main/docs/flows/TDC_ENCRYPTED_AI_MODEL_TEE_FLOW.md">TDC flow</a>.</p>

<hr />

<h2 id="6-live-today-vs-target">6. Live today vs target</h2>

<table>
  <thead>
    <tr>
      <th>Path</th>
      <th>What happens</th>
      <th>TEE?</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Local Docker / native / MLX</strong></td>
      <td>Signed contract → train on host/trainer image → register → infer</td>
      <td><strong>No</strong> — product UX demo</td>
    </tr>
    <tr>
      <td><strong>CAN/JCS MVP</strong></td>
      <td>Job + <strong>simulated</strong> attestation + DEK/MEK <strong>release signals</strong> (no key bytes to API)</td>
      <td>Coordination demo</td>
    </tr>
    <tr>
      <td><strong>Target CCR</strong></td>
      <td>Real quote → attested TLS → DEK+MEK in enclave → decrypt → train → zeroize</td>
      <td><strong>Yes</strong></td>
    </tr>
  </tbody>
</table>

<p>Local product-tour screenshots show the <strong>runnable</strong> loop. Azure confidential VMs + Key Vault / SKR are the <strong>cloud target</strong>—see <a href="/security/2026/08/17/azure-confidential-computing-deep-dive/">Azure confidential computing deep dive</a>. Host training and TEE paths are distinct.</p>

<hr />

<h2 id="7-provenance-events-evidence">7. Provenance events (evidence)</h2>

<p>A clean-room job should leave a trail such as:</p>

<ul>
  <li>Job created (bound to <code class="language-plaintext highlighter-rouge">contractId</code>)</li>
  <li>Attestation presented / verified</li>
  <li>DEK released · MEK released</li>
  <li>Training started / completed (or failed)</li>
  <li>Session destroyed / keys zeroized</li>
</ul>

<p>Ledger-backed claims (SCITT CCF) and CAN AuditLogs / CompliancePulse ingest sit beside this for GRC. The cryptographic story only works if <strong>destroy</strong> is real when escrow expires.</p>

<hr />

<h2 id="8-takeaways">8. Takeaways</h2>

<ol>
  <li><strong>Decrypt is a privilege</strong>, not a default—gated by <strong>attestation ∧ contract ∧ dual-key escrow</strong>.</li>
  <li><strong>Plaintext stays in the TEE</strong> for the job window; storage holds ciphertext.</li>
  <li><strong>Local demos ≠ confidential VMs</strong>—label them correctly for CISOs.</li>
  <li>Pair with <a href="/security/2026/08/16/can-kms-dek-mek-escrow/">KMS / DEK / MEK</a> for who owns which key, and with <a href="/security/2026/08/14/gmase-deep-dive/">Open-GMASE</a> for whether training may start at all.</li>
</ol>

<p><strong>One sentence:</strong> In CAN’s clean-room design, encrypted data and models are decrypted only after the enclave proves what it is and the Ricardian contract proves that enclave is allowed to train.</p>]]></content><author><name></name></author><category term="security" /><category term="can" /><category term="tee" /><category term="attestation" /><category term="encryption" /><category term="dek" /><category term="mek" /><category term="confidential-computing" /><category term="depa" /><summary type="html"><![CDATA[How Confidential AI Network intends encrypted datasets and models to be decrypted only inside a Trusted Execution Environment after hardware attestation and Ricardian contract verification.]]></summary></entry><entry><title type="html">Merkle trees for model audit — proving what happened when the model misbehaves</title><link href="https://dpi-apps.space/security/2026/08/16/merkle-trees-model-audit/" rel="alternate" type="text/html" title="Merkle trees for model audit — proving what happened when the model misbehaves" /><published>2026-08-16T00:00:00+00:00</published><updated>2026-08-16T00:00:00+00:00</updated><id>https://dpi-apps.space/security/2026/08/16/merkle-trees-model-audit</id><content type="html" xml:base="https://dpi-apps.space/security/2026/08/16/merkle-trees-model-audit/"><![CDATA[<p><em>When a model produces a harmful, biased, or contract-violating outcome, the question is not only “what did it output?”—it is “what inputs, policy, and artifacts led here, and can we prove nobody rewrote the trail?”</em></p>

<p><strong>Related:</strong> <a href="/product/2026/08/14/can-contract-to-prediction/">Contract → governed prediction</a> · <a href="/product/2026/08/16/ricardian-contracts-in-can/">Ricardian contracts in CAN</a> · <a href="/product-tour/#auditor">Product tour — Auditor</a> · <a href="/security/2026/08/14/gmase-deep-dive/">Open-GMASE</a> · <a href="/security/2026/08/16/can-tee-attest-decrypt-train/">TEE attest → decrypt</a> · In-repo: <a href="https://github.com/gitmujoshi/Confidential-AI-Network/blob/main/docs/features/AUDITOR_ROLE.md">AUDITOR_ROLE.md</a> · <a href="https://github.com/gitmujoshi/Confidential-AI-Network/blob/main/docs/security/MERKLE_TREE_PROVENANCE_IMPLEMENTATION.md">MERKLE_TREE_PROVENANCE_IMPLEMENTATION.md</a></p>

<blockquote>
  <p><strong>Status:</strong> Merkle builders, proofs, and Auditor UI (<code class="language-plaintext highlighter-rouge">/auditor/*</code>, <code class="language-plaintext highlighter-rouge">/api/auditor/*</code>). <strong>Verify</strong> checks leaf inclusion under a published root. Provenance report UI and SCITT path are available. Cross-cloud Merkle replication and extended leaf types: partial. See <a href="https://github.com/gitmujoshi/Confidential-AI-Network/blob/main/docs/features/AUDITOR_ROLE.md">AUDITOR_ROLE.md</a>.</p>
</blockquote>

<hr />

<h2 id="1-why-the-model-misbehaved-needs-cryptography">1. Why “the model misbehaved” needs cryptography</h2>

<p>A bad prediction, a leaked feature, or a training run that used the wrong dataset creates a GRC incident. Typical evidence fails under scrutiny:</p>

<table>
  <thead>
    <tr>
      <th>Weak evidence</th>
      <th>What an adversary (or honest mistake) can do</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Log file on disk</td>
      <td>Edit after the fact</td>
    </tr>
    <tr>
      <td>Screenshot of the UI</td>
      <td>No binding to bytes that trained the model</td>
    </tr>
    <tr>
      <td>“Trust our SIEM export”</td>
      <td>Incomplete or reordered without proof</td>
    </tr>
    <tr>
      <td>Model card PDF</td>
      <td>Not tied to the artifact hash</td>
    </tr>
  </tbody>
</table>

<p>You need a structure where:</p>

<ol>
  <li>Every material event is <strong>hashed</strong>.</li>
  <li>Hashes are <strong>aggregated</strong> so one <strong>root</strong> commits to the whole set.</li>
  <li>Anyone can check a single event with a short <strong>inclusion proof</strong> against a published root (and optionally a ledger receipt).</li>
</ol>

<p>That structure is a <strong>Merkle tree</strong>.</p>

<hr />

<h2 id="2-merkle-trees-in-one-diagram">2. Merkle trees in one diagram</h2>

<pre><code class="language-mermaid">flowchart TB
  R["Root hash&lt;br/&gt;(commit to entire job)"]
  A["H(A∥B)"]
  B["H(C∥D)"]
  L1["leaf: dataset digest"]
  L2["leaf: contract / terms digest"]
  L3["leaf: training config"]
  L4["leaf: model artifact / decision"]

  R --&gt; A
  R --&gt; B
  A --&gt; L1
  A --&gt; L2
  B --&gt; L3
  B --&gt; L4
</code></pre>

<ul>
  <li><strong>Leaf</strong> = cryptographic hash of a provenance record (dataset chunk, config JSON, checkpoint, policy decision, …).</li>
  <li><strong>Parent</strong> = hash of its children (order fixed; algorithm usually SHA-256).</li>
  <li><strong>Root</strong> = single digest that commits to all leaves.</li>
  <li><strong>Inclusion proof</strong> = sibling hashes along the path from leaf → root. Anyone with the root can recompute and verify the leaf was in the tree <strong>when that root was published</strong>.</li>
</ul>

<p>Change one byte of training data or swap a config field → leaf changes → root changes. That is the audit property.</p>

<hr />

<h2 id="3-what-can-puts-under-the-tree">3. What CAN puts under the tree</h2>

<h3 id="31-target-design-full-lifecycle">3.1 Target design (full lifecycle)</h3>

<p>Aligned with the provenance design and training job lifecycle:</p>

<table>
  <thead>
    <tr>
      <th>Phase</th>
      <th>Example leaves</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Before train</strong></td>
      <td>Contract id / terms digest · dataset ciphertext or content hash · model base digest · KMS / Key Vault refs · TEE attestation digest (when present)</td>
    </tr>
    <tr>
      <td><strong>During train</strong></td>
      <td>Hyperparams · DP config (ε/δ if used) · epoch checkpoints · Open-GMASE <code class="language-plaintext highlighter-rouge">start_training</code> decision id</td>
    </tr>
    <tr>
      <td><strong>After train</strong></td>
      <td>Final artifact hash · metrics · provenance report bundle</td>
    </tr>
    <tr>
      <td><strong>Infer</strong></td>
      <td>Deploy / predict governance decisions · input digest (careful with PII) · output label / class</td>
    </tr>
  </tbody>
</table>

<p>The <strong>Merkle Tree Service</strong> aggregates nodes; PostgreSQL stores trees/nodes/proofs; <strong>SCITT CCF</strong> can hold a <strong>receipt</strong> that anchors the root (or claim) on a confidential ledger—so the root itself is harder to rewrite than an app database row alone.</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Events → hash leaves → Merkle root → (optional) SCITT receipt
                ↑
     inclusion proof for one disputed event
</code></pre></div></div>

<h3 id="32-what-the-auditor-ui-builds-today">3.2 What the Auditor UI builds today</h3>

<p>The Auditor workspace (<code class="language-plaintext highlighter-rouge">/auditor/dashboard</code> → <strong>Audit tree</strong>) builds a <strong>contract-scoped</strong> tree from durable DB evidence. Each <strong>Verify</strong> click checks inclusion of one of these leaf kinds:</p>

<table>
  <thead>
    <tr>
      <th>Leaf kind</th>
      <th>What the leaf commits to</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>contract</strong></td>
      <td>Contract id, status, legal-document hash, parties, environment specs, training params, linked datasets</td>
    </tr>
    <tr>
      <td><strong>training_job</strong></td>
      <td>Job id/status, metrics, artifact hashes (when recorded), timestamps</td>
    </tr>
    <tr>
      <td><strong>scitt_claim</strong></td>
      <td>SCITT claim type/status/data markers for that contract</td>
    </tr>
    <tr>
      <td><strong>ai_model</strong></td>
      <td>Registered model metadata (name, framework, architecture, ids)</td>
    </tr>
  </tbody>
</table>

<p>Not every row in the “target design” table above is a separate leaf yet (for example raw DP config or every G-MASE decision may live in AuditLogs / CompliancePulse until folded into this tree). The product-tour screens show this path: <a href="/product-tour/#auditor">Auditor section</a>.</p>

<hr />

<h2 id="4-what-an-auditor-actually-verifies">4. What an Auditor actually verifies</h2>

<p>Two different jobs—do not conflate them.</p>

<h3 id="41-what-verify-checks-cryptography">4.1 What <strong>Verify</strong> checks (cryptography)</h3>

<p>That a <strong>leaf is included</strong> in the tree under the published <strong>root hash</strong>.</p>

<p>In other words: <em>“This evidence record belongs to this committed provenance set and has not been silently dropped or swapped relative to this root.”</em></p>

<table>
  <thead>
    <tr>
      <th>Verified by inclusion proof</th>
      <th>Not verified by inclusion proof</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Integrity of lineage for that leaf under root R</td>
      <td>That the model’s prediction was correct</td>
    </tr>
    <tr>
      <td>Consistency of the audit trail for that contract</td>
      <td>Ethics / fairness of the model</td>
    </tr>
    <tr>
      <td>Binding of listed contract / job / claim / model digests</td>
      <td>That every extended leaf type is always present</td>
    </tr>
  </tbody>
</table>

<p>If the inclusion proof <strong>fails</strong>, treat it as an <strong>integrity / ops</strong> problem first—not only a model-quality problem.</p>

<h3 id="42-what-the-auditor-reviews-human">4.2 What the Auditor <strong>reviews</strong> (human)</h3>

<p>After Verify succeeds (or while investigating), they open the <strong>Ricardian contract</strong> the training was based on and ask process questions:</p>

<ul>
  <li>Was this the agreed use, data, and environment?</li>
  <li>Which training job produced the disputed artifact?</li>
  <li>Which SCITT markers were recorded for sign / train / deploy?</li>
</ul>

<p>Merkle trees do not make models ethical. They make <strong>denial and rewriting of history expensive</strong>. Auditors prove <strong>lineage integrity</strong>, then judge <strong>process fit to the contract</strong>—not model quality by itself.</p>

<hr />

<h2 id="5-incident-playbook-model-misbehaves">5. Incident playbook: model misbehaves</h2>

<p>Suppose an inference result looks wrong, unsafe, or outside the Ricardian use terms.</p>

<h3 id="51-freeze-the-claim">5.1 Freeze the claim</h3>

<ol>
  <li>Capture <strong>model id</strong>, <strong>job id</strong>, <strong>contract id</strong>, timestamp, and the disputed output.</li>
  <li>Open the Auditor <strong>audit tree</strong> for that contract (or export the proof package)—load the published <strong>Merkle root</strong> (and SCITT receipt if enabled).</li>
  <li>Do <strong>not</strong> only trust the live training UI screenshot.</li>
</ol>

<h3 id="52-verify-the-lineage-you-care-about">5.2 Verify the lineage you care about</h3>

<table>
  <thead>
    <tr>
      <th>Question</th>
      <th>Merkle / Auditor answer (today vs target)</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Is this contract’s trail intact under root R?</td>
      <td><strong>Today:</strong> Verify <strong>contract</strong> / <strong>training_job</strong> / <strong>scitt_claim</strong> / <strong>ai_model</strong> leaves</td>
    </tr>
    <tr>
      <td>Was this the dataset we signed for?</td>
      <td><strong>Target:</strong> dataset leaf ∈ tree; <strong>today:</strong> review <code class="language-plaintext highlighter-rouge">contractDatasets</code> on the contract leaf + catalog</td>
    </tr>
    <tr>
      <td>Were DP / residency flags the ones in the contract?</td>
      <td><strong>Target:</strong> config leaf; <strong>today:</strong> compare contract <code class="language-plaintext highlighter-rouge">trainingParams</code> / env specs + job metrics</td>
    </tr>
    <tr>
      <td>Did Open-GMASE ALLOW this predict?</td>
      <td>Prefer AuditLogs / CompliancePulse decision id; fold into Merkle when that leaf type is published</td>
    </tr>
    <tr>
      <td>Is the artifact we served the one we trained?</td>
      <td>Job <strong>artifactHashes</strong> / registered model leaf vs deployed bytes</td>
    </tr>
  </tbody>
</table>

<h3 id="53-separate-bad-model-from-bad-process">5.3 Separate “bad model” from “bad process”</h3>

<table>
  <thead>
    <tr>
      <th>Finding</th>
      <th>Interpretation</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Proofs verify; output still harmful</td>
      <td>Model / data / policy design problem—lineage is intact</td>
    </tr>
    <tr>
      <td>Proofs fail or root ≠ receipt</td>
      <td>Integrity / ops incident—do not treat UI history as truth</td>
    </tr>
    <tr>
      <td>ALLOW decision missing or DENY bypassed</td>
      <td>Control-plane failure (gate, keys, or deployment)</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="6-how-this-fits-open-gmase-and-compliancepulse">6. How this fits Open-GMASE and CompliancePulse</h2>

<table>
  <thead>
    <tr>
      <th>Layer</th>
      <th>Role when something goes wrong</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Open-GMASE OPA</strong></td>
      <td>May have <strong>denied</strong> a bad side effect before it ran—or ALLOW’d it with a recorded reason</td>
    </tr>
    <tr>
      <td><strong>CAN AuditLogs</strong></td>
      <td><code class="language-plaintext highlighter-rouge">GMASE_TOOL_DECISION</code> and job events</td>
    </tr>
    <tr>
      <td><strong>Merkle provenance</strong></td>
      <td>Binds durable contract evidence into a <strong>root</strong> with inclusion proofs (Auditor UI)</td>
    </tr>
    <tr>
      <td><strong>CompliancePulse ingest</strong></td>
      <td>External copy of governance decisions for control-plane review</td>
    </tr>
    <tr>
      <td><strong>SCITT</strong></td>
      <td>Ledger receipt / claim markers for the contract trail</td>
    </tr>
  </tbody>
</table>

<p>Together: <strong>prevent</strong> where possible (OPA), <strong>record</strong> always (audit), <strong>prove</strong> under challenge (Merkle + receipt).</p>

<hr />

<h2 id="7-what-auditors-should-ask-for">7. What auditors should ask for</h2>

<ol>
  <li>Algorithm (e.g. SHA-256) and leaf canonicalization rules (JSON field order, hashing of files).</li>
  <li>Published <strong>root</strong> for the contract (Auditor audit-tree view).</li>
  <li><strong>Inclusion proof</strong> for the disputed leaf (<strong>Verify</strong> in the UI, or API <code class="language-plaintext highlighter-rouge">POST /api/auditor/verify-proof</code>).</li>
  <li>Optional <strong>SCITT receipt</strong> verifying the root/claim.</li>
  <li>Mapping from leaf → human-readable event (contract id, job id, claim id, model id).</li>
  <li>The <strong>Ricardian contract</strong> record itself—terms the training was based on.</li>
</ol>

<p>If the vendor cannot produce (3) against (2), you have a narrative, not evidence.</p>

<hr />

<h2 id="8-limits">8. Limits</h2>

<table>
  <thead>
    <tr>
      <th>Merkle / provenance helps</th>
      <th>It does not replace</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Detecting tampering of the recorded trail</td>
      <td>Stopping a model from being wrong on valid data</td>
    </tr>
    <tr>
      <td>Efficient proofs for one event among thousands</td>
      <td>Full replay of GPU nondeterminism without careful leaf design</td>
    </tr>
    <tr>
      <td>Binding artifacts / jobs to a contract</td>
      <td>DEK/MEK custody (see <a href="/security/2026/08/16/can-kms-dek-mek-escrow/">KMS</a>) or TEE isolation (see <a href="/security/2026/08/16/can-tee-attest-decrypt-train/">TEE</a>)</td>
    </tr>
    <tr>
      <td>Supporting NIST/CIS-style audit evidence</td>
      <td>Certified compliance by itself</td>
    </tr>
    <tr>
      <td>Auditor <strong>Verify</strong> = inclusion under root</td>
      <td>A judgment that the output was “correct” or “ethical”</td>
    </tr>
  </tbody>
</table>

<p>Hashing <strong>raw prompts that contain secrets</strong> into leaves can create a new leakage path—hash digests or redacted envelopes, not plaintext PII, in the published tree.</p>

<hr />

<h2 id="9-takeaways">9. Takeaways</h2>

<ol>
  <li>A <strong>Merkle root</strong> is a compact commitment to the provenance set for a contract / job.</li>
  <li>Auditor <strong>Verify</strong> answers: “Is this leaf in the committed history under root R?”—<strong>integrity of lineage</strong>, not model quality.</li>
  <li>After proofs succeed, review the <strong>governing Ricardian contract</strong> to separate bad process from bad model.</li>
  <li>CAN pairs Merkle with <strong>SCITT</strong>, <strong>AuditLogs</strong>, and <strong>Open-GMASE</strong> so incidents separate <strong>integrity</strong> from <strong>model quality</strong>.</li>
  <li>Ask for proofs under challenge—not screenshots.</li>
</ol>

<p><strong>One sentence:</strong> Merkle trees let CAN turn “trust our logs” into “verify this leaf against a published root”—and the Auditor role is where that check happens when a model’s behavior is under dispute.</p>]]></content><author><name></name></author><category term="security" /><category term="can" /><category term="merkle" /><category term="provenance" /><category term="audit" /><category term="scitt" /><category term="governance" /><category term="g-mase" /><summary type="html"><![CDATA[How Merkle trees turn training and inference events into tamper-evident evidence—so when a model misbehaves, auditors can verify lineage and decisions instead of trusting screenshots.]]></summary></entry><entry><title type="html">Ricardian contracts in CAN — legal prose that the runtime can enforce</title><link href="https://dpi-apps.space/product/2026/08/16/ricardian-contracts-in-can/" rel="alternate" type="text/html" title="Ricardian contracts in CAN — legal prose that the runtime can enforce" /><published>2026-08-16T00:00:00+00:00</published><updated>2026-08-16T00:00:00+00:00</updated><id>https://dpi-apps.space/product/2026/08/16/ricardian-contracts-in-can</id><content type="html" xml:base="https://dpi-apps.space/product/2026/08/16/ricardian-contracts-in-can/"><![CDATA[<p>A PDF agreement does not stop a training job or bind runtime state to the exact terms parties signed.</p>

<p><strong>CAN</strong> uses a <strong>Ricardian contract</strong>: legal prose plus machine-enforceable structure (datasets, params, environment, keys, signatures) so train/infer proceed only under that state.</p>

<p><strong>Related:</strong> <a href="/product/2026/08/14/can-contract-to-prediction/">Contract → governed prediction</a> · <a href="/product/2026/08/17/can-contract-management-signing/">Contract management — signing keys &amp; verify</a> · <a href="/product-tour/">Product tour</a> · <a href="/security/2026/08/16/merkle-trees-model-audit/">Merkle / Auditor</a> · <a href="/security/2026/08/16/can-kms-dek-mek-escrow/">KMS DEK/MEK</a> · <a href="/security/2026/08/16/can-tee-attest-decrypt-train/">TEE attest → decrypt</a> · In-repo: <a href="https://github.com/gitmujoshi/Confidential-AI-Network/blob/main/docs/contracts/RICARDIAN_CONTRACT_GUIDE.md">RICARDIAN_CONTRACT_GUIDE.md</a></p>

<blockquote>
  <p><strong>Status:</strong> Creating, previewing, multi-party signing, and <strong>SIGNED → train</strong> gates are live on the local stack. On-chain deploy and some signature crypto are <strong>demo / Phase 1</strong> (see §8). Cloud clean-room key release remains <a href="/security/2026/08/16/can-tee-attest-decrypt-train/">Phase 2 in the TEE narrative</a>.</p>
</blockquote>

<hr />

<h2 id="1-what-ricardian-means-here">1. What “Ricardian” means here</h2>

<p>Ian Grigg’s Ricardian idea (simplified): one document that humans can read, machines can hash unambiguously, and signatures bind to <strong>that</strong> byte-exact artifact.</p>

<p>In CAN: legal prose bound to machine-enforceable structure (datasets, training params, privacy, clean-room host).</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Legal prose  ──hash──►  legalDocumentHash  ──bound to──►  Contract row
     ▲                                                      │
     │                                                      ▼
Human review / signatures                         Runtime gates (train / infer)
</code></pre></div></div>

<p>Machine-only → opaque JSON. Legal-only → NDA. Ricardian is both.</p>

<hr />

<h2 id="2-the-dual-layer-in-can">2. The dual layer in CAN</h2>

<table>
  <thead>
    <tr>
      <th>Layer</th>
      <th>Fields</th>
      <th>Purpose</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Legal</strong></td>
      <td><code class="language-plaintext highlighter-rouge">legalDocument</code> (JSONB)</td>
      <td>Title, parties, recitals, terms, accumulated <code class="language-plaintext highlighter-rouge">signatures[]</code></td>
    </tr>
    <tr>
      <td><strong>Binding digests</strong></td>
      <td><code class="language-plaintext highlighter-rouge">legalDocumentHash</code>, <code class="language-plaintext highlighter-rouge">ricardianSignature</code></td>
      <td>Commit to the document bytes; platform-level binding marker</td>
    </tr>
    <tr>
      <td><strong>Machine / execution</strong></td>
      <td><code class="language-plaintext highlighter-rouge">contractDatasets</code>, <code class="language-plaintext highlighter-rouge">aiModelIds</code>, <code class="language-plaintext highlighter-rouge">trainingParams</code>, <code class="language-plaintext highlighter-rouge">environmentSpecs</code>, <code class="language-plaintext highlighter-rouge">kmsConfigs</code>, <code class="language-plaintext highlighter-rouge">tspCloudProvider</code>, party ids</td>
      <td>What training and policy gates actually read</td>
    </tr>
  </tbody>
</table>

<p>Creation (simplified):</p>

<ol>
  <li>TDC runs the wizard → <code class="language-plaintext highlighter-rouge">POST /api/contracts/ricardian</code>.</li>
  <li>Service <strong>generates</strong> <code class="language-plaintext highlighter-rouge">legalDocument</code> from a template (<code class="language-plaintext highlighter-rouge">AI_TRAINING</code> or <code class="language-plaintext highlighter-rouge">BASIC</code>).</li>
  <li>Canonical JSON → <strong>SHA-256</strong> → <code class="language-plaintext highlighter-rouge">legalDocumentHash</code> (<code class="language-plaintext highlighter-rouge">0x…</code>).</li>
  <li>Platform records <code class="language-plaintext highlighter-rouge">ricardianSignature</code> over that hash (see §8).</li>
  <li>Optional smart-contract address (real chain if configured; otherwise <strong>mock</strong>).</li>
  <li>Persist <code class="language-plaintext highlighter-rouge">Contract</code> at <strong><code class="language-plaintext highlighter-rouge">PENDING_TDP_APPROVAL</code></strong> and notify linked TDPs.</li>
</ol>

<p>Screens: <a href="/product-tour/#local">product tour — contract create &amp; sign</a>.</p>

<hr />

<h2 id="3-who-the-parties-are">3. Who the parties are</h2>

<table>
  <thead>
    <tr>
      <th>Role</th>
      <th>In the contract</th>
      <th>What they do</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>TDC</strong></td>
      <td>Training Data Consumer</td>
      <td>Creates the Ricardian contract; selects datasets &amp; catalog model; starts training after <strong>SIGNED</strong></td>
    </tr>
    <tr>
      <td><strong>TDP</strong></td>
      <td>Training Data Provider</td>
      <td>Owns data; reviews terms; <strong>signs</strong> to approve use</td>
    </tr>
    <tr>
      <td><strong>TSP</strong></td>
      <td>Tech Service Provider (formerly CCRP)</td>
      <td>Hosts the environment (Local Docker today; cloud confidential compute in design); <strong>signs</strong> as assigned host</td>
    </tr>
    <tr>
      <td><strong>Auditor</strong></td>
      <td>Not a party</td>
      <td>Read-only: Merkle tree + contract review when a model is disputed (<a href="https://github.com/gitmujoshi/Confidential-AI-Network/blob/main/docs/features/AUDITOR_ROLE.md">Auditor role</a>)</td>
    </tr>
  </tbody>
</table>

<p>Design roots sit with iSPIRT <a href="https://depa.world">DEPA</a>—consent-style, multi-party sharing with identifiers (<strong>DEPA IDs</strong>) on parties, datasets, contracts, and jobs.</p>

<hr />

<h2 id="4-lifecycle-from-draft-intent-to-enforced-runtime">4. Lifecycle: from draft intent to enforced runtime</h2>

<pre><code class="language-mermaid">sequenceDiagram
  participant TDC
  participant CAN
  participant TDP
  participant TSP
  participant Train

  TDC-&gt;&gt;CAN: Create Ricardian (legal + machine fields)
  CAN-&gt;&gt;TDP: Notify PENDING_TDP_APPROVAL
  TDP-&gt;&gt;CAN: Sign as TDP
  CAN-&gt;&gt;TSP: Status PENDING_TSP_APPROVAL
  TSP-&gt;&gt;CAN: Sign as TSP
  Note over CAN: status = SIGNED
  TDC-&gt;&gt;Train: Start training (requires SIGNED)
  Train-&gt;&gt;CAN: Jobs, provenance, optional G-MASE gates
</code></pre>

<h3 id="41-create-tdc">4.1 Create (TDC)</h3>

<p>Five-step UI (<code class="language-plaintext highlighter-rouge">CreateRicardianContract</code>):</p>

<ol>
  <li>Template</li>
  <li>Details &amp; dataset selection (1–3 datasets)</li>
  <li>Environment &amp; TSP (compute, security, KMS refs)</li>
  <li>Review generated legal document</li>
  <li>Submit</li>
</ol>

<h3 id="42-sign-tdp--tsp">4.2 Sign (TDP → TSP)</h3>

<ul>
  <li><strong>TDP</strong> signs via <code class="language-plaintext highlighter-rouge">POST /api/contracts/:id/sign</code> with <code class="language-plaintext highlighter-rouge">partyType=TDP</code> → moves toward TSP approval.</li>
  <li><strong>TSP</strong> (assigned <code class="language-plaintext highlighter-rouge">tspId</code>) signs → status becomes <strong><code class="language-plaintext highlighter-rouge">SIGNED</code></strong>.</li>
  <li>Each approval appends to <code class="language-plaintext highlighter-rouge">legalDocument.signatures[]</code> and writes a best-effort <strong>SCITT</strong> claim (<code class="language-plaintext highlighter-rouge">contract_approval</code>).</li>
</ul>

<p><strong>Runtime note:</strong> The training gate today requires <strong><code class="language-plaintext highlighter-rouge">status === 'SIGNED'</code></strong> (reached when TSP completes). A separate <code class="language-plaintext highlighter-rouge">tdcSigned</code> column exists on the model; do not assume every UML “all three parties must sign” path is what the local trainer enforces. Prefer the live path above.</p>

<h3 id="43-train-and-infer">4.3 Train and infer</h3>

<ul>
  <li><strong>Train:</strong> <code class="language-plaintext highlighter-rouge">tdcTrainingExecutionService</code> refuses jobs unless the contract is <strong>SIGNED</strong> (and env / cloud / privacy constraints are present).</li>
  <li><strong>Infer:</strong> Deployed models stay tied to the training <code class="language-plaintext highlighter-rouge">contractId</code>; Open-GMASE can gate deploy/predict via package <code class="language-plaintext highlighter-rouge">open_gmase/can_contracts</code> (<a href="/guides/2026/08/14/can-gmase-demo-slice/">demo slice</a>).</li>
</ul>

<p>No signature → no training. That is the product claim that replaces “we emailed a Word doc.”</p>

<hr />

<h2 id="5-what-the-machine-side-binds">5. What the machine side binds</h2>

<p>These fields are not decoration—they are what jobs and gates consume:</p>

<table>
  <thead>
    <tr>
      <th>Binding</th>
      <th>Contract fields</th>
      <th>Examples</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Data</strong></td>
      <td><code class="language-plaintext highlighter-rouge">contractDatasets</code>, primary dataset ids</td>
      <td>Which TDP catalogs are in scope (max 1–3)</td>
    </tr>
    <tr>
      <td><strong>Model</strong></td>
      <td><code class="language-plaintext highlighter-rouge">aiModelIds</code></td>
      <td>Catalog base model (e.g. DistilBERT for NLP tours)</td>
    </tr>
    <tr>
      <td><strong>Training rules</strong></td>
      <td><code class="language-plaintext highlighter-rouge">trainingParams</code></td>
      <td>Epochs, DP (<code class="language-plaintext highlighter-rouge">epsilon</code>/<code class="language-plaintext highlighter-rouge">delta</code>), accuracy floors, run limits</td>
    </tr>
    <tr>
      <td><strong>Environment</strong></td>
      <td><code class="language-plaintext highlighter-rouge">environmentSpecs</code></td>
      <td>Instance shape, <code class="language-plaintext highlighter-rouge">security.attestationRequired</code>, encryption, network isolation</td>
    </tr>
    <tr>
      <td><strong>Keys</strong></td>
      <td><code class="language-plaintext highlighter-rouge">kmsConfigs</code> (often from wizard <code class="language-plaintext highlighter-rouge">environmentSpecs.kms</code>)</td>
      <td>Provider, key id / Vault OCID, region — see <a href="/security/2026/08/16/can-kms-dek-mek-escrow/">KMS post</a></td>
    </tr>
    <tr>
      <td><strong>Where it runs</strong></td>
      <td><code class="language-plaintext highlighter-rouge">tspId</code>, <code class="language-plaintext highlighter-rouge">tspCloudProvider</code></td>
      <td>Local, OCI, Azure, …</td>
    </tr>
  </tbody>
</table>

<p>Wizard defaults lean secure: attestation required, encryption at rest/in transit, network isolation—even when the local trainer is Docker rather than a hardware TEE.</p>

<hr />

<h2 id="6-how-the-contract-shows-up-in-evidence">6. How the contract shows up in evidence</h2>

<p>When a model misbehaves, the contract is the spine of the audit story:</p>

<table>
  <thead>
    <tr>
      <th>Evidence path</th>
      <th>Contract role</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Provenance report</strong></td>
      <td>Exposes <code class="language-plaintext highlighter-rouge">legalDocumentHash</code>, <code class="language-plaintext highlighter-rouge">ricardianSignature</code>, parties, jobs</td>
    </tr>
    <tr>
      <td><strong>Auditor Merkle tree</strong></td>
      <td><strong>contract</strong> leaf commits to hash, signature, env specs, training params, datasets (<a href="/security/2026/08/16/merkle-trees-model-audit/">Merkle post</a>)</td>
    </tr>
    <tr>
      <td><strong>SCITT claims</strong></td>
      <td><code class="language-plaintext highlighter-rouge">contract_creation</code> / <code class="language-plaintext highlighter-rouge">contract_approval</code> markers</td>
    </tr>
    <tr>
      <td><strong>Open-GMASE</strong></td>
      <td>OPA input includes <code class="language-plaintext highlighter-rouge">contract_id</code>, <code class="language-plaintext highlighter-rouge">contract_status</code>, classification / region hints from the contract</td>
    </tr>
  </tbody>
</table>

<p>Auditors do <strong>not</strong> use the Ricardian text to prove the model was “correct.” They use it to prove <strong>which agreement governed the run</strong>, then Verify Merkle inclusion for that trail.</p>

<hr />

<h2 id="7-why-this-is-better-than-pdf--nda">7. Why this is better than “PDF + NDA”</h2>

<table>
  <thead>
    <tr>
      <th>Approach</th>
      <th>Stops unauthorized train?</th>
      <th>Tamper-evident?</th>
      <th>Ties artifact to terms?</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>PDF in email</td>
      <td>No</td>
      <td>No</td>
      <td>Manual at best</td>
    </tr>
    <tr>
      <td>Checkbox ToS in UI</td>
      <td>Soft</td>
      <td>Usually not</td>
      <td>Weak</td>
    </tr>
    <tr>
      <td><strong>CAN Ricardian</strong></td>
      <td>Yes — status gate</td>
      <td>Hash + signatures + SCITT/Merkle path</td>
      <td>Job and model carry <code class="language-plaintext highlighter-rouge">contractId</code></td>
    </tr>
  </tbody>
</table>

<p>That is the DEPA-shaped idea applied to AI training: <strong>use is licensed by agreement</strong>, not by whoever has a copy of the CSV.</p>

<hr />

<h2 id="8-phase-1-limits">8. Phase 1 limits</h2>

<table>
  <thead>
    <tr>
      <th>Topic</th>
      <th>Reality today</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong><code class="language-plaintext highlighter-rouge">ricardianSignature</code></strong></td>
      <td>Platform binding digest for demos—not full multi-party ECDSA / cloud KMS signing of the legal hash (production target: IdP + KMS). Deep dive: <a href="/product/2026/08/17/can-contract-management-signing/">Contract management — signing &amp; verify</a></td>
    </tr>
    <tr>
      <td><strong>On-chain deploy</strong></td>
      <td>Real only if blockchain is enabled and available; otherwise <strong>mock</strong> network/address</td>
    </tr>
    <tr>
      <td><strong>TDC signature</strong></td>
      <td>Model supports <code class="language-plaintext highlighter-rouge">tdcSigned</code>; <strong>SIGNED</strong> for training is driven by the <strong>TSP</strong> completing the current flow</td>
    </tr>
    <tr>
      <td><strong>Templates</strong></td>
      <td>Built-in <code class="language-plaintext highlighter-rouge">AI_TRAINING</code> / <code class="language-plaintext highlighter-rouge">BASIC</code>; rich clause libraries / customer templates: roadmap</td>
    </tr>
    <tr>
      <td><strong>TEE / key release</strong></td>
      <td>Contract can <em>require</em> attestation; local Docker is not hardware TEE—see <a href="/security/2026/08/16/can-tee-attest-decrypt-train/">TEE post</a></td>
    </tr>
    <tr>
      <td><strong>Naming</strong></td>
      <td>Runtime prefers <strong>TSP</strong>; older templates/DB columns may still say <strong>CCRP</strong></td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="9-takeaways">9. Takeaways</h2>

<ol>
  <li>A <strong>Ricardian contract</strong> in CAN is legal prose <strong>plus</strong> hashed binding <strong>plus</strong> machine fields the runtime enforces.</li>
  <li>Lifecycle: <strong>create → TDP sign → TSP sign → SIGNED → train/infer</strong>.</li>
  <li>Machine bindings (<code class="language-plaintext highlighter-rouge">datasets</code>, <code class="language-plaintext highlighter-rouge">trainingParams</code>, <code class="language-plaintext highlighter-rouge">environmentSpecs</code>, <code class="language-plaintext highlighter-rouge">kmsConfigs</code>, cloud) are first-class—not footnotes.</li>
  <li>Provenance, Merkle, SCITT, and Open-GMASE all hang off the <strong>same contract id</strong>.</li>
  <li>Ask vendors for the hash, the signature trail, and the <strong>SIGNED</strong> gate—not a PDF alone.</li>
</ol>

<p><strong>One sentence:</strong> CAN’s Ricardian contract is how multi-party AI collaboration becomes enforceable state instead of an email attachment—readable by people, hashed for integrity, and checked before training runs.</p>]]></content><author><name></name></author><category term="product" /><category term="can" /><category term="ricardian" /><category term="contracts" /><category term="depa" /><category term="signing" /><category term="provenance" /><category term="training" /><summary type="html"><![CDATA[What a Ricardian contract is, how CAN binds human-readable terms to machine state, and how that agreement gates training, inference, and audit.]]></summary></entry><entry><title type="html">Confidential AI Network — contract to prediction (moved)</title><link href="https://dpi-apps.space/product/2026/08/14/reintroducing-confidential-ai-network/" rel="alternate" type="text/html" title="Confidential AI Network — contract to prediction (moved)" /><published>2026-08-14T00:00:00+00:00</published><updated>2026-08-14T00:00:00+00:00</updated><id>https://dpi-apps.space/product/2026/08/14/can-contract-to-prediction-redirect</id><content type="html" xml:base="https://dpi-apps.space/product/2026/08/14/reintroducing-confidential-ai-network/"><![CDATA[<p>This article now lives at
<a href="/product/2026/08/14/can-contract-to-prediction/">Confidential AI Network: from signed contract to governed prediction</a>.</p>]]></content><author><name></name></author><category term="product" /><category term="redirect" /><summary type="html"><![CDATA[This note moved to a clearer URL.]]></summary></entry></feed>