Skip to content

Commit a25c85e

Browse files
authored
Merge pull request #125 from davidben/nodes-english
Program in English as well as Python
2 parents 1739752 + f54e299 commit a25c85e

1 file changed

Lines changed: 36 additions & 13 deletions

File tree

draft-davidben-tls-merkle-tree-certs.md

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -430,14 +430,44 @@ Given a Merkle Tree over `n` elements, a subtree defined by `[start, end)`, a co
430430

431431
## Arbitrary Intervals
432432

433-
Not all `[start, end)` intervals of a Merkle tree are valid subtrees. This section describes how, for any `start < end`, to determine up to two subtrees that efficiently cover the interval. The subtrees are determined by the following Python procedure:
433+
Not all `[start, end)` intervals of a Merkle tree are valid subtrees. This section describes how, for any `start < end`, to determine up to two subtrees that efficiently cover the interval. The subtrees are determined by the following procedure:
434+
435+
1. If `end - start` is one, return a single subtree, `[start, end)`.
436+
437+
2. Otherwise, run the following to return a pair of subtrees:
438+
439+
1. Let `last` be `end - 1`, the last index in `[start, end)`.
440+
441+
2. Let `split` be the bit index of the most significant bit where `start` and `last` differ. Bits are numbered from the least significant bit, starting at zero. `split` is the height at which `start` and `last`'s paths in the tree diverge.
442+
443+
3. Let `mid` be `last` with the least significant `split` bits set to zero. `mid` is the leftmost leaf node in the above divergence point's right branch.
444+
445+
4. Within the least significant `split` bits of `left`, let `b` be the bit index of the most significant bit with value zero, if any:
446+
447+
1. If there is such a bit, let `left_split` be `b + 1`.
448+
2. Otherwise, let `left_split` be zero.
449+
450+
`left_split` is the height of the lowest common ancestor of the nodes in `[start, mid)`.
451+
452+
5. Let `left_start` be `start` with the least significant `left_split` bits set to zero. `left_start` is the above lowest common ancestor's leftmost leaf node.
453+
454+
6. Return the subtrees `[left_start, mid)` and `[mid, end)`.
455+
456+
When the procedure returns a single subtree, the subtree is `[start, start+1)`. When it returns two subtrees, `left` and `right`, the subtrees satisfy the following properties:
457+
458+
* `left.end = right.start`. That is, the two subtrees cover adjacent intervals.
459+
* `left.start <= start` and `end = right.end`. That is, the two subtrees together cover the entire target interval, possibly with some extra entries before `start` left, but not after `end`.
460+
* `left.end - left.start < 2 * (end - start)` and `right.end - right.start <= end - start`. That is, the two subtrees efficiently cover the interval.
461+
* `left` is full, while `right` may be partial.
462+
463+
The following Python code implements this procedure:
434464

435465
~~~python
436466
def find_subtrees(start, end):
437467
""" Returns a list of one or two subtrees that efficiently
438468
cover [start, end). """
439469
assert start < end
440-
if end - start < 2:
470+
if end - start == 1:
441471
return [(start, end),]
442472
last = end - 1
443473
# Find where start and last's tree paths diverge. The two
@@ -448,19 +478,10 @@ def find_subtrees(start, end):
448478
# Maximize the left endpoint. This is just before start's
449479
# path leaves the right edge of its new subtree.
450480
left_split = (~start & mask).bit_length()
451-
left = start & ~((1 << left_split) - 1)
452-
return [(left, mid), (mid, end)]
481+
left_start = start & ~((1 << left_split) - 1)
482+
return [(left_start, mid), (mid, end)]
453483
~~~
454484

455-
[[TODO: Write this up in prose too.]]
456-
457-
When the procedure returns a single subtree, the subtree is `[start, end)`. When it returns two subtrees, `left` and `right`, the subtrees satisfy the following properties:
458-
459-
1. `left.end = right.start`. That is, the two subtrees cover adjacent intervals.
460-
2. `left.start <= start` and `end = right.end`. That is, the two subtrees together cover the entire target interval, possibly with some extra entries before `start` left, but not after `end`.
461-
3. `left.end - left.start < 2 * (end - start)` and `right.end - right.start <= end - start`. That is, the two subtrees efficiently cover the interval.
462-
4. `left` is full, while `right` may be partial.
463-
464485
{{fig-subtree-example}} shows the subtrees which cover `[5, 13)` in a Merkle Tree of 13 elements. The two subtrees selected are `[4, 8)` and `[8, 13)`. Note that the subtrees cover a slightly larger interval than `[5, 13)`.
465486

466487
<!-- Ideally we'd use the Unicode box-drawing characters for the text form, but aasvg doesn't support them: https://github.com/martinthomson/aasvg/issues/9 -->
@@ -1436,3 +1457,5 @@ In draft-04, there is no fast issuance mode. In draft-05, frequent, non-landmark
14361457
- Removed now unnecessary placeholder text
14371458

14381459
- First draft at IANA registration and ASN.1 module
1460+
1461+
- Added a prose version of the procedure to select subtrees

0 commit comments

Comments
 (0)