diff --git a/dip-pasta-compact-quorum-proofs.md b/dip-pasta-compact-quorum-proofs.md new file mode 100644 index 00000000..13165848 --- /dev/null +++ b/dip-pasta-compact-quorum-proofs.md @@ -0,0 +1,503 @@ +
+ DIP: pasta-compact-quorum-proofs + Title: Compact Quorum Proof Chains for Trustless Platform Verification + Author(s): PastaPastaPasta + Special-Thanks: + Comments-Summary: No comments yet. + Status: Draft + Type: Standard + Created: 2026-01-17 + License: MIT License ++ +## Table of Contents + +1. [Abstract](#abstract) +1. [Motivation](#motivation) +1. [Prior Work](#prior-work) +1. [Trusted Initial State](#trusted-initial-state) +1. [Quorum Proof Chain Data Structures](#quorum-proof-chain-data-structures) + 1. [ChainlockEntry](#chainlockentry) + 1. [QuorumCommitmentProof](#quorumcommitmentproof) + 1. [QuorumProofChainResponse](#quorumproofchainresponse) +1. [Verification Algorithm](#verification-algorithm) + 1. [Verifier State](#verifier-state) + 1. [ChainLock Verification](#chainlock-verification) + 1. [Quorum Commitment Verification](#quorum-commitment-verification) + 1. [Proof Processing Algorithm](#proof-processing-algorithm) +1. [Proof Construction](#proof-construction) + 1. [ChainLock Selection Strategy](#chainlock-selection-strategy) + 1. [Quorum Commitment Merkle Proof Construction](#quorum-commitment-merkle-proof-construction) +1. [P2P Messages](#p2p-messages) + 1. [GETQUORUMPROOFCHAIN](#getquorumproofchain) + 1. [QUORUMPROOFCHAIN](#quorumproofchain) +1. [gRPC API](#grpc-api) +1. [Proof Size Analysis](#proof-size-analysis) +1. [Security Considerations](#security-considerations) +1. [Backward Compatibility](#backward-compatibility) +1. [Reference Implementation](#reference-implementation) +1. [Copyright](#copyright) + +## Abstract + +This DIP defines Compact Quorum Proof Chains, a mechanism for trustlessly verifying LLMQ public keys using ChainLocks and the `merkleRootQuorums` field in coinbase transactions. This enables light clients and the Platform SDK to cryptographically verify Platform quorum public keys without trusting any external party. + +The key insight is that a ChainLock at height H proves block H, and that block's coinbase transaction contains a `merkleRootQuorums` covering ALL currently active quorums at that height. This allows verification of any active quorum's commitment using a single chainlocked block's data, resulting in compact proofs of approximately 1 KB in typical scenarios. + +## Motivation + +Platform proof verification currently requires two steps: + +1. **GroveDB Proof**: Verify data against a Merkle root (cryptographic) +2. **Tenderdash Signature**: Verify BLS signature from a Platform quorum (requires quorum public key) + +The quorum public key is currently obtained via trusted sources: + +| Method | Trust Model | +| ------ | ----------- | +| Dash Core RPC | Trust the node operator | +| TrustedHttpContextProvider | Trust centralized quorum servers | + +Both methods require trusting an external party, which undermines the trustless nature of the verification. + +This DIP enables verification of quorum public keys cryptographically using only: + +1. A hardcoded checkpoint (block hash + known quorum keys) embedded in the SDK +2. Proofs provided by any untrusted server (verified client-side) + +By leveraging the existing ChainLock infrastructure and `merkleRootQuorums` commitment in each block's coinbase, clients can build a cryptographic chain of trust from a known checkpoint to any currently active quorum. + +## Prior Work + +* [DIP-0002: Special Transactions](https://github.com/dashpay/dips/blob/master/dip-0002.md) +* [DIP-0004: Simplified Verification of Deterministic Masternode Lists](https://github.com/dashpay/dips/blob/master/dip-0004.md) +* [DIP-0006: Long-Living Masternode Quorums](https://github.com/dashpay/dips/blob/master/dip-0006.md) +* [DIP-0007: LLMQ Signing Requests / Sessions](https://github.com/dashpay/dips/blob/master/dip-0007.md) +* [DIP-0008: ChainLocks](https://github.com/dashpay/dips/blob/master/dip-0008.md) + +## Trusted Initial State + +Verification requires a trusted starting point embedded in client software. This checkpoint must contain: + +1. A block hash and height identifying a known-good block +2. The public keys of active ChainLock quorums at that height (identified by quorum hash and type) + +The specific serialization format of this checkpoint is an implementation detail left to client software. + +### Quorum Lifespans and Checkpoint Freshness + +The effectiveness of this verification scheme depends on overlapping quorum lifespans between the checkpoint and current chain tip. + +**Mainnet:** + +| Quorum Type | Purpose | DKG Interval | Active Count | Lifespan | +| ----------- | ------- | ------------ | ------------ | -------- | +| LLMQ_400_60 | ChainLocks | 288 blocks (~12 hours) | 4 | ~48 hours | +| LLMQ_100_67 | Platform | 24 blocks (~1 hour) | 24 | ~24 hours | + +**Testnet:** + +| Quorum Type | Purpose | DKG Interval | Active Count | Lifespan | +| ----------- | ------- | ------------ | ------------ | -------- | +| LLMQ_50_60 | ChainLocks | 288 blocks (~12 hours) | 4 | ~48 hours | +| LLMQ_25_67 | Platform | 24 blocks (~1 hour) | 24 | ~24 hours | + +With a checkpoint less than 36 hours old, at least one ChainLock quorum from the checkpoint will still be active, enabling direct verification with a single chainlock. Older checkpoints require bridging through intermediate chainlock quorums. + +## Quorum Proof Chain Data Structures + +### ChainlockEntry + +A ChainLock signature that proves a specific block is canonical. + +| Field | Type | Size | Description | +| ----- | ---- | ---- | ----------- | +| height | int32_t | 4 | Height of the chainlocked block | +| blockHash | uint256 | 32 | Hash of the chainlocked block | +| signature | BLSSig | 96 | Recovered threshold signature | +| signingQuorumHash | uint256 | 32 | Hash of the quorum that signed this chainlock | +| signingQuorumType | uint8_t | 1 | LLMQ type of the signing quorum | + +Total size: ~165 bytes + +**Note**: The signing quorum can be deterministically calculated using `SelectQuorumForSigning` given the height, but including it explicitly simplifies verification and enables the verifier to check if the signing quorum is known before attempting signature verification. + +### QuorumCommitmentProof + +A proof that a specific quorum commitment is included in a chainlocked block's `merkleRootQuorums`. + +| Field | Type | Size | Description | +| ----- | ---- | ---- | ----------- | +| commitment | CFinalCommitment | variable | The quorum final commitment (see [DIP-0006](https://github.com/dashpay/dips/blob/master/dip-0006.md)) | +| chainlockIndex | uint32_t | 4 | Index into the response's chainlocks array | +| quorumMerklePathLength | compactSize uint | 1-9 | Number of hashes in the merkle path | +| quorumMerklePath | uint256[] | 32 * length | Merkle path from commitment hash to `merkleRootQuorums` | +| coinbaseTx | CTransaction | variable | The coinbase transaction containing `merkleRootQuorums` | +| coinbaseMerkleProof | CPartialMerkleTree | variable | Merkle proof that coinbase is in the block | + +The `CFinalCommitment` structure is defined in [DIP-0006](https://github.com/dashpay/dips/blob/master/dip-0006.md) and contains the `quorumPublicKey` that this proof ultimately verifies. + +Estimated size: ~700-900 bytes (varies by quorum size and tree depth) + +### QuorumProofChainResponse + +The complete response containing all data needed to verify a target quorum. + +| Field | Type | Size | Description | +| ----- | ---- | ---- | ----------- | +| headerCount | compactSize uint | 1-9 | Number of block headers | +| headers | CBlockHeader[] | 80 * count | Block headers for each chainlock | +| chainlockCount | compactSize uint | 1-9 | Number of chainlock entries | +| chainlocks | ChainlockEntry[] | variable | ChainLock signatures in verification order | +| quorumProofCount | compactSize uint | 1-9 | Number of quorum proofs | +| quorumProofs | QuorumCommitmentProof[] | variable | Quorum commitment proofs | + +Headers and chainlocks are paired by index: `headers[i]` corresponds to `chainlocks[i]`. + +## Verification Algorithm + +### Verifier State + +The verifier maintains the following state: + +```text +H_verified: uint32 // Highest height cryptographically confirmed +Q_known: Map<(uint256, uint8), BLSPubKey> // Known quorum public keys + // Key: (quorumHash, quorumType) + // Value: quorumPublicKey +``` + +Initial state is populated from the checkpoint: + +* `H_verified = checkpoint.height` +* `Q_known = checkpoint.chainlockQuorums ∪ checkpoint.platformQuorums` + +### ChainLock Verification + +To verify a ChainLock against a known quorum: + +1. Verify the signing quorum is in `Q_known` +2. Retrieve the quorum's public key from `Q_known` +3. Calculate the message hash: + `msgHash = SHA256(llmqType, quorumHash, SHA256(height), blockHash)` +4. Verify the BLS signature against the quorum public key and message hash +5. Verify that `hash(header) == blockHash` + +If verification succeeds, update `H_verified = max(H_verified, chainlock.height)`. + +### Quorum Commitment Verification + +To verify a quorum commitment proof: + +1. Verify `chainlockIndex` references a chainlock with height <= `H_verified` +2. Retrieve the corresponding coinbase transaction and block header +3. Verify the coinbase merkle proof: + * The `coinbaseMerkleProof` must prove that `coinbaseTx` is in the block + * The block's merkle root must match `header.hashMerkleRoot` +4. Extract `merkleRootQuorums` from the coinbase transaction's extra payload +5. Calculate `commitmentHash = SHA256(serialize(commitment))` +6. Verify the quorum merkle path: + * Compute the merkle root from `commitmentHash` and `quorumMerklePath` + * The computed root must match `merkleRootQuorums` +7. Verify the commitment's `quorumSig`: + * This threshold signature proves the quorum members agreed on this public key + * Verification uses the aggregated public keys from the commitment's `signers` bitvector + +If verification succeeds, add the quorum to `Q_known`: +`Q_known[(commitment.quorumHash, commitment.llmqType)] = commitment.quorumPublicKey` + +### Proof Processing Algorithm + +```text +FUNCTION verify_quorum_proof(checkpoint, proof, targetQuorum) -> Result