EUDI Wallet-backed image commitments
Introducing IIRY: the «Is It Really You» commitment to images - based on Content Credentials standards
The first European Digital Identity Wallet hackathon for the German implementation has concluded. My submission is IIRY - an iPhone/iPad app + small backend that lets, for example, a parent challenge a request for money by a child over WhatsApp. It builds on - and extends - two relevant Content Credentials standards: C2PA and CAWG VC+VP.
Important boundary: IIRY does not prove that the WhatsApp account belongs to the wallet holder, that the message is true, or that the request is legitimate. It proves something narrower: a state-issued EUDI Wallet holder presentation was bound to this particular image file, and the visible challenge lets the receiver judge whether the screenshot answers the request they sent.
As the whole EUDIW ecosystem is not in production yet, IIRY relies on the German sandbox implementation - which is not yet feature-complete itself. The sandbox does not allow real identities to be used and is thus restricted to the test persona of “Erika Mustermann”.
Flow
The IIRY UX flow would look this, for the aforementioned money-ask case:
the parent would post the «Is It Really You» challenge to the WhatsApp channel,
the child would screenshot the conversation and
share the screenshot with the IIRY app
the IIRY app:
prepares the image to host the wallet-backed commitment (C2PA + CAWG)
builds a matching Credential Presentation request and
opens the German EUDIW Sandbox app used in the SPRIND hackathon environment
(the wallet returns a holder-bound presentation for a nonce that IIRY made image-specific, technically resulting in a vp_token)
ties the vp_token in with the C2PA + CAWG structure
offers to share the committed image back with WhatsApp
the parent would:
receive the committed image back,
share the image with the IIRY app and
confirm using IIRY that the image was bound to the state-issued digital identity of the child (including a visual check of the timestamped IIRY challenge)
Messengers different from WhatsApp are also supported - most testing during development was done using Telegram.
Implementation
High level slides are here (originally created for LinkedIn). The app (source on Github) is written in Swift, the small backend in Python. The backend is there to receive the identity/presentation data from the EUDIW ecosystem, but the processing steps of the image take place right on the edge device (iPhone/iPad/Mac). The image content is thus not sent to a remote server (or shared with state institutions like the German federal printing agency - in its role of the digital identity issuer). Because messenger apps remove metadata including C2PA containers, images with an IIRY commitment are protected in two ways:
shared as files, not plain images
a new file extension “.c2pa.cawg.iiry” is added to “.jpg”
Perhaps counter-intuitively, the IIRY commitment is not stored as Exif metadata. Instead, IIRY writes a C2PA/JUMBF manifest store into JPEG APP11 segments - the JPEG marker reserved by C2PA for this kind of metadata. Inside that JUMBF store, IIRY carries a constrained C2PA profile: a c2pa.hash.data assertion, a cawg.identity assertion, a c2pa.claim.v2 claim, and a detached COSE_Sign1 ES256 signature over the C2PA claim. (This COSE signature is the C2PA manifest signature; it is separate from the wallet holder-binding proof, which remains inside the OpenID4VP / SD-JWT VC presentation carried by cawg.identity.)
The so-called hard binding starts with c2pa.hash.data: the IIRY verifier recomputes a SHA-256 hash over the JPEG while excluding the embedded C2PA APP11 byte ranges themselves. The CAWG identity assertion then references that same hard-binding assertion. The C2PA claim records hashes of the embedded assertions, including c2pa.hash.data and cawg.identity, and the C2PA claim signature authenticates those claim bytes. So the binding chain is: JPEG bytes excluding C2PA APP11 ranges → c2pa.hash.data → cawg.identity → wallet evidence.
The subtle part is that the wallet nonce must already commit to the CAWG signer payload before the wallet returns. IIRY handles this by following CAWG’s draft placeholder/data-hash interaction pattern: it builds a placeholder identity assertion of stable size, computes the future signer-payload hash, puts that hash into the OpenID4VP nonce, and later replaces the placeholder with the real wallet evidence while preserving the C2PA hash layout.
Standards proposal
IIRY is also a proposal for a narrow CAWG extension. CAWG’s current VC+VP profile defines how identity assertions can be represented in Content Credentials, but the German EUDI Wallet sandbox flow returns OpenID4VP evidence using SD-JWT VC presentations. IIRY therefore uses a namespaced CAWG sig_type for OpenID4VP holder-binding evidence. The wallet signs a holder-binding proof over the OpenID4VP nonce; IIRY makes that nonce commit to the CAWG signer payload and C2PA image-binding context.
Shortcomings
IIRY was developed against and tested with the German EUDIW Sandbox app and backend infrastructure. Interoperability with other states’ EUDIW implementations is unknown as of yet.
To bind the identity to the image, IIRY uses the nonce parameter of the EUDIW holder presentation request. This implementation detail is informed by the fact the German EUDIW implementation does not yet support transaction_data (or QES).
Because messaging apps may strip C2PA metadata or even resample the image (thus invalidating any file hashes), the protective .iiry file is needed (see above). This, however, renders the user experience non-self-explanatory.
In my tests, WhatsApp, Telegram, and Garmin Messenger did not preserve the C2PA metadata path IIRY needs.
CAWG VC+VP itself is not yet a published standard, but a work-in-progress draft. The IIRY extension proposal should therefore be read as prototype profile work, not as something current generic CAWG validators already understand.
IIRY commitments carry state-issued, issuer-confirmed identity data inside the image file. This is intended and core to the design, but it is also a privacy trade-off: sharing the intact Commitment file means sharing the disclosed wallet presentation evidence.
Only JPEG is supported currently. Any other formats, including the PNGs created by the iOS screenshot function, are converted to JPEG first.
Bug: existing metadata is lost during the conversion step, e.g. the screenshot marker flag that iOS adds to such PNGs.
The C2PA generator signature requires a trusted signing key. The IIRY repository includes the sample/test key from c2patool for that purpose. A production-grade deployment would use a different key, with the obstacle that c2patool - the official C2PA command-line tool - would not automatically trust it. (Production-grade deployments would need to go through the C2PA Conformance Program). Workaround: pass the sample trust anchor to c2patool explicitly outside production-grade setups.
c2patool rejects .iiry files out of the box because it detects media type from the file extension. The workaround for local inspection is to copy the same bytes to a temporary .jpg filename before invoking c2patool.
Next steps
Align the implementation with upcoming DE EUDIW revisions
Support other wallet implementations?
Present standard extensions to CAWG?
Consider alternatives to the C2PA(tool) sample generator key?









