Hashing
MPCP uses deterministic, domain-separated hashing for signatures and intent binding.
Canonical JSON
All hash inputs use canonical JSON:
- Sorted keys (lexicographic)
- No whitespace
- UTF-8 encoding
- Consistent handling of optional/null fields
This ensures identical hashes across implementations and environments.
Domain-Separated Prefixes
MPCP prefixes hash inputs with a domain string to prevent cross-artifact and cross-protocol collisions:
| Artifact | Domain Prefix |
|---|---|
| PolicyGrant | MPCP:PolicyGrant:1.0: |
| SBA | MPCP:SBA:1.0: |
| SPA | MPCP:SPA:1.0: |
| SettlementIntent | MPCP:SettlementIntent:1.0: |
Example for SBA:
hash = SHA256("MPCP:SBA:1.0:" || canonicalJson(authorization))
The version in the prefix matches the artifact version field.
SettlementIntentHash
The intentHash binds an SPA to a canonical settlement intent:
intentHash = SHA256("MPCP:SettlementIntent:1.0:" || canonicalJson(canonicalIntent))
The canonical payload includes only semantic fields:
- version
- rail
- asset (if present)
- amount
- destination (if present)
- referenceId (if present)
Metadata (e.g., createdAt) is excluded from the hash.
Purpose
- Deterministic verification — Same input → same hash across implementations
- Replay protection — intentHash binds authorization to a specific settlement
- Dispute resolution — Intent can be anchored to a ledger; disputes verify anchor against intentHash
- Future versions — Domain prefixes isolate 1.0 from 1.1, 2.0, etc.