How consent is proven
How a consent record, its sealed event chain, a signed receipt and a daily anchor together prove what a person chose.
A consent is worth what you can prove about it later. The proof has to show what the person saw, what they chose, when, under which law, and that nobody edited the answer afterwards. PIEDAP Consent builds that proof in four layers.
Four layers of proof#
| Layer | What it shows | Who can check it |
|---|---|---|
| Consent record | The person's current answer to one form | Anyone with access to the project |
| Sealed event chain | Every past state of the record, each sealed to the one before | The deployment, which holds the sealing key |
| Signed receipt | The record, the wording and the chain, signed for use outside the product | Anyone with the published public key |
| Daily anchor | All of a project's sealed events for one day, under one signed root | Anyone who kept the anchor when it was sent |
The consent record#
There is one record per person per form, kept apart for live and test keys. It holds the current answer and changes when the person changes their mind.
The seal covers these fields:
- the consent id, and the keyed hash and type of the identifier
- the form, its version and a SHA-256 of its exact definition
- each decision: the purpose, the answer, the time and any partner answers
- the status and what produced it, such as
ACCEPT_ALLorWITHDRAW - the country, subdivision, law and property
- the channel, language, environment and times
- for a child or a person with a guardian, the relationship, the method and time of verification, and a keyed hash of the reference
- for consent brought in from earlier, the basis you stated and the reference or SHA-256 of the notice the person saw
- for consent taken by your staff or on paper, the capture context: channel, method, evidence reference, document SHA-256 and keyed staff and site hashes, on its own event
An import's own id, and an unsealed copy of the original time, sit beside the seal; the time itself is sealed with each decision. Each field above is sealed only when it is set, so older records seal exactly as before.
Some details sit beside the record, outside the seal. They are the subject fingerprint, the IP address hash, the browser, the page address and your metadata. The encrypted readable identifier, if the project keeps one, sits there too. Leaving them out of the seal is what lets erasure remove them without breaking the proof.
The sealed event chain#
Every change of state adds an event. The event holds the full state at that moment and a proofHash:
proofHash = HMAC-SHA256(chainKey,
"v3:" + previousProofHash + ":" + canonical(payload))canonicalis JSON with keys sorted at every depth, so the same state always gives the same text.previousProofHashis the seal of the event before, or 64 zeros for the first event.chainKeyis a secret held outside the database. Each event stores the id of the key that sealed it, so the key can be changed while older events still verify.
Sealed event types are CREATED, UPDATED, WITHDRAWN, EXPIRED, ERASED and LINKED. Events are numbered from 1 within a record, and the database refuses two events with the same number.
Changing a past state means recomputing the seal of every later event, and that needs the chain key. Someone who can write to the database but does not hold the key cannot produce a keyed chain that verifies.
Earlier seal versions and events outside the chain
The prefix is the seal version. Version 3 includes the property. Version 2 events keep verifying unchanged. Events from before keyed sealing use version 1, a plain SHA-256, and the result says when a chain includes them.
Exporting a receipt writes an EXPORTED event for the audit trail. It sits outside the chain and shares the numbering, so the sealed events of a record can skip a number. RENEWED is defined as a sealed type, and nothing writes it in this version.
An example#
Asha accepts analytics on 17 September and withdraws on 24 September. On 2 October she asks to be erased. Her record then has three sealed events:
| Number | Type | What it seals |
|---|---|---|
| 1 | CREATED |
Analytics allowed, against version 3 of the form |
| 2 | WITHDRAWN |
Every optional purpose refused, and the time of withdrawal |
| 3 | ERASED |
The erased state |
Erasure never deletes history. It removes the details beside the record and keeps the keyed hash, because every seal covers it. A consent still in force when the person is erased gets a WITHDRAWN event first.
Limits#
- The keys matter. Whoever holds both the chain key and the signing key can create new, validly sealed records. Anchors you hold outside the deployment limit this to days not yet anchored.
- Today is not anchored yet. A day's events are covered by the anchor made after the day closes.
- Only the deployment can replay the seals. Recomputing an event's HMAC needs the chain key. A third party relies on the signed result in the receipt and, for independence, on the anchors.
- Test records are not evidence. They are sealed and anchored like live ones, then deleted 30 days after their last change.
- Retention deletes records. When the operator turns enforcement on, a record past its period is deleted with its events. A hash of each event stays, so earlier anchors still verify.