Skip to content

mpt: shorten, generalize proofs (API and wire format change) - #79

Merged
FiloSottile merged 1 commit into
FiloSottile:mainfrom
rsc:main
Jul 8, 2026
Merged

mpt: shorten, generalize proofs (API and wire format change)#79
FiloSottile merged 1 commit into
FiloSottile:mainfrom
rsc:main

Conversation

@rsc

@rsc rsc commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

As suggested in rsc/tmp#21 and #75, shorten proofs to remove the mptproof prefix, which costs 8 bytes per proof for little benefit. In fact, if we are going to strip non-essential information, then the single-byte prefix at the start of the proof is also unnecessary, so this commit removes that too.

While we are changing the proof format, also use a varint-encoded length prefix ahead of keys and values, so that the wire format of proofs applies to any size keys and values, even though this API still assumes [32]byte. (Followup work will revise the package API to allow variable-size keys and values.)

The handling of variable-length keys is slightly subtle since we have to pad keys of different lengths to make them comparable for insertion in the tree, but we want to avoid introducing any ambiguity where two different keys pad to the same bit sequence. The answer is to pad with a sequence that always differs from itself when not exactly aligned (so not all 0s or all 1s or any other purely repeating sequence). Working within that constraint, the chosen key padding is a 0x00 byte followed by as many 0xFF bytes as needed. The 0x00 ensures that NUL-free text keys sort in the usual order in the tree, while the 0xFFs that follow ensure that keys of other lengths (even keys ending in 0x00 or 0xFF) will not have the same padding at the same positions.

The previous Prove and Verify signatures were:

Prove(key Key) (proof Proof, err error)
Verify(snap Snapshot, key Key, proof Proof) (val Val, ok bool, err error)

Now they are:

Prove(key Key) (val Val, ok bool, proof Proof, err error)
Verify(snap Snapshot, key Key, val Val, ok bool, proof Proof) error

The invariant maintained is that Verify is passed the snapshot plus all the results of Prove. The difference is that now the val, ok are returned by Prove instead of Verify. Of course, they should not be trusted until Prove has succeeded.

This commit also adds VerifyPresent and VerifyNotPresent helpers wrapping Verify, which can improve clarity at some call sites.

This commit also adds test vectors for Verify in testdata/verify.txt, for easier use by other implementations.

As suggested in rsc/mpt#21 and FiloSottile#75, shorten proofs
to remove the mptproof prefix, which costs 8 bytes per proof for little benefit.
In fact, if we are going to strip non-essential information, then the
single-byte prefix at the start of the proof is also unnecessary,
so this commit removes that too.

While we are changing the proof format, also use a varint-encoded length
prefix ahead of keys and values, so that the wire format of proofs applies
to any size keys and values, even though this API still assumes [32]byte.
(Followup work will revise the package API to allow variable-size keys and values.)

The handling of variable-length keys is slightly subtle since we have to
pad keys of different lengths to make them comparable for insertion in
the tree, but we want to avoid introducing any ambiguity where two different
keys pad to the same bit sequence. The answer is to pad with a sequence
that always differs from itself when not exactly aligned (so not all 0s or all 1s
or any other purely repeating sequence). Working within that constraint,
the chosen key padding is a 0x00 byte followed by as many 0xFF bytes as needed.
The 0x00 ensures that NUL-free text keys sort in the usual order in the tree,
while the 0xFFs that follow ensure that keys of other lengths
(even keys ending in 0x00 or 0xFF) will not have the same padding at the same
positions.

The previous Prove and Verify signatures were:

	Prove(key Key) (proof Proof, err error)
	Verify(snap Snapshot, key Key, proof Proof) (val Val, ok bool, err error)

Now they are:

	Prove(key Key) (val Val, ok bool, proof Proof, err error)
	Verify(snap Snapshot, key Key, val Val, ok bool, proof Proof) error

The invariant maintained is that Verify is passed the snapshot
plus all the results of Prove. The difference is that now the val, ok
are returned by Prove instead of Verify. Of course, they should
not be trusted until Prove has succeeded.

This commit also adds VerifyPresent and VerifyNotPresent helpers
wrapping Verify, which can improve clarity at some call sites.

This commit also adds test vectors for Verify in testdata/verify.txt,
for easier use by other implementations.
@FiloSottile
FiloSottile merged commit e0a6396 into FiloSottile:main Jul 8, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants