Skip to content
SPEC-WALLET-0001SpecificationIn forceversion 1.0.02 October 2026

In brief ​

This document sets out the rules every wallet compatible with Tamga Network must follow internally: keys, on-device storage, backup, the consent screen and credential copies. It is written for wallet developers; Tamga Wallet (a separate repository) is the reference implementation of these rules.

When to read

Plain explanation

The keys bound to a credential are generated in the phone's secure hardware and never leave it; so they are not backed up, and when the phone changes, the credentials are obtained again from the institution. For every share the person sees what goes to whom and approves it; a site that asks for more than it needs triggers a separate warning. The wallet keeps several copies of the same credential: it always shows the same site the same copy and different sites different copies, so sites cannot link the person across one another. "Sign in with Tamga" uses a separate pseudonym for each site. If the person wishes, they can reset the wallet and delete their data both from Tamga's services and from the phone.


Scope ​

The internal design of the wallet: key management, local storage, backup and recovery, the consent surface, use of credential copies, the schema cache.

The protocols are in SPEC-PROTO-0001 and SPEC-PROTO-0002. The WIA (Wallet Instance Attestation)Cüzdan sağlayıcısının imzaladığı, cüzdan kurulumunun gerçek olduğunu bildiren kısa ömürlü beyan; belge veren, belgeyi vermeden önce denetler. and the key attestationCüzdan sağlayıcısının, belge anahtarının güvenli donanımda üretildiğini ve tutulduğunu bildiren kısa ömürlü beyanı. are in ADR-0025; the cüzdan sağlayıcısı (wallet provider)Cüzdanı sunan ve cüzdan ile anahtar kanıtlarını imzalayan kuruluş. Tamga Wallet ağın ilk cüzdanıdır. issues them.


1. The resolved tension — can the key be backed up? ​

This section is the most important part of the document because two existing design decisions contradicted each other.

1.1 The contradiction ​

SPEC-CRED-0001 §3 says:

The key is generated in the device's secure element (Secure Enclave/StrongBox) and can never be exported → the credential is non-transferable.

The backup design in the project notes, on the other hand, implied:

A 24-word seed + mandatory PIN; an encrypted backup on the server (the server cannot decrypt it).

If the seed brings the wallet back in a usable state, it also brings back the belge sahibi (holder)Belgeyi cüzdanında tutan ve kime göstereceğine karar veren kişi. key. But if the holder key cannot leave the secure area, the seed cannot bring it back.

Both cannot be true at once.

1.2 Why the key cannot be derived from the seed ​

The tempting option is: derive the holder keys from the seed, keep them in software, recover them anywhere.

This option is rejected because it defeats holder bindingBelgeyi yalnız belge sahibinin cihazındaki bir anahtara bağlamak; kopyalanan belge gösterilemez. entirely:

Consequence
Seed → holder key derivableThe seed can be shared
The seed can be sharedThe credential is transferable
The credential is transferableThe gap in SPEC-CRED-0001 §3 comes back

In that document's own words: the attack "a student has their certificate issued into a friend's wallet" would be closed at issuance and reopened at recovery. A back door is more dangerous than a front door because nobody looks there.

1.3 Decision ​

Invariant WL1: holder keys are not derived from a seed and never leave the device's secure area.

Invariant WL2: the backup carries the credential documents and the manifest; it does not carry holder keys. A credential restored on a new device therefore cannot be presented — re-issuance is required.

This is an accepted user-experience cost. The alternative is to lose the system's core security property.

1.3b A third path considered (review R10) ​

The decision was taken between two options; there is a third one, and it needs to be rejected explicitly: platform-synced keys (iCloud Keychain / Google Password Manager style key classes, hardware-backed but portable across devices).

Assessment
ProNo re-issuance on a device change; the best user experience
Con 1Trust moves from Tamga to Apple/Google — they decide where the key goes
Con 2Another device on the same account receives the key → the "credential is non-transferable" principle (WL1) is broken at account level
Con 3The EUDI ARF does not count this class as W3 (certified WSCD); state-stage alignment with the state is at risk

Rejected. In the expansion stage it may be reconsidered as an optional "easy recovery" mode for level W2 — if the user knowingly chooses lower assurance. For now it is not worth the product complexity.

1.4 The real role of the seed ​

The seed does a narrower job than it seems:

What the seed recoversWhat it does not recover
The wallet identity (the decryption key of the backup)Holder keys
The credentials themselves (readable, not presentable)The ability to present
The manifest: which type from which institution—
Settings, language, presentation record—

The manifest is critical: on the new device it offers the user a one-tap list "request these 4 credentials again". It does not remove the pain of recovery but makes it manageable.


2. Key architecture ​

2.1 Key types ​

KeyWhereExportableLifetime
Holder keys (N per issuance)Secure Enclave / StrongBoxNoCredential lifetime
Backup encryption keyDerived from the seedAs the seedPermanent
Wallet instance keySecure areaNoInstallation lifetime

2.2 Wallet assurance levels ​

The wallet-side component of Axis A in PM-ASSUR-0001:

LevelKey storagePhase
W1Software (no secure area)Not supported
W2Device secure area (Secure Enclave / StrongBox)Initial-stage minimum
W3Certified WSCDThe state stage

Invariant WL3: W1 wallets are not supported. Tamga Wallet is not installed on a device without a secure area — it is refused with a clear warning to the user.

2.3 PIN ​

The PIN is the user verification condition for access to the key in the secure area; it does not encrypt the key (the hardware does that).

RuleValue
LengthAt least 6 digits
BiometricsNext to the PIN, not instead of it (the fallback is the PIN)
Attempts5 wrong → 30 s delay; 10 → the wallet locks, the seed is required
Presentation approvalPIN or biometrics mandatory for every presentation

The last row matters: a presentation must be a deliberate act of the user. An unlocked wallet is prevented from presenting silently in the background.


3. Local storage ​

┌──────────────────────────────────────┐
│ Secure area (hardware)               │
│   holder keys — cannot leave         │
├──────────────────────────────────────┤
│ Encrypted local database             │
│   credentials    SD-JWT strings      │
│   batch_state    copy ledger         │
│   verifier_map   sticky mapping      │
│   schema_cache   Type Metadata       │
│   presentation_log  presentation log │
│   settings                           │
└──────────────────────────────────────┘

Invariant WL4: the presentation_log never leaves the device automatically or to a server; it leaves the device only in an export the person starts themselves, encrypted with their own password (EU TS10, ADR-0027) — it does not enter the backup either (SPEC-PROTO-0002/PV8). If it entered the backup, it would be uploaded to the server on a device change, even if encrypted, and a behavioural profile would be centralised.

The user can view and delete this record.


4. Managing credential copies ​

This section closes Open question 1 of SPEC-PROTO-0001 and Open question 3 of SPEC-CRED-0002.

4.1 The sticky copy rule ​

Invariant WL5: a doğrulayıcı (verifier)Gösterilen belgeyi denetleyen taraf: imza, belge verenin güven listesindeki kaydı, durum ve politika. Relying party diye de anılır. is always shown the same batch copy. Different verifiers are shown different copies.

verifier_map: (verifier_id, vct) → copy_index

The rationale works in both directions:

DirectionWhy
Same copy to the same verifierThe verifier already knows who the person is (the application is named). Showing a different copy gains no unlinkability, it only spends copies.
Different copy to a different verifierIf two verifiers collude, they cannot link through cnf and idx (SPEC-CRED-0003 §9.4).

verifier_id is the x509_hashHAIP'teki client kimliği biçimi: kimlik, relying party'nin erişim sertifikasının base64url SHA-256 özetidir. client identifier (SPEC-PROTO-0002 §2.1) — a stable and verifiable key.

4.2 A consistent disclosure set ​

Invariant WL6: for repeated presentations of the same vct to the same verifier, the wallet uses the same disclosure set.

The reason is in the Security notes of SPEC-SCHEMA-0002: a changing set reveals which fields are being hidden. If 8 fields are disclosed in the first presentation and 6 in the second, the verifier can infer the difference.

If the verifier asks for fewer fields, the wallet does not present more — the new request itself applies, not an intersection; but the user is shown "you previously gave this verifier these fields".

4.3 Running out ​

Copies leftWallet behaviour
3Silent — visible in settings
2Notification to the user: "2 uses left for your student certificate"
0, known verifierThe existing copy is used thanks to the sticky mapping — no problem
0, new verifierThe user chooses: (a) refresh, (b) reuse an existing copy — with a linkability warning

Invariant WL7: refresh without user action happens only under the conditions AR1–AR4 of ADR-0023. Institutional credentials that have a refresh token are refreshed at the threshold announced by the institution, with the app in the foreground and unlocked, after a random delay; for identity and contact credentials refresh is a user action. The user can turn it off in settings.

4.4 Diploma — initial stage ​

Under SPEC-PROTO-0001 §8.5 the diploma is issued as a single copy in the initial stage. The sticky mapping still applies (the single copy goes to every verifier) and idx linkability is an accepted risk — it is also shown to the user inside the wallet, not only in the pilot agreement.


5. Consent surface ​

Minimum content, in this order:

  1. Who is asking — the verifier's name (from its güven listesi (trust list)Bir ülkenin kök sertifikalarını, belge verenlerini ve kayıtlı relying party'lerini taşıyan imzalı liste. Bugün Tamga'da güven bu listelere dayanır; ortak defter sonra gelir. entry) + a registered/unregistered mark
  2. For what — the purpose text (SPEC-API-0001 §4.1)
  3. What will be shared — field-by-field list, with values
  4. What will not be shared — the names of the fields that stay hidden (not their values)
  5. Approve / Decline

The fourth item is unusual and deliberate: the user needs to see selective disclosureBir belgeden yalnız doğrulayıcının istediği alanların gösterilmesi, fazlasının değil. working. The line "your grade average will not be shared" explains the product's value at a glance.

5.2 Over-request warning ​

Closes Open question 1 of SPEC-PROTO-0002.

Three levels, three different visual weights:

SituationPresentation
Registered + within scopeNormal screen, no warning
Registered + fields outside scopeOut-of-scope fields appear in the list in a separate block, in a different colour, under the heading "this verifier is not authorised to request these fields". The approve button becomes active after a 3-second delay.
Unregistered verifierA separate screen that interrupts the flow: "This verifier is not registered with Tamga. We cannot verify who it is." → Continue / Cancel

Avoiding warning fatigue: a warning appears only in a truly abnormal situation. In the normal flow there is no warning. If we put a warning on every presentation, it becomes invisible.

Invariant WL8: the over-request warning is not a line of text next to the approve button; it requires a separate visual block and a delayed button.

5.3 Repeated different queries ​

Security notes of SPEC-PROTO-0002: a verifier can map which credentials a user holds by sending different queries.

If more than 3 different queries within 24 hours come from the same verifier, the wallet informs the user: "This verifier asked for 4 different credentials today."

5.4 Per-site pseudonym (ADR-0031) ​

"Sign in with Tamga" uses a per-site pseudonym (takma ad (pseudonym)Cüzdanın her web sitesi için ayrı türettiği kararlı hesap kimliği; iki site aynı kişiyi eşleştiremez.) as the account key, not a credential value (ARF (Architecture and Reference Framework)Rolleri, mimariyi, güven modelini ve kuralları anlatan belge seti. Tamga ARF, AB ARF'sinin düzenini izler. Topic 11).

StepWhat the wallet does
SeedIt verifies the urn:tamga:id:PseudonymSeed:1 credential that comes with the identity credential (same signer as the identity credential, the key of copy 0) and puts the seed into secure storage (Keychain / Keystore; hardware-protected in the store build). The seed does not appear in the credential list and is never offered to a DCQL query (PS3).
RequestA format: "tamga-pseudonym" query in DCQL (meta.mode: single / multiple). If there is no credential query, the request corresponds to a pseudonym-only sign-in (no credential).
Consent screenA "Your pseudonym for this site" card: new, or used before (the value is not shown). On a multiple site the user picks one of their existing pseudonyms or a new one. A pseudonym is given only to a site registered in the trust list.
DerivationAfter PIN/biometric approval: k = HKDF-SHA256(seed, "tamga-pseudonym-v1|" + site + "|" + index) → a P-256 key; pseudonym = the RFC 7638 thumbprint of the public key. Site = the registered client_id of the actual RP (with an intermediary, the actual RP; ADR-0017 K7). The key exists only in memory and is wiped after signing.
PresentationIn the vp_token, under the id of the pseudonym query, a tamga-pseudonym+jwt: the public key in the header, in the body aud = client_id, nonce, rp, plus a fresh WIA and PoP for this transaction.
My pseudonymsSettings: site name, created / last used, a label the user gives (not sent to the site), delete. A deleted index is never derived again for that site; registering again opens a new index. Only the site name and the event are written to the log, never the pseudonym value.

When the identity is verified again on a new phone, the same seed arrives → the same pseudonyms → the accounts on the sites are recognised. The migration file (§7.5) carries neither the seed nor the key (LX2).


6. Schema cache ​

The implementation of ARCH-0003/CMP8.

RuleValue
When it is fetchedAt installation and when a credential of a new type is received
HowIn bulk — all related Type Metadata + the extends chain
When it is not fetchedAt presentation time
ValidityUnlimited — vct#integrity defines the content (SPEC-SCHEMA-0001 §7.1)

Invariant WL9: the wallet makes no request to schemas.tamga.network at presentation time. If it did, the schema server would collect "who used which credential type when".

If a type that is not in the cache is to be presented, the user is told "this credential type cannot be verified yet, an internet connection is needed" and the fetch happens with the user's approval.


7. Backup and recovery ​

7.1 Backup content ​

encrypted_backup = AES-GCM(
    key     = HKDF(seed),
    content = {
        manifest:    [{ issuer, vct, received_at }],
        credentials: [SD-JWT strings],
        settings:    { language, notifications }
    }
)

Not in the backup: holder keys (WL1), presentation_log (WL4), verifier_map.

Why there is no verifier_map: new copies will be obtained on the new device anyway, so the old mapping is meaningless. It also records which verifiers received presentations — the same rationale as WL4.

7.2 Server side ​

The backup may be uploaded to a Tamga-hosted store. The server cannot decrypt it — the key is derived from the seed and the seed never goes to the server.

What the server seesWhat it does not see
Encrypted blob sizeContent
Upload timeWhich credentials
Wallet instance identifierThe user's identity

7.3 Device change flow ​

1. Install on the new device
2. Enter the seed + set a new PIN
3. Download and decrypt the backup
4. The manifest is shown:
     ┌──────────────────────────────────────────┐
     │ 4 of your credentials must be re-issued  │
     │                                          │
     │ ☑ Diploma — Istanbul Bilgi Univ.         │
     │ ☑ Student certificate — Istanbul Bilgi U.│
     │ ☐ Driving licence — (state stage)            │
     │                                          │
     │ [ Request the selected ones again ]      │
     └──────────────────────────────────────────┘
5. An OID4VCI flow for each (SPEC-PROTO-0001)
     → new holder keys, new cnf, new idx

The user is told clearly: the old credentials can be viewed but not presented; re-issuance is needed. Hiding this is worse than hitting a failure at presentation time.

7.4 Losing the seed ​

If the seed and the device are lost, there is no recovery. The user applies again to each institution and proves their identity through the institution's own procedure (SPEC-PROTO-0001 §11 — in-person binding).

This is not a disaster: the credentials are data the institution can produce again. What is lost is access, not data.

Invariant WL10: Tamga never holds a recovery key on the user's behalf. If it did, a centre able to open every wallet would come into existence.

7.5 EU TS10 migration file ​

The wallet produces a migration file in the EU TS10 format (Settings → Move to a new phone):

  • Content: MigrationData, i.e. the list of credentials to obtain again (listOfCredentials: vct, institution, institution address). There are no credentials that are not bound to the device.
  • Encryption: JWE PBES2-HS256+A128KW + A128GCM with the person's password (TS10 §5).
  • Sharing: it goes wherever the person chooses through the share menu; it does not go to Tamga.
  • In the new wallet: the person opens the file; the list links to the institution's page with "obtain again" buttons (WL2).

Credential values, copies and keys do not enter the file. The transaction log does (ADR-0027); on import the person is asked whether to restore the log. The log can also be exported on its own as an encrypted file (TS10 §4.1).

7.6 Reset the wallet and delete my data ​

Settings → Reset the wallet and delete my data (store rules: in-app deletion; KVKK art. 7). Order:

  1. Identity service — for every credential obtained from the identity service, a presentation with no claims disclosed (SD-JWT VC + KB-JWT; aud = the service, nonce = the service's /nonce) → POST {id}/erasure. The service recognises the credential by its own signature and possession by the cnf key; it deletes the record and its event rows, revokes all copies, and has the session and images deleted at the remote identity verification provider (SPEC-ID-0003 §9.1).
  2. Wallet provider — POST {wp}/units/delete signed with the unit key: the unit is revoked (WIA bits), then the record (public key, version, device attestation data) is deleted (ADR-0025).
  3. Device — all credentials and keys, the pseudonym seed, the log, the PIN (WL1: no recovery).

Without a network, step 3 is still done; if steps 1–2 cannot be done, the person is told and shown the e-mail route. Data held by institutions (issuer, verifier) stays with them; the route is a TS7 erasure request (History → "Ask them to delete my data").


8. Invariants ​

#Invariant
WL1Holder keys are not derived from a seed; they do not leave the secure area.
WL2The backup carries the credentials and the manifest; it does not carry keys — a device change requires re-issuance.
WL3W1 (software-key) wallets are not supported.
WL4The presentation_log never leaves the device to a server or automatically and does not enter the server backup; it leaves the device only in an export the person starts, encrypted with the person's password (TS10) (ADR-0027).
WL5Always the same batch copy to a verifier; a different copy to a different verifier.
WL6The disclosure set is consistent for the same verifier + the same vct.
WL7Refresh without user action happens only under the conditions AR1–AR4 of ADR-0023.
WL8The over-request warning requires a separate visual block + a delayed button.
WL9No request to the schema server at presentation time.
WL10Tamga does not hold a recovery key on the user's behalf.
WL11Every presentation requires PIN or biometric approval.
WL12The pass token (tamga-pass+jwt) carries no personal data: only iss (opaque pass_id), aud, iat, exp (≤ 60 s), jti; credential content and claims do not enter the QR code (ADR-0012).
WL13A pass is generated only for an RP/terminal group registered in the trust list, and the consent given at registration is time-limited (≤ 6 months) and scoped; the user can withdraw consent at any moment (the grant is deleted). It is the only exception to WL11.
WL14Every display of a pass is written to the presentation_log (within WL4, on the device); the Show screen displays a live clock and the remaining time.
WL15Site pseudonym keys are not holder keys: they are derived only from the ADR-0031 seed per site and index, and are not stored persistently; the seed stays only in the device's secure storage and enters no backup, no migration file and no presentation.

Security and privacy notes ​

Recovery is the weakest point of holder binding. The reasoning in §1.2 must be repeated: every design proposal that asks for easy recovery must pass the question "does this make the credential transferable?". If the answer is yes, it is rejected.

The backup size is a signal. From the blob size the server can estimate how many credentials there are. Mitigation: the backup is padded to fixed-size blocks.

The sticky mapping keeps a list. verifier_map contains the verifiers to which the user has presented — it is as sensitive as the presentation_log and subject to the same rules (it stays on the device, it does not enter the backup).

PIN lockout is a DoS surface. Someone who seizes the device can enter a wrong PIN 10 times and lock the wallet. Accepted risk — the alternative is to leave it open to brute force.


Open questions ​

  1. Re-issuance on a new device requires the institution to still recognise the person. What will the university do if a graduate changes device 10 years later? A question of institutional process → PM-GTM-0001.
  2. How will W3 (certified WSCD) be detected in the state stage — device attestation or separate hardware? → SPEC-WALLET-0002
  3. How costly is fixed-size padding of the backup? To be measured.
  4. Are multiple devices (tablet + phone) supported? Not now — every device means a separate holder key, so a separate issuance for every device. Batch issuance could partly solve this but has not been designed.
  5. Should verifier_map be shown to the user? For transparency yes, but a list of "which employers you applied to" is also visible to whoever gets hold of the phone.

Related documents ​

SPEC-CRED-0001 · SPEC-CRED-0002 · SPEC-CRED-0003 · SPEC-PROTO-0001 · SPEC-PROTO-0002 · SPEC-SCHEMA-0001 · SPEC-SCHEMA-0002 · SPEC-API-0001 · ARCH-0003 · PM-ASSUR-0001 · PM-GOV-0001 · INVARIANTS


Status ​

In force — version 1.0.0 (2026-10-02).