Participant Assurance Levels¶
Based on:
doc/project/40-proposals/007-pod-identity-and-tenancy-model.mddoc/project/40-proposals/017-organization-subjects-and-org-did-key.mddoc/project/20-memos/console-participant-identity-create-and-import.mddoc/normative/50-constitutional-ops/ROOT-IDENTITY-AND-NYMS.md(DIA-ROOT-ID-001)doc/normative/50-constitutional-ops/ATTESTATION-PROVIDERS.md(DIA-ATTEST-PROVIDERS-001)doc/normative/50-constitutional-ops/ROLE-TO-IAL-MATRIX.md(DIA-ROLE-IAL-001)
This memo defines the assurance level model for participant:did:key:... subjects
in Orbiplex Node. It establishes the four-level credibility hierarchy, the
append-only verification fact contract, the sovereign operator trust anchor
pattern, and the privacy boundary that keeps PII out of the fact log.
This model is a prerequisite for downstream consumers — procurement policy, capability access control, and federated trust presentation — that need a stable assurance level contract to design against.
Motivation¶
Not all participants are equally credible. An anonymous key with no external verification carries different weight than a participant whose phone number has been confirmed, or one whose government-issued identity has been attested, or one whose public key is an explicitly pinned infrastructure trust anchor.
The assurance level is not a reputation signal — it is a structural property of
the identity binding itself: how strongly is this participant:did:key:...
anchored to a verifiable real-world entity?
Downstream systems — procurement eligibility, capability policy gates, federation onboarding, escrow authorization — may require a minimum assurance level as a precondition. That contract must be defined once, at the identity layer, rather than reimplemented ad hoc by each consumer.
Canonical Scale: IAL0–IAL5¶
The Orbiplex Node assurance model is grounded in the normative DIA identity
assurance level scale defined in ROOT-IDENTITY-AND-NYMS.md
(DIA-ROOT-ID-001). That scale runs from IAL0 to IAL5.
The four levels used by the Participant runtime map to the canonical scale as follows:
| Runtime name | Canonical level | Source of assurance |
|---|---|---|
Unknown |
IAL0 |
no external attestation |
PhoneVerified |
IAL1 |
phone OTP confirmation (source_class: phone) |
GovIdVerified |
IAL3 |
eID, PESEL+registry, or equivalent strong source |
SovereignOperator |
IAL5 |
software-pinned key; governance designation |
IAL2 (basic multisig pseudonym) and IAL4 (legally/constitutionally
unsealable pseudonym) are not exposed as distinct levels in the MVP Participant
runtime. They remain part of the canonical DIA scale for use in federation and
governance contexts where those levels are relevant.
GovIdVerified maps to IAL3 rather than IAL2 because the supported
verification methods (eid, mobywatel, epuap, PESEL via registry) all fall
under source_class: strong in ATTESTATION-PROVIDERS.md, which tops out
at IAL3. Reaching IAL4 would require a separate unsealing track, which is
out of scope for MVP.
SovereignOperator maps to IAL5 because it is a governance-level trust
anchor, orthogonal to the attestation chain. It is defined as a distinct
strength class (sovereign) in ATTESTATION-PROVIDERS.md.
Relationship to NIST SP 800-63 and eIDAS¶
The DIA IAL0–IAL5 scale is structurally parallel to established identity
assurance frameworks, adapted to the Orbiplex trust model.
NIST SP 800-63-3 defines three Identity Assurance Levels:
- IAL1: claimed identity, no real-world verification required,
- IAL2: evidence-based verification, remote or in-person identity proofing,
- IAL3: in-person or supervised remote verification, physical or biometric evidence.
eIDAS (EU regulation 910/2014 and its 2.0 revision) defines three assurance levels for electronic identification:
- Low: limited confidence in the claimed identity,
- Substantial: substantial confidence, typically multi-factor authentication,
- High: high confidence, multi-factor with physical presence or equivalent.
The DIA canonical levels map approximately to those frameworks as follows:
| DIA level | Runtime name | NIST SP 800-63 | eIDAS | Basis |
|---|---|---|---|---|
IAL0 |
Unknown |
below IAL1 | below Low | key exists, no binding verified |
IAL1 |
PhoneVerified |
IAL1 | Low | possession factor (phone OTP) |
IAL2 |
— | IAL1–IAL2 | Low–Substantial | basic multisig; not exposed in MVP runtime |
IAL3 |
GovIdVerified |
IAL2 | Substantial–High | strong source: eID, registry, qualified sig |
IAL4 |
— | IAL3 | High | unsealable; requires separate track |
IAL5 |
SovereignOperator |
N/A | N/A | software-anchored governance designation |
The mapping is approximate. NIST IAL2 aligns roughly with DIA IAL3 because
both require evidence-based real-world identity proofing from a strong source;
DIA IAL2 is the intermediate multisig fallback which has no direct NIST
equivalent. DIA IAL5 has no equivalent in NIST SP 800-63 or eIDAS — those
frameworks address personal identity verification and do not define a class for
software-distribution trust anchors.
Assurance Levels¶
IAL5 SovereignOperator > IAL3 GovIdVerified > IAL1 PhoneVerified > IAL0 Unknown
IAL0 — Unknown¶
No verification has been performed. The participant is identified only by their
participant:did:key:... value. Self-declared metadata such as nickname or
label does not elevate this level.
This is the default state for every newly created or imported participant.
IAL1 — PhoneVerified¶
The participant's phone number has been confirmed via an active verification step (for example, SMS OTP). This establishes that the operator controlling the participant key also controls the claimed phone number at the time of verification.
This level does not bind the participant to a real-world legal identity. It is a
possession-factor confirmation, not an identity proofing step. Corresponds to
source_class: phone in ATTESTATION-PROVIDERS.md.
IAL3 — GovIdVerified¶
The participant has been bound to a government-issued identity record: a country code and a national identification number (for example, PL + PESEL, DE + personal ID, or similar). Verification must be performed against an authoritative source or a delegated attester.
This level provides a binding between the cryptographic participant and a
legal-identity-level real-world entity. It is the strongest level achievable
through claim verification in the MVP runtime. Corresponds to source_class:
eid, mobywatel, epuap, or registry in ATTESTATION-PROVIDERS.md.
IAL5 — SovereignOperator¶
The participant's public key appears in the node's sovereign operator list — a statically configured or compiled-in set of explicitly pinned trusted keys. This designation is a governance decision, not a verification outcome.
Sovereign operator status is not derived from any verification fact. It overrides
the claim-based hierarchy entirely. A sovereign operator with no verified phone
or government ID still holds the highest assurance level, because the trust
anchor is the explicit key pinning in the software distribution, not the
verification chain. Corresponds to source_class: software-pinned in
ATTESTATION-PROVIDERS.md.
Assurance Level as a Derived Property¶
The assurance level is not stored. It is computed by the projector from:
- the set of
ParticipantVerificationFactevents for the participant, - the sovereign operator list from node configuration.
This ensures the level is always consistent with the current fact history and sovereign list. If a verification is revoked, the level drops immediately on next projection. If a participant is added to or removed from the sovereign list, the level updates on next daemon open or configuration reload.
Pseudocode:
fn compute_assurance_level(participant_id, verification_facts, sovereign_list):
if participant_id in sovereign_list:
return SovereignOperator
if any GovIdVerificationConfirmed and not revoked for participant_id:
return GovIdVerified
if any PhoneVerificationConfirmed and not revoked for participant_id:
return PhoneVerified
return Unknown
Verification Facts¶
Verification events are recorded in the stream identity/participant-verification-fact.v1
as append-only facts. The stream follows the same pattern as
identity/participant-fact.v1.
Critical constraint: the fact log must contain no data derived from the verified material — not the raw value, and not any hash of it.
Phone numbers and national ID numbers (PESEL, passport, etc.) have limited
entropy and predictable structure. A hash of such a value — even blake3 — is
vulnerable to brute-force enumeration: an attacker who obtains the hash can
recover the original value by exhaustively hashing the small search space. For
Polish phone numbers (+48 + 9 digits ≈ 10⁹ candidates) or PESEL (11 digits
encoding birth date and gender, further reducing the effective search space),
this attack is practical on commodity hardware.
The fact therefore records only that verification occurred — by whom, and when:
ParticipantVerificationFact
| PhoneVerificationConfirmed
| participant_id: String // participant:did:key:z...
| verified_at: String // RFC 3339
| verifier_ref: String // reference to attestation bundle or verifier id
|
| GovIdVerificationConfirmed
| participant_id: String
| country_code: String // ISO 3166-1 alpha-2, e.g. "PL"
| id_kind: String // "pesel" | "nip" | "passport" | ...
| verified_at: String
| verifier_ref: String
|
| VerificationRevoked
participant_id: String
claim_kind: String // "phone" | "gov-id"
revoked_at: String
reason: Option<String>
country_code and id_kind are retained in GovIdVerificationConfirmed
because they describe the verification method, not the verified value. They do
not allow reconstruction of the ID number.
Local deduplication. If the node needs to detect duplicate verification
attempts for the same phone number or ID (for example, to prevent one number
from being linked to multiple participants), that check must use
HMAC(node_secret_key, normalized_value) in a separate local store outside
the fact log — never the raw value or an unsecretted hash. The HMAC key is
node-local and never leaves the machine. This store is mutable and deletable,
consistent with GDPR obligations.
Attestation Bundle — What the Participant Presents¶
When a participant presents proof of verification to another party (another node, a federation onboarding gate, a procurement policy check), they present an attestation bundle — a signed artifact produced by the verifying parties.
The attestation bundle proves that verification occurred via the verifiers' signatures. It contains no material derived from the verified data:
participant-verification-attestation.v1:
participant_id // participant:did:key:z...
claim_kind // "phone" | "gov-id"
country_code? // for gov-id: ISO 3166-1 alpha-2
id_kind? // for gov-id: "pesel" | "passport" | ...
assurance_level // "ial1" | "ial3"
verified_at
expires_at
verifier_signatures[] // one or more verifier signatures
The receiving party verifies the signatures, not any hash of the participant's phone number or ID. The phone number and ID number are never present in the bundle in any form.
This separation is the security boundary: the fact log records what happened locally; the attestation bundle is what crosses trust boundaries. Neither contains brute-forceable derivations of PII.
Privacy Boundary and GDPR¶
The append-only fact log is incompatible with GDPR Article 17 (right to erasure) if it contains personal data in any recoverable form. The design above satisfies this by ensuring the fact log contains no PII and no hash from which PII could be recovered.
If the node needs to store retrievable PII for operational reasons (for example, to re-present data to the operator), that data must live in a separate, mutable store outside the fact log, with:
- explicit retention policy,
- operator-accessible deletion path,
- no cross-node replication by default.
The existence of such a store and its schema is outside the scope of this memo and should be defined in a dedicated privacy or data-retention document.
Sovereign operator trust requires no PII at all. It is purely a key-pinning designation with no personal data involved.
Sovereign Operator List¶
The sovereign operator list is a node-level configuration, not a fact in the log.
It is loaded at Daemon::open() alongside the fact history and passed into the
assurance level computation as an external parameter.
Recommended form in the node daemon TOML:
[identity]
sovereign_operators = [
"participant:did:key:z6Mk...",
]
For keys whose trust is protocol-level rather than deployment-level (for example, a designated Orbiplex Foundation infrastructure participant), the list may be compiled into the binary as a compile-time constant. That decision is a governance call, not an implementation detail.
The sovereign operator list must be treated as a security-sensitive configuration artifact. Changes to it should be auditable at the deployment level, equivalent to changing a TLS trust anchor.
Downstream Consumers¶
The assurance level is a contract that the identity crate exposes for
consumption by other subsystems. Anticipated consumers include:
- procurement policy — minimum assurance level required to place an order,
- capability access control — certain host capabilities gated by assurance level,
- federated trust presentation — how this node presents its operator participant's assurance level to peers,
- escrow and settlement authorization — high-value operations may require
GovIdVerifiedor higher, - onboarding gates — federation admission may require a minimum level.
None of these downstream contracts are defined here. This memo establishes only the identity-layer contract. Each consumer defines its own minimum level requirement independently.
What This Memo Does Not Define¶
- The verification protocol for phone confirmation (SMS OTP, carrier lookup, etc.).
- The verification protocol for government ID (document scan, registry API, etc.).
- The schema for the separate PII store, if one is introduced.
- The format or validation rules for national ID numbers by country.
- The schema for the local deduplication store using HMAC.
- The full schema and signing contract for
participant-verification-attestation.v1. - Threshold or delegated custody of assurance-level claims.
- Cross-node or federated presentation of assurance levels.
- The governance process for adding or removing sovereign operator keys.
Those should be defined in dedicated documents as the relevant workstreams mature.