Each attribute has:
name – machine-readable key (age, residency.country)type – scalar, range, enum, set, boolean, referenceissuer – self-asserted, gov, institution, protocolvalue – stored encrypted in the Vaultvalid_from / valid_until – temporal boundsattestation_proof – optional proof from external issuerAttributes live in a Merkle Attribute Tree inside the Vault:
attributes_root = MerkleRoot([
leaf(attribute_1),
leaf(attribute_2),
...
])
Attribute Leaf Encoding
Attribute {
descriptor_id // e.g. "residency_country"
value_commitment // commitment to the real value
issuer_id // who asserted it
valid_from
valid_until
attestation_ref? // external attestation link
}
attribute_leaf = H(
descriptor_id,
value_commitment,
issuer_id,
valid_from,
valid_until,
attestation_ref?
)
attributes_root = MerkleRoot(
sorted_by(descriptor_id, [attribute_leaf_1, attribute_leaf_2, ...])
)
The real values live encrypted in the Vault; the Identity Layer only sees commitments and metadata.
value_commitment can be a Pedersen / hash commitment to the real value.descriptor_id before building the tree keeps it deterministic.The Vault stores the raw values, encrypted.
The attribute tree only stores commitments and metadata, so Verifiers never see personal data, only committed facts.