Depends on: -
RFCs: RFC-022
Abstract
This spec defines a commitment scheme for results of batch queries executed by ODF nodes. A commitment cryptographically binds the result of a to all of its inputs, including the exact states of the queried , and to the identity of the node that executed it. This allows consumers to process query results optimistically and hold every party involved in producing the result accountable long after the response was received, by verifying and disputing the results later.Commitment Properties
The commitment scheme provides the following properties:- Hiding - The commitment does not reveal any information about the operation. The hashes in the
commitmentsection don’t reveal inputs or outputs, while theproofsection reveals only the identity of the node that performed the computation. - Binding - It is impossible to change any inputs or outputs of the operation without invalidating the commitment.
- Succinct - The commitment is small enough to be stored cheaply (e.g. on a blockchain), and disputing the result does not require storing and transferring the resulting data.
- Deterministic - The same query results in the same commitment, as long as the query itself is deterministic.
- Reproducible - Given the same inputs a third party can repeat the query, arrive at the same results, and validate them against the original commitment.
- Non-repudiable - A node cannot deny performing the operation, as the commitment is signed with the key tied to the node’s identity.
- Composable - Computation split into several steps, possibly executed by nodes belonging to different parties (e.g. when joining datasets of different owners), produces commitments that compose into one final commitment. In case of a dispute the responsibility can be assigned to the specific party, not only to the party that aggregated the final result.
- Multi-protocol - The commitment structure can be reused across different protocols without significant alterations.
Response Structure
A node executing a query that was requested to be verifiable returns a response consisting of the following sections:Input
Theinput section contains all information needed to fully reproduce the result of the operation:
- The query and its dialect
- All parameters that affect the output, including the requested data and schema formats
- The list of queried datasets, each with:
id- the unique identifier of the datasetalias- the name under which the dataset was referred to in the queryblockHash- hash of the block that represents the exact state of the dataset the query was executed against
Output
Theoutput section contains the result data and its schema in the requested formats.
Sub-queries
ThesubQueries section contains information about parts of the operation that were executed by other nodes (e.g. in federated queries). Every entry has the same structure as the top-level response, excluding the output section, making the scheme recursive. Sub-queries are empty when the entire operation was executed by a single node.
Commitment
Thecommitment section is a succinct commitment to the operation, consisting of:
inputHash-multihash(canonicalize(input))outputHash-multihash(canonicalize(output))subQueriesHash-multihash(canonicalize(subQueries))
canonicalize is defined in JSON Hashing.
The commitment section is technically redundant, as the consumer has to recompute all hashes to validate the response anyway. It is included to protect consumers from implementing hashing in a way that is inconsistent with this spec, and to help isolate inconsistencies to specific parts of the response during validation and dispute resolution.
Proof
Theproof section ties the commitment to the identity of the node that performed the computation:
type- signature scheme (e.g.Ed25519Signature2020)verificationMethod- DID of the node, from which the public key used to verify the signature can be derivedproofValue-multibase(sign(canonicalize(commitment)))
JSON Hashing
To exclude variations in whitespace, property order, and number representation between JSON libraries, JSON objects are converted into canonical form as specified in RFC 8785: JSON Canonicalization Scheme before hashing or signing.Response Validation
Immediately upon receiving the response the consumer must validate it to ensure that the commitment is not bogus and is disputable:- Verify that the
proof.verificationMethodDID belongs to the node the data was requested from - Verify
commitment.outputHashby recomputing the hash - Verify
commitment.inputHashby recomputing the hash - Verify
commitment.subQueriesHashby recomputing the hash - Verify the signature in
proof.proofValueusing:- Message:
canonicalize(commitment) - Public key:
key_from_did(proof.verificationMethod)
- Message:
- Repeat steps 3-5 recursively for every entry in
subQueries
Storing Commitments
To be able to dispute the result in future, the consumer should store the following sections:inputsubQueriescommitmentproof
output section doesn’t need to be stored, as it can be reproduced from the input.
These sections provide different layers of verifiability and can be used separately:
input- provides reproducibilitycommitment- seals the response against tamperingproof- adds non-repudiation via signaturesubQueries- provide the above for multi-party computations
Dispute Resolution
The procedure of resolving a dispute using a commitment via reproducibility is as follows:- Consumer submits a claim to the verifier, providing the
input,subQueries,commitment, andproofsections - Verifier obtains the datasets listed in
input.datasetsat the specified block hashes - Verifier validates the claim according to the Response Validation rules
- If any check fails, the claim is rejected as invalid
- Verifier checks that all nodes that signed the
subQueriesare known (registered) nodes- If an unknown node is found, the claim is accepted and the blame is assigned to the root node for using a bogus node to compute part of the response
- Verifier generates the logical query plan and checks that it is identical or equivalent to the plan composed from the
subQueries- If the plan does not correspond to the original query, the claim is accepted and the blame is assigned to the root node for providing a malicious query plan
- In a bottom-up fashion, verifier repeats all computation steps using their
inputsections and compares hashes of the outputs to the correspondingcommitment.outputHashvalues- If a hash doesn’t match, the claim is accepted and the blame is assigned to the node that signed the corresponding commitment for providing malicious output data
Use in Other Protocols
While described here using JSON responses of a REST API, the same structure can be used in other protocols, e.g. Flight SQL using canonical structures in a binary format, or blockchain oracles. In protocols that already provide some of these properties some sections may be redundant. E.g. a blockchain oracle response is already signed by the provider’s transaction, making the root-levelproof unnecessary. Including all sections nevertheless allows using the same dispute resolution procedure across protocols, without the need to map provider addresses on different blockchains to node identities.