
Article of our Co-Founder Ariane in IM+io
Article for IM+io of the August-Wilhelm Scheer Institut of our Co-Founder Ariane Scheer-Danielsson towards the need for a Trust Layer in Physical AI.

On mobile, the right home for a signing key is the platform keystore, not JavaScript. But our manifest logic is TypeScript, and we refused to fork it per platform. The resolution is a narrow bridge: our c2pa-ts library defines Signer, TimestampProvider, and crypto interfaces, and thin native adapters inject platform callbacks for signing, hashing, and randomness. One audited manifest codebase runs on iOS, Android, browsers, and Lambda. The key's home becomes a deployment decision, not an architecture fork.
Everything in the library that touches cryptography depends on interfaces, not implementations. Browser deployments wire in WebSigner and WebCrypto. Server deployments use LocalSigner and Node crypto. Mobile uses NativeSigner over platform callbacks. The manifest code above these interfaces is byte-identical across all four. When we fix a claim-encoding bug, it is fixed everywhere, once.
Signing evidence in the browser means the private key lives in IndexedDB. That sentence makes security engineers nervous, and it should. These are software-held browser keys, not hardware-backed key material, and the design treats them accordingly.
In-situ cryptography means signing happens at capture, on the device, at the edge. If the private key lived on a server, every capture would need a round trip carrying either the key or the evidence, and both options break the model. WebCrypto generates ECDSA P-256 pairs and can persist CryptoKey objects in IndexedDB. The capability is there. The discipline has to come from you.
Never trust a stored key. IndexedDB is user-visible, user-editable storage. So getKeyPair treats every retrieved key as suspect until proven otherwise. The validation ladder, in order: is the entry younger than 30 days; does it carry a client identity; is it actually a key object of the right type with the right usages; and finally, the decisive check, can the stored public key verify a fresh signature from the stored private key. A key pair that fails any rung is deleted and regenerated. That last rung is the one people skip, and it is the only one that catches bit flips, partial writes, and tampered stores. Structure checks prove shape. A sign-verify round trip proves function.

Thirty days, then a fresh start. Long-lived browser keys accumulate exposure: every extension, every XSS window, every shared-device session adds up. Rotation bounds the blast radius, and because certificates are issued per key through our API, rotation is a routine CSR, not a migration. Ephemerality is a feature of the security model, not an inconvenience to apologize for.
Binding keys to devices. A Thumbmark fingerprint is stored alongside the key as its client identity. This is not a PUF and we do not claim it is: browser fingerprints are probabilistic and changeable. What it buys is abuse analysis and lifecycle context, a pragmatic web analog of device binding. Where hardware allows real key attestation, use that instead. Where it does not, honest weak binding beats pretending.
From key pair to certificate. A PKCS#10 CSR is generated from the browser key, submitted through the DPoP-and-HMAC-protected API, and the returned chain is parsed and wrapped into a WebSigner implementing the C2PA Signer interface. The key's entire life, generation, validation, certification, rotation, signing, happens in a loop the SDK drives without user involvement.

setupCrypto accepts seven callbacks: one-shot digest, streaming digest creation, streaming update, streaming finalization, signature verification, signing, and randomness. Streaming digest IDs let native code hash large assets incrementally without shuttling buffers back and forth. NativeTimestampProvider defers the entire RFC 3161 round trip to platform code, because networking and certificate pinning belong to the app, not the library.
The interface is the whole architecture. Everything else is plumbing.
Here is the subtle part that costs implementers days. COSE and C2PA want ECDSA signatures in IEEE P1363 form: r and s concatenated, fixed width. Platform APIs, iOS, Android, most HSMs, return ASN.1 DER. The bridge converts in both directions using an ASN.1 EC signature formatter: DER to P1363 on the way out of native signers, P1363 to DER on the way into native verifiers.
Get this wrong and nothing crashes. Signatures simply fail validation in other tools, silently, on files your users already shipped. This is the class of bug you find with conformance test vectors, not unit tests, which is why our crypto boundary is covered by both.
Robots, AGVs, and industrial cameras are native-code environments with real key stores. This architecture is their on-ramp: the same manifest pipeline, with keys in whatever hardware the platform offers. PUF-derived keys from our Visual Handshake work plug into the same callback interface. Signing at the edge, at capture time, is the pattern our mutual-witnessing patent describes, and this bridge is how it reaches devices that will never run a browser.
Why not compile a Rust core to every platform? That inverts our investment: the value is the shared, audited manifest layer. Narrow crypto callbacks per platform are cheaper to review than a full FFI surface.
Does the bridge slow signing down? Signing is a few hundred bytes across the boundary. Hashing is the volume concern, which is exactly why the digest API is streaming.
Can a robot fleet use hardware attestation? Yes, at the native layer. The library sees a Signer; whether the key is attested by a secure element is a property of the callback implementation.
Is IndexedDB safe for private keys? Safe enough for the browser threat model, with non-extractable key options where supported and validate-on-read as the safety net. It is not a secure enclave, and our security claims do not pretend otherwise.
Why 30 days and not 90? Shorter windows shrink exposure but multiply certificate issuance. Thirty days balances both for evidence capture volumes we see. The constant is a policy decision, not a law.
Cross-platform provenance is usually a story about compromise. Interface-first design is how ours became a story about reuse instead.