Balanced MIP-8 page commitments

This file defines a variant of the MIP-8 page commitment model from commitment.v. The public input, slot normalization, pair leaves, bitmap seal, and collision statement are the same. The only algorithmic change is the merge schedule for nonempty pair leaves.
In commitment.v, the compact value tree is the induced subtree of the 64-pair complete page tree: empty complete-tree regions disappear, and the surviving unary stretches do not create merge hashes. Here, after the same pair-leaf extraction step, we forget the empty regions for scheduling and recursively split the ordered active leaves at the median. Every internal node therefore combines two nonempty sublists whose lengths differ by at most one along each split.
For example, with active pair indices 0, 1, 8, and 32:
induced schedule from commitment.v:

                 Node
                /    \
            Node      Leaf 32
           /    \
       Node      Leaf 8
      /    \
  Leaf 0  Leaf 1

balanced schedule in this file:

              Node
             /    \
         Node      Node
        /   \      /   \
  Leaf 0 Leaf 1 Leaf 8 Leaf 32
With an odd number of active leaves, the left side gets length / 2 leaves and the right side gets the rest:
active pair indices [0], [8], [32]:

              Node
             /    \
        Leaf 0     Node
                  /    \
             Leaf 8   Leaf 32
As in commitment.v, an empty page is sealed directly with the 128-bit slot bitmap. A nonempty page hashes each active pair leaf, hashes the balanced merge tree, and seals the tree root together with the same bitmap.
The correctness property is the same binding statement, specialized to the balanced trace. If two normalized slot lists differ but their balanced roots are equal, then the two traced executions contain an aligned hash collision. The only difference is what "aligned" means for internal merge nodes: merge locations are positions in the balanced median-split tree, while leaf locations remain the original pair indices and the seal location is unchanged.
Extract the nonempty pair leaves together with their original 0-based pair positions. The positions are not used to choose the balanced merge shape; they are retained so leaf hash calls can still be aligned with the original page geometry.
Fixpoint pair_entries_from
    (start : nat) (pairs : list (option pair_leaf))
    : list (nat × pair_leaf) :=
  match pairs with
  | [][]
  | Some value :: rest
      (start, value) :: pair_entries_from (S start) rest
  | None :: rest
      pair_entries_from (S start) rest
  end.

Definition active_pair_entries (slots : slot_values)
    : list (nat × pair_leaf) :=
  pair_entries_from 0 (pair_options slots).

Split by median. For odd lengths, the right side has one more element.
Definition median_split {A : Type} (values : list A) : nat :=
  Nat.div2 (length values).

Build a balanced located tree from the ordered active pair entries. fuel is just structural recursion fuel; the exported builder below supplies length entries. Internal node locations are balanced-tree coordinates: depth counts median-split levels from the root, and index is the horizontal index at that depth.
Fixpoint balanced_located_tree_from_entries_fuel
    (fuel depth index : nat) (entries : list (nat × pair_leaf))
    : option located_value_tree :=
  match fuel with
  | O
      match entries with
      | [(pair_index, value)]Some (LocatedTreeLeaf pair_index value)
      | _None
      end
  | S fuel'
      match entries with
      | []None
      | [(pair_index, value)]Some (LocatedTreeLeaf pair_index value)
      | _
          let split := median_split entries in
          match
            balanced_located_tree_from_entries_fuel
              fuel' (S depth) (2 × index) (firstn split entries),
            balanced_located_tree_from_entries_fuel
              fuel' (S depth) (2 × index + 1) (skipn split entries)
          with
          | Some lhs, Some rhs
              Some (LocatedTreeNode depth index lhs rhs)
          | _, _None
          end
      end
  end.

Definition balanced_located_tree_from_entries
    (entries : list (nat × pair_leaf)) : option located_value_tree :=
  balanced_located_tree_from_entries_fuel (length entries) 0 0 entries.

Definition balanced_located_tree_from_slots
    (slots : slot_values) : option located_value_tree :=
  balanced_located_tree_from_entries (active_pair_entries slots).

Definition balanced_value_tree_from_slots
    (slots : slot_values) : option value_tree :=
  option_map erase_located_tree (balanced_located_tree_from_slots slots).

Section BalancedTreeDemo.
  Variables (v0 v1 v8 v32 v32' : slot_word).

  Let zero : slot_word := bytes32_of_N 0.
  Let singleton_pair_slot (value : slot_word) : slot_values :=
    [Some value; None].

  Let four_leaf_slots : slot_values :=
    singleton_pair_slot v0 ++
    singleton_pair_slot v1 ++
    repeat None 12 ++
    singleton_pair_slot v8 ++
    repeat None 46 ++
    [Some v32; Some v32'].
  Let pair0 : pair_leaf := (v0, zero).
  Let pair1 : pair_leaf := (v1, zero).
  Let pair8 : pair_leaf := (v8, zero).
  Let pair32 : pair_leaf := (v32, v32').
  Let four_leaf_tree : located_value_tree :=
    LocatedTreeNode 0 0
      (LocatedTreeNode 1 0
        (LocatedTreeLeaf 0 pair0)
        (LocatedTreeLeaf 1 pair1))
      (LocatedTreeNode 1 1
        (LocatedTreeLeaf 8 pair8)
        (LocatedTreeLeaf 32 pair32)).

The active leaves are pair indices 0, 1, 8, and 32. Unlike the induced tree in commitment.v, the balanced schedule merges (0,1) and (8,32) in parallel before the final root merge.
active leaves:
  pair 0  = (v0, 0)
  pair 1  = (v1, 0)
  pair 8  = (v8, 0)
  pair 32 = (v32, v32')

balanced located tree:

                    LocatedTreeNode 0 0
                   /                   \
       LocatedTreeNode 1 0       LocatedTreeNode 1 1
          /             \           /              \
 LocatedTreeLeaf   LocatedTreeLeaf LocatedTreeLeaf LocatedTreeLeaf
    0 (v0, 0)       1 (v1, 0)      8 (v8, 0)      32 (v32, v32')
The example lemma balanced_located_tree_four_leaf_demo proves that the algorithm returns exactly this balanced located tree.
  Example balanced_located_tree_four_leaf_demo :
    balanced_located_tree_from_slots four_leaf_slots = Some four_leaf_tree.
  Proof.
    reflexivity.
  Qed.

  Let three_leaf_slots : slot_values :=
    singleton_pair_slot v0 ++
    repeat None 14 ++
    singleton_pair_slot v8 ++
    repeat None 46 ++
    [Some v32; Some v32'].
  Let three_leaf_tree : located_value_tree :=
    LocatedTreeNode 0 0
      (LocatedTreeLeaf 0 pair0)
      (LocatedTreeNode 1 1
        (LocatedTreeLeaf 8 pair8)
        (LocatedTreeLeaf 32 pair32)).

With three leaves, the median split puts one leaf on the left and two on the right.
active leaves:
  pair 0  = (v0, 0)
  pair 8  = (v8, 0)
  pair 32 = (v32, v32')

balanced located tree:

                    LocatedTreeNode 0 0
                   /                   \
          LocatedTreeLeaf         LocatedTreeNode 1 1
             0 (v0, 0)              /              \
                            LocatedTreeLeaf  LocatedTreeLeaf
                               8 (v8, 0)     32 (v32, v32')
The example lemma balanced_located_tree_three_leaf_demo proves that the odd-size median split is reflected in the returned tree.
Final seal step. Empty pages are sealed by bitmap alone; nonempty pages seal the same bitmap with the balanced merge-tree root.
Definition balanced_root (slots : slot_values) : digest :=
  match balanced_located_tree_from_slots slots with
  | Noneseal_empty (bitmap_to_bytes16 (slot_bitmap slots))
  | Some tree
      seal_nonempty
        (bitmap_to_bytes16 (slot_bitmap slots))
        (eval_located_tree tree)
  end.

Trace-producing version used by the binding theorem.
Definition balanced_root_with_trace (slots : slot_values) : root_trace :=
  match balanced_located_tree_from_slots slots with
  | None
      {|
        traced_root :=
          seal_empty (bitmap_to_bytes16 (slot_bitmap slots));
        traced_calls :=
          [mk_located_call
             LocSeal
             (InputSealEmpty (bitmap_to_bytes16 (slot_bitmap slots)))]
      |}
  | Some tree
      let tree_root := eval_located_tree tree in
      {|
        traced_root :=
          seal_nonempty (bitmap_to_bytes16 (slot_bitmap slots)) tree_root;
        traced_calls :=
          tree_located_calls tree ++
          [mk_located_call
             LocSeal
             (InputSealNonempty
                (bitmap_to_bytes16 (slot_bitmap slots))
                tree_root)]
      |}
  end.

End BalancedAlgorithm.

Correctness

The proof follows the same strategy as commitment.v. If the seal inputs differ, root equality exposes a seal collision. If the seal inputs agree, the bitmap agrees, so both executions have the same active pair indices and hence the same balanced tree shape. The proof then compares corresponding leaves and merge nodes at their balanced locations.
Section BalancedCorrectness.

Lemma Nat_div2_le n :
  Nat.div2 n n.

Lemma pair_entries_from_values start pairs :
  map snd (pair_entries_from start pairs) =
  pair_option_values pairs.

Lemma pair_entries_from_indices_same start pairs pairs' :
  pair_option_bitmap pairs = pair_option_bitmap pairs'
  map fst (pair_entries_from start pairs) =
  map fst (pair_entries_from start pairs').
Lemma active_pair_entries_values slots :
  map snd (active_pair_entries slots) =
  active_pair_values slots.

Lemma active_pair_entries_indices_same slots slots' :
  slot_bitmap slots = slot_bitmap slots'
  map fst (active_pair_entries slots) =
  map fst (active_pair_entries slots').

Lemma balanced_located_tree_from_entries_values_fuel
    fuel depth index entries tree :
  balanced_located_tree_from_entries_fuel
    fuel depth index entries = Some tree
  located_tree_values tree = map snd entries.
Lemma balanced_located_tree_from_entries_values entries tree :
  balanced_located_tree_from_entries entries = Some tree
  located_tree_values tree = map snd entries.

Lemma balanced_located_tree_from_entries_some_fuel fuel depth index entries :
  length entries fuel
  entries []
   tree,
    balanced_located_tree_from_entries_fuel
      fuel depth index entries = Some tree.

Lemma balanced_located_tree_from_entries_some entries :
  entries []
   tree, balanced_located_tree_from_entries entries = Some tree.

Lemma balanced_located_tree_from_entries_same_shape_fuel
    fuel depth index entries entries' tree tree' :
  map fst entries = map fst entries'
  balanced_located_tree_from_entries_fuel
    fuel depth index entries = Some tree
  balanced_located_tree_from_entries_fuel
    fuel depth index entries' = Some tree'
  same_located_tree_shape tree tree'.

Lemma balanced_located_tree_from_entries_same_shape entries entries' tree tree' :
  map fst entries = map fst entries'
  balanced_located_tree_from_entries entries = Some tree
  balanced_located_tree_from_entries entries' = Some tree'
  same_located_tree_shape tree tree'.

Lemma balanced_located_tree_from_slots_values slots tree :
  balanced_located_tree_from_slots slots = Some tree
  located_tree_values tree = active_pair_values slots.

Lemma balanced_located_tree_from_slots_empty_values slots :
  balanced_located_tree_from_slots slots = None
  active_pair_values slots = [].

Lemma balanced_located_tree_from_slots_same_shape
    slots slots' tree tree' :
  slot_bitmap slots = slot_bitmap slots'
  balanced_located_tree_from_slots slots = Some tree
  balanced_located_tree_from_slots slots' = Some tree'
  same_located_tree_shape tree tree'.
Theorem balanced_root_with_trace_root slots :
  (balanced_root_with_trace slots).(traced_root) = balanced_root slots.

Theorem Balanced_Root_injective_no_collision slots slots' :
  no_aligned_collisions
    (balanced_root_with_trace slots)
    (balanced_root_with_trace slots')
  balanced_root slots = balanced_root slots'
  normalize_slots slots = normalize_slots slots'.
Theorem Balanced_Root_binding_break_extracts_aligned_collision slots slots' :
  (balanced_root_with_trace slots).(traced_root) =
  (balanced_root_with_trace slots').(traced_root)
  normalize_slots slots normalize_slots slots'
  exists_aligned_collision
    (balanced_root_with_trace slots)
    (balanced_root_with_trace slots').

Theorem Balanced_Root_distinct_no_collision slots slots' :
  no_aligned_collisions
    (balanced_root_with_trace slots)
    (balanced_root_with_trace slots')
  normalize_slots slots normalize_slots slots'
  balanced_root slots balanced_root slots'.

End BalancedCorrectness.

This page has been generated by coqdoc