<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE rfc [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">
]>
<?xml-stylesheet type="text/xsl" href="rfc2629.xslt" ?>
<!-- generated by https://github.com/cabo/kramdown-rfc version 1.7.19 (Ruby 3.0.2) -->
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" ipr="trust200902" docName="draft-bryce-cose-merkle-mountain-range-proofs-01" category="exp" submissionType="IETF" tocInclude="true" sortRefs="true" symRefs="true" version="3">
  <!-- xml2rfc v2v3 conversion 3.23.2 -->
  <front>
    <title abbrev="MMRIVER">Merkle Mountain Range for Immediately Verifiable and Replicable Commitments</title>
    <seriesInfo name="Internet-Draft" value="draft-bryce-cose-merkle-mountain-range-proofs-01"/>
    <author fullname="Robin Bryce">
      <organization>DataTrails</organization>
      <address>
        <email>robinbryce@gmail.com</email>
      </address>
    </author>
    <date year="2024" month="November" day="22"/>
    <area>Security</area>
    <workgroup>COSE</workgroup>
    <keyword>Internet-Draft</keyword>
    <abstract>
      <?line 26?>

<t>This specification describes the COSE encoding of proofs for post-order traversal binary Merkle trees, also known as history trees and Merkle mountain ranges.
Proving and verifying are defined in terms of the cryptographic asynchronous accumulator described by <eref target="https://eprint.iacr.org/2015/718.pdf">ReyzinYakoubov</eref>.
The technical advantages of post-order traversal binary Merkle trees are discussed in <eref target="https://static.usenix.org/event/sec09/tech/full_papers/crosby.pdf">CrosbyWallachStorage</eref> and <eref target="https://research.swtch.com/tlog#appendix_a">PostOrderTlog</eref>.</t>
    </abstract>
    <note removeInRFC="true">
      <name>Discussion Venues</name>
      <t>Discussion of this document takes place on the
    CBOR Object Signing and Encryption Working Group mailing list (cose@ietf.org),
    which is archived at <eref target="https://mailarchive.ietf.org/arch/browse/cose/"/>.</t>
      <t>Source for this draft and an issue tracker can be found at
    <eref target="https://github.com/datatrails/draft-bryce-cose-merkle-mountain-range-proofs"/>.</t>
    </note>
  </front>
  <middle>
    <?line 32?>

<section anchor="introduction">
      <name>Introduction</name>
      <t>A post ordered binary merkle tree is, logically, the unique series of perfect binary merkle trees required to commit its leaves.</t>
      <t>Example,</t>
      <artwork><![CDATA[
   6
 2   5
0 1 3 4 7
]]></artwork>
      <t>This illustrates <tt>MMR(8)</tt>, which is comprised of two perfect trees rooted at 6 and 7.
7 is the root of a tree comprised of a single element.</t>
      <t>The peaks of the perfect trees form the accumulator.</t>
      <t>The storage of a tree maintained in this way is addressed as a linear array, and additions to the tree are always appends.</t>
    </section>
    <section anchor="conventions-and-definitions">
      <name>Conventions and Definitions</name>
      <t>The key words "<bcp14>MUST</bcp14>", "<bcp14>MUST NOT</bcp14>", "<bcp14>REQUIRED</bcp14>", "<bcp14>SHALL</bcp14>", "<bcp14>SHALL
NOT</bcp14>", "<bcp14>SHOULD</bcp14>", "<bcp14>SHOULD NOT</bcp14>", "<bcp14>RECOMMENDED</bcp14>", "<bcp14>NOT RECOMMENDED</bcp14>",
"<bcp14>MAY</bcp14>", and "<bcp14>OPTIONAL</bcp14>" in this document are to be interpreted as
described in BCP 14 <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when, they
appear in all capitals, as shown here.</t>
      <?line -18?>

<ul spacing="normal">
        <li>
          <t>A complete MMR(n) defines an mmr with n nodes where no equal height sibling trees exist.</t>
        </li>
        <li>
          <t><tt>i</tt> shall be the index of any node, including leaf nodes, in the MMR</t>
        </li>
        <li>
          <t>g shall be the zero based height of a node in the tree.</t>
        </li>
        <li>
          <t><tt>H(x)</tt> shall be the SHA-256 digest of any value x</t>
        </li>
        <li>
          <t><tt>||</tt> shall mean concatenation of raw byte representations of the referenced values.</t>
        </li>
      </ul>
      <t>In this specification, all numbers are unsigned 64 bit integers.
The maximum height of a single tree is 64 (which will have <tt>g=63</tt> for its peak).</t>
    </section>
    <section anchor="description-of-the-mmriver-verifiable-data-structure">
      <name>Description of the MMRIVER Verifiable Data Structure</name>
      <t>This documents extends the verifiable data structure registry of <xref target="I-D.draft-ietf-cose-merkle-tree-proofs"/> with the following value:</t>
      <table align="left" anchor="verifiable-data-structure-values">
        <name>Verifiable Data Structure Algorithms</name>
        <thead>
          <tr>
            <th align="left">Name</th>
            <th align="left">Value</th>
            <th align="left">Description</th>
            <th align="left">Reference</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td align="left">MMRIVER_SHA256</td>
            <td align="left">TBD_1 (requested assignment 3)</td>
            <td align="left">Linearly addressed, position committing, MMR implementations, such as the MMRIVER ledger</td>
            <td align="left">This document</td>
          </tr>
        </tbody>
      </table>
      <t>This document defines inclusion proofs for Merkle Mountain Range, Immediately Verifiable and Efficiently Replicable (MMRIVER) ledgers.
Verifiers <bcp14>MUST</bcp14> reject all other proof types</t>
    </section>
    <section anchor="inclusion-proof">
      <name>Inclusion Proof</name>
      <t>The CBOR representation of an inclusion proof is</t>
      <sourcecode type="cddl"><![CDATA[
inclusion-proof = bstr .cbor [

  ; zero based index of a tree node
  index: uint

  ; path proving the node's inclusion
  inclusion-path: [ + bstr ]
]
]]></sourcecode>
      <t>Note that the inclusion path for the index leads to a single permanent node in the tree.
This node will initially be a peak in the accumulator, as the tree grows it will eventually be "buried" by a new peak.</t>
      <section anchor="inclusionproofpath">
        <name>inclusion_proof_path</name>
        <t><tt>inclusion_proof_path(i, c)</tt> is used to produce the verification paths for inclusion proofs and consistency proofs.</t>
        <t>Given:</t>
        <ul spacing="normal">
          <li>
            <t><tt>c</tt> the index of the last node in any tree which contains <tt>i</tt>.</t>
          </li>
          <li>
            <t><tt>i</tt> the index of the mmr node whose verification path is required.</t>
          </li>
        </ul>
        <t>And the methods:</t>
        <ul spacing="normal">
          <li>
            <t><xref target="indexheight">index_height</xref> which obtains the zero based height <tt>g</tt> of any node.</t>
          </li>
        </ul>
        <t>And the constraints:</t>
        <ul spacing="normal">
          <li>
            <t><tt>i &lt;= c</tt></t>
          </li>
        </ul>
        <t>We define <tt>inclusion_proof_path</tt> as</t>
        <sourcecode type="python"><![CDATA[
  def inclusion_proof_path(i, c):

    path = []

    g = index_height(i)

    while True:

      # The sibling of i is at i +/- 2^(g+1)
      siblingoffset = (2 << g)

      # If the index after i is higher, it is the left parent,
      # and i is the right sibling
      if index_height(i+1) > g:

        # The witness to the right sibling is offset behind i
        isibling = i - siblingoffset + 1

        # The parent of a right sibling is stored immediately
        # after
        i += 1
      else:

        # The witness to a left sibling is offset ahead of i
        isibling = i + siblingoffset - 1

        # The parent of a left sibling is stored immediately after
        # its right sibling
        i += siblingoffset

      # When the computed sibling exceeds the range of MMR(C+1),
      # we have completed the path
      if isibling > c:
          return path

      path.append(isibling)

      # Set g to the height of the next item in the path.
      g += 1
]]></sourcecode>
      </section>
    </section>
    <section anchor="receipt-of-inclusion">
      <name>Receipt of Inclusion</name>
      <t>The cbor representation of an inclusion proof is:</t>
      <sourcecode type="cddl"><![CDATA[
protected-header-map = {
  &(alg: 1) => int
  &(vds: 395) => 2
  * cose-label => cose-value
}
]]></sourcecode>
      <ul spacing="normal">
        <li>
          <t>alg (label: 1): <bcp14>REQUIRED</bcp14>. Signature algorithm identifier. Value type: int.</t>
        </li>
        <li>
          <t>vds (label: 395): <bcp14>REQUIRED</bcp14>. verifiable data structure algorithm identifier. Value type: int.</t>
        </li>
      </ul>
      <t>The unprotected header for an inclusion proof signature is:</t>
      <sourcecode type="cddl"><![CDATA[
inclusion-proofs = [ + inclusion-proof ]

verifiable-proofs = {
  &(inclusion-proof: -1) => inclusion-proofs
}

unprotected-header-map = {
  &(vdp: 396) => verifiable-proofs
  * cose-label => cose-value
}
]]></sourcecode>
      <t>The payload of an MMRIVER inclusion proof signature is the tree peak committing to the nodes inclusion, or the node itself where the proof path is empty.
The algorithm <xref target="includedroot">included_root</xref> obtains this value.</t>
      <t>The payload <bcp14>MUST</bcp14> be detached.
Detaching the payload forces verifiers to recompute the root from the inclusion proof,
this protects against implementation errors where the signature is verified but the payload merkle root does not match the inclusion proof.</t>
      <section anchor="verifying-the-receipt-of-inclusion">
        <name>Verifying the Receipt of inclusion</name>
        <t>The inclusion proof and signature are verified in order.
First the verifiers applies the inclusion proof to a possible entry (set member) bytes.
The result is the merkle root implied by the inclusion proof path for the candidate value.
The COSE Sign1 payload <bcp14>MUST</bcp14> be set to this value.
Second the verifier checks the signature of the COSE Sign1.
If the resulting signature verifies, the Receipt has proved inclusion of the entry in the verifiable data structure.
If the resulting signature does not verify, the signature may have been tampered with.</t>
        <t>It is recommended that implementations return a single boolean result for Receipt verification operations, to reduce the chance of accepting a valid signature over an invalid inclusion proof.</t>
        <t>As the proof must be processed prior to signature verification the implementation <bcp14>SHOULD</bcp14> check the lengths of the proof paths are appropriate for the provided tree sizes.</t>
      </section>
      <section anchor="includedroot">
        <name>included_root</name>
        <t>The algorithm <tt>included_root</tt> calculates the accumulator peak for the provided proof and node value.</t>
        <t>Given:</t>
        <ul spacing="normal">
          <li>
            <t><tt>i</tt> is the index the <tt>nodeHash</tt> is to be shown at</t>
          </li>
          <li>
            <t><tt>nodehash</tt> the value whose inclusion is to be shown</t>
          </li>
          <li>
            <t><tt>proof</tt> is the path of sibling values committing i.</t>
          </li>
        </ul>
        <t>And the methods:</t>
        <ul spacing="normal">
          <li>
            <t><xref target="indexheight">index_height</xref> which obtains the zero based height <tt>g</tt> of any node.</t>
          </li>
          <li>
            <t><xref target="hashpospair64">hash_pospair64</xref> which applies <tt>H</tt> to the new node position and its children.</t>
          </li>
        </ul>
        <t>We define <tt>included_root</tt> as</t>
        <sourcecode type="python"><![CDATA[
  def included_root(i, nodehash, proof):

    root = nodehash

    g = index_height(i)

    for sibling in proof:

      # If the index after i is higher, it is the left parent,
      # and i is the right sibling

      if index_height(i + 1) > g:

        # The parent of a right sibling is stored immediately after

        i = i + 1

        # Set `root` to `H(i+1 || sibling || root)`
        root = hash_pospair64(i + 1, sibling, root)
      else:

        # The parent of a left sibling is stored immediately after
        # its right sibling.

        i = i + (2 << g)

        # Set `root` to `H(i+1 || root || sibling)`
        root = hash_pospair64(i + 1, root, sibling)

      # Set g to the height of the next item in the path.
      g = g + 1

    # If the path length was zero, the original nodehash is returned
    return root
]]></sourcecode>
      </section>
    </section>
    <section anchor="consistency-proof">
      <name>Consistency Proof</name>
      <t>A consistency proof shows that the accumulator, defined in <eref target="https://eprint.iacr.org/2015/718.pdf">ReyzinYakoubov</eref>,
for tree-size-1 is a prefix of the accumulator for tree-size-2.</t>
      <t>The signature is over the complete accumulator for tree-size-2 obtained using the proof and the, supplied, possibly empty, list of <tt>right-peaks</tt> which complete the accumulator for tree-size-2.</t>
      <t>The receipt of consistency is defined so that a chain of cumulative consistency proofs can be verified together.</t>
      <t>The cbor representation of a consistency proof is:</t>
      <sourcecode type="cddl"><![CDATA[
consistency-path = [ * bstr ]

consistency-proof =  bstr .cbor [

  ; previous tree size
  tree-size-1: uint

  ; latest tree size
  tree-size-2: uint

  ; the inclusion path from each accumulator peak in
  ; tree-size-1 to its new peak in tree-size-2.
  consistency-paths: [ + consistency-path ]

  ; the additional peaks that
  ; complete the accumulator for tree-size-2,
  ; when appended to those produced by the consistency paths
  right-peaks: [ *bstr ]
]
]]></sourcecode>
      <section anchor="consistencyproofpath">
        <name>consistency_proof_path</name>
        <t>Produces the verification paths for inclusion of the peaks of tree-size-1 under the peaks of tree-size-2.</t>
        <t>right-peaks are obtained by invoking <tt>peaks(tree-size-2 - 1)</tt>, and discarding length(proofs) from the left.</t>
        <t>Given:</t>
        <ul spacing="normal">
          <li>
            <t><tt>ifrom</tt> is the last index of tree-size-1</t>
          </li>
          <li>
            <t><tt>ito</tt> is the last index of tree-size-2</t>
          </li>
        </ul>
        <t>And the methods:</t>
        <ul spacing="normal">
          <li>
            <t><xref target="inclusionproofpath">inclusion_proof_path</xref></t>
          </li>
          <li>
            <t><xref target="peaks"/></t>
          </li>
        </ul>
        <t>And the constraints:</t>
        <ul spacing="normal">
          <li>
            <t><tt>ifrom &lt;= ito</tt></t>
          </li>
        </ul>
        <t>We define <tt>consistency_proof_paths</tt> as</t>
        <sourcecode type="python"><![CDATA[
  def consistency_proof_paths(ifrom, ito):

    proof = []

    for i in peaks(ifrom):
      proof.append(inclusion_proof_path(i, ito))

    return proof
]]></sourcecode>
      </section>
    </section>
    <section anchor="receipt-of-consistency">
      <name>Receipt of Consistency</name>
      <t>The cbor representation of an inclusion proof for MMRIVER is:</t>
      <sourcecode type="cddl"><![CDATA[
protected-header-map = {
  &(alg: 1) => int
  &(vds: 395) => 2
  * cose-label => cose-value
}
]]></sourcecode>
      <ul spacing="normal">
        <li>
          <t>alg (label: 1): <bcp14>REQUIRED</bcp14>. Signature algorithm identifier. Value type: int.</t>
        </li>
        <li>
          <t>vds (label: 395): <bcp14>REQUIRED</bcp14>. verifiable data structure algorithm identifier. Value type: int.</t>
        </li>
      </ul>
      <t>The unprotected header for an inclusion proof signature is:</t>
      <sourcecode type="cddl"><![CDATA[
consistency-proofs = [ + consistency-proof ]

verifiable-proofs = {
  &(consistency-proof: -2) => consistency-proof
}

unprotected-header-map = {
  &(vdp: 396) => verifiable-proofs
  * cose-label => cose-value
}
]]></sourcecode>
      <t>The payload <bcp14>MUST</bcp14> be detached.
Detaching the payload forces verifiers to recompute the roots from the consistency proofs.
This protects against implementation errors where the signature is verified but the payload is not genuinely produced by the included proof.</t>
      <section anchor="verifying-the-receipt-of-consistency">
        <name>Verifying the Receipt of consistency</name>
        <t>Verification accommodates verifying the result of a cumulative series of consistency proofs.</t>
        <t>Perform the following for each consistency-proof in the list, verifying the signature with the output of the last.</t>
        <ol spacing="normal" type="1"><li>
            <t>Initialize current proof as the first consistency-proof.</t>
          </li>
          <li>
            <t>Initialize accumulatorfrom to the peaks of tree-size-1 in the current proof.</t>
          </li>
          <li>
            <t>Initialize ifrom to tree-size-1 - 1 from the current proof.</t>
          </li>
          <li>
            <t>Initialize proofs to the consistency-paths from the current proof.</t>
          </li>
          <li>
            <t>Apply the algorithm <xref target="consistentroots">consistent_roots</xref></t>
          </li>
          <li>
            <t>Apply the peaks algorithm to obtain the accumulator for tree-size-2</t>
          </li>
          <li>
            <t>From the peaks for tres-size-2, discard from the left the number of roots returned by consistent_roots.</t>
          </li>
          <li>
            <t>Create the consistent accumulator by appending the remaining peaks to the consistent roots.</t>
          </li>
          <li>
            <t>If there are no remaining proofs, use the consistent accumulator as the detached payload and verify the signature of the COSE Sign1.</t>
          </li>
        </ol>
        <t>It is recommended that implementations return a single boolean result for Receipt verification operations, to reduce the chance of accepting a valid signature over an invalid consistency proof.</t>
        <t>As the proof must be processed prior to signature verification the implementation <bcp14>SHOULD</bcp14> check the lengths of the proof paths are appropriate for the provided tree sizes.</t>
        <section anchor="consistentroots">
          <name>consistent_roots</name>
          <t><tt>consistent_roots</tt> returns the descending height ordered list of elements from the accumulator for the consistent future state.</t>
          <t>Implementations <bcp14>MUST</bcp14> require that the number of peaks returned by <xref target="peaks"/><tt>(ifrom)</tt> equals the number of entries in <tt>accumulatorfrom</tt>.</t>
          <t>Given:</t>
          <ul spacing="normal">
            <li>
              <t><tt>ifrom</tt> the last index in the complete MMR from which consistency was proven.</t>
            </li>
            <li>
              <t><tt>accumulatorfrom</tt> the node values corresponding to the peaks of the accumulator for tree-size-1</t>
            </li>
            <li>
              <t><tt>proofs</tt> the inclusion proofs for each node in <tt>accumulatorfrom</tt> for tree-size-2</t>
            </li>
          </ul>
          <t>And the methods:</t>
          <ul spacing="normal">
            <li>
              <t><xref target="includedroot">included_root</xref></t>
            </li>
            <li>
              <t><xref target="peaks"/></t>
            </li>
          </ul>
          <t>We define <tt>consistent_roots</tt> as</t>
          <sourcecode type="python"><![CDATA[
  def consistent_roots(ifrom, accumulatorfrom, proofs):

    frompeaks = peaks(ifrom)

    # if length(frompeaks) != length(proofs) -> ERROR

    roots = []
    for i in range(len(accumulatorfrom)):
      root = included_root(
          frompeaks[i], accumulatorfrom[i], proofs[i])

      if roots and roots[-1] == root:
          continue
      roots.append(root)

    return roots
]]></sourcecode>
        </section>
      </section>
    </section>
    <section anchor="appending-a-leaf">
      <name>Appending a leaf</name>
      <t>An algorithm for appending to a tree maintained in post order layout is provided.
Implementation defined methods for interacting with storage are specified.</t>
      <section anchor="addleafhash">
        <name>add_leaf_hash</name>
        <t>When a new node is appended, if its height matches the height of its immediate predecessor, then the two equal height siblings <bcp14>MUST</bcp14> be merged.
Merging is defined as the append of a new node which takes the adjacent peaks as its left and right children.
This process <bcp14>MUST</bcp14> proceed until there are no more completable sub trees.</t>
        <t><tt>add_leaf_hash(f)</tt> adds the leaf hash value f to the tree.</t>
        <t>Given:</t>
        <ul spacing="normal">
          <li>
            <t><tt>f</tt> the leaf value resulting from <tt>H(x)</tt> for the caller defined leaf value <tt>x</tt></t>
          </li>
          <li>
            <t><tt>db</tt> an interface supporting the <xref target="append"/> and <xref target="get"/> implementation defined storage methods.</t>
          </li>
        </ul>
        <t>And the methods:</t>
        <ul spacing="normal">
          <li>
            <t><xref target="indexheight">index_height</xref></t>
          </li>
          <li>
            <t><xref target="hashpospair64"/></t>
          </li>
        </ul>
        <t>We define <tt>add_leaf_hash</tt> as</t>
        <sourcecode type="python"><![CDATA[
  def add_leaf_hash(db, f: bytes):

    # Set g to 0, the height of the leaf item f
    g = 0

    # Set i to the result of invoking Append(f)
    i = db.append(f)

    # If index_height(i) is greater than g (#looptarget)
    while index_height(i) > g:

      # Set ileft to the index of the left child of i,
      # which is i - 2^(g+1)

      ileft = i - (2 << g)

      # Set iright to the index of the the right child of i,
      # which is i - 1

      iright = i - 1

      # Set v to H(i + 1 || Get(ileft) || Get(iright))
      # Set i to the result of invoking Append(v)

      i = db.append(
        hash_pospair64(i+1, db.get(ileft), db.get(iright)))

      # Set g to the height of the new i, which is g + 1
      g += 1

    return i
]]></sourcecode>
      </section>
      <section anchor="implementation-defined-storage-methods">
        <name>Implementation defined storage methods</name>
        <t>The following methods are assumed to be available to the implementation.
Very minimal requirements are specified.</t>
        <t>Informally, the storage must be array like and have no gaps.</t>
        <section anchor="get">
          <name>Get</name>
          <t>Reads the value from the tree at the supplied index.</t>
          <t>The read <bcp14>MUST</bcp14> be consistent with any other calls to Append or Get within the same algorithm invocation.</t>
          <t>Get <bcp14>MAY</bcp14> fail for transient reasons.</t>
        </section>
        <section anchor="append">
          <name>Append</name>
          <t>Appends new node to storage and returns the index that will be occupied by the node provided to the next call to append.</t>
          <t>The implementation <bcp14>MUST</bcp14> guarantee that the results of Append are immediately available to Get calls in the same invocation of the algorithm.</t>
          <t>Append <bcp14>MUST</bcp14> return the node <tt>i</tt> identifying the node location which comes next.</t>
          <t>The implementation <bcp14>MAY</bcp14> defer commitment to underlying persistent storage.</t>
          <t>Append <bcp14>MAY</bcp14> fail for transient reasons.</t>
        </section>
      </section>
      <section anchor="node-values">
        <name>Node values</name>
        <t>Interior nodes in the <bcp14>MUST</bcp14> prefix the value provided to <tt>H(x)</tt> with <tt>pos</tt>.</t>
        <t>The value <tt>v</tt> for any interior node <bcp14>MUST</bcp14> be <tt>H(pos || Get(LEFT_CHILD) || Get(RIGHT_CHILD))</tt></t>
        <t>The algorithm for leaf addition is provided the result of <tt>H(x)</tt> directly.</t>
        <section anchor="hashpospair64">
          <name>hash_pospair64</name>
          <t>Returns <tt>H(pos || a || b)</tt>, which is the value for the node identified by index <tt>pos - 1</tt></t>
          <t>Editors note: How this draft accommodates hash alg agility is tbd.</t>
          <t>Given:</t>
          <ul spacing="normal">
            <li>
              <t><tt>pos</tt> the size of the MMR whose last node index is <tt>pos - 1</tt></t>
            </li>
            <li>
              <t><tt>a</tt> the first value to include in the hash after <tt>pos</tt></t>
            </li>
            <li>
              <t><tt>b</tt> the second value to include in the hash after <tt>pos</tt></t>
            </li>
          </ul>
          <t>And the constraints:</t>
          <ul spacing="normal">
            <li>
              <t><tt>pos &lt; 2^64</tt></t>
            </li>
            <li>
              <t><tt>a</tt> and <tt>b</tt> <bcp14>MUST</bcp14> be hashes produced by the appropriate hash alg.</t>
            </li>
          </ul>
          <t>We define <tt>hash_pospair64</tt> as</t>
          <sourcecode type="python"><![CDATA[
  def hash_pospair64(pos, a, b):

    # Note: Hash algorithm agility is tbd, this example uses SHA-256
    h = hashlib.sha256()

    # Take the big endian representation of pos
    h.update(pos.to_bytes(8, byteorder="big", signed=False))
    h.update(a)
    h.update(b)
    return h.digest()
]]></sourcecode>
        </section>
      </section>
    </section>
    <section anchor="essential-supporting-algorithms">
      <name>Essential supporting algorithms</name>
      <section anchor="indexheight">
        <name>index_height</name>
        <t><tt>index_height(i)</tt> returns the zero based height <tt>g</tt> of the node index <tt>i</tt></t>
        <t>Given:</t>
        <ul spacing="normal">
          <li>
            <t><tt>i</tt> the index of any mmr node.</t>
          </li>
        </ul>
        <t>We define <tt>index_height</tt> as</t>
        <sourcecode type="python"><![CDATA[
  def index_height(i) -> int:
    pos = i + 1
    while not all_ones(pos):
      pos = pos - most_sig_bit(pos) + 1

    return bit_length(pos) - 1
]]></sourcecode>
      </section>
      <section anchor="peaks">
        <name>peaks</name>
        <t><tt>peaks(i)</tt> returns the peak indices for <tt>MMR(i+1)</tt>, which is also its accumulator.</t>
        <t>Assumes MMR(i+1) is complete, implementations can check for this condition by
testing the height of i+1</t>
        <t>Given:</t>
        <ul spacing="normal">
          <li>
            <t><tt>i</tt> the index of any mmr node.</t>
          </li>
        </ul>
        <t>We define <tt>peaks</tt></t>
        <sourcecode type="python"><![CDATA[
  def peaks(i):
    peak = 0
    peaks = []
    s = i+1
    while s != 0:
      # find the highest peak size in the current MMR(s)
      highest_size = (1 << log2floor(s+1)) - 1
      peak = peak + highest_size
      peaks.append(peak-1)
      s -= highest_size

    return peaks
]]></sourcecode>
      </section>
    </section>
    <section anchor="security-considerations">
      <name>Security Considerations</name>
      <t>See the security considerations section of:</t>
      <ul spacing="normal">
        <li>
          <t><xref target="RFC9053"/></t>
        </li>
      </ul>
    </section>
    <section anchor="iana-considerations">
      <name>IANA Considerations</name>
      <t>Editors note: Hash agility is desired.
We can start with SHA-256.
Two of the referenced implementations use BLAKE2b-256,
We would like to add support for SHA3-256, SHA3-512, and possibly Keccak and Pedersen.</t>
      <section anchor="additions-to-existing-registries">
        <name>Additions to Existing Registries</name>
        <t>Editors note: todo registry requests</t>
      </section>
      <section anchor="new-registries">
        <name>New Registries</name>
      </section>
    </section>
  </middle>
  <back>
    <references anchor="sec-normative-references">
      <name>Normative References</name>
      <reference anchor="RFC9053">
        <front>
          <title>CBOR Object Signing and Encryption (COSE): Initial Algorithms</title>
          <author fullname="J. Schaad" initials="J." surname="Schaad"/>
          <date month="August" year="2022"/>
          <abstract>
            <t>Concise Binary Object Representation (CBOR) is a data format designed for small code size and small message size. There is a need to be able to define basic security services for this data format. This document defines a set of algorithms that can be used with the CBOR Object Signing and Encryption (COSE) protocol (RFC 9052).</t>
            <t>This document, along with RFC 9052, obsoletes RFC 8152.</t>
          </abstract>
        </front>
        <seriesInfo name="RFC" value="9053"/>
        <seriesInfo name="DOI" value="10.17487/RFC9053"/>
      </reference>
      <reference anchor="I-D.draft-ietf-cose-merkle-tree-proofs">
        <front>
          <title>COSE Receipts</title>
          <author fullname="Orie Steele" initials="O." surname="Steele">
            <organization>Transmute</organization>
          </author>
          <author fullname="Henk Birkholz" initials="H." surname="Birkholz">
            <organization>Fraunhofer SIT</organization>
          </author>
          <author fullname="Antoine Delignat-Lavaud" initials="A." surname="Delignat-Lavaud">
            <organization>Microsoft</organization>
          </author>
          <author fullname="Cedric Fournet" initials="C." surname="Fournet">
            <organization>Microsoft</organization>
          </author>
          <date day="17" month="October" year="2024"/>
          <abstract>
            <t>   COSE (CBOR Object Signing and Encryption) Receipts prove properties
   of a verifiable data structure to a verifier.  Verifiable data
   structures and associated proof types enable security properties,
   such as minimal disclosure, transparency and non-equivocation.
   Transparency helps maintain trust over time, and has been applied to
   certificates, end to end encrypted messaging systems, and supply
   chain security.  This specification enables concise transparency
   oriented systems, by building on CBOR (Concise Binary Object
   Representation) and COSE.  The extensibility of the approach is
   demonstrated by providing CBOR encodings for RFC9162.

            </t>
          </abstract>
        </front>
        <seriesInfo name="Internet-Draft" value="draft-ietf-cose-merkle-tree-proofs-07"/>
      </reference>
      <reference anchor="RFC2119">
        <front>
          <title>Key words for use in RFCs to Indicate Requirement Levels</title>
          <author fullname="S. Bradner" initials="S." surname="Bradner"/>
          <date month="March" year="1997"/>
          <abstract>
            <t>In many standards track documents several words are used to signify the requirements in the specification. These words are often capitalized. This document defines these words as they should be interpreted in IETF documents. This document specifies an Internet Best Current Practices for the Internet Community, and requests discussion and suggestions for improvements.</t>
          </abstract>
        </front>
        <seriesInfo name="BCP" value="14"/>
        <seriesInfo name="RFC" value="2119"/>
        <seriesInfo name="DOI" value="10.17487/RFC2119"/>
      </reference>
      <reference anchor="RFC8174">
        <front>
          <title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title>
          <author fullname="B. Leiba" initials="B." surname="Leiba"/>
          <date month="May" year="2017"/>
          <abstract>
            <t>RFC 2119 specifies common key words that may be used in protocol specifications. This document aims to reduce the ambiguity by clarifying that only UPPERCASE usage of the key words have the defined special meanings.</t>
          </abstract>
        </front>
        <seriesInfo name="BCP" value="14"/>
        <seriesInfo name="RFC" value="8174"/>
        <seriesInfo name="DOI" value="10.17487/RFC8174"/>
      </reference>
    </references>
    <?line 632?>

<section anchor="references">
      <name>References</name>
      <section anchor="informative-references">
        <name>Informative References</name>
        <ul spacing="normal">
          <li>
            <t><eref target="https://eprint.iacr.org/2015/718.pdf">ReyzinYakoubov</eref></t>
          </li>
          <li>
            <t><eref target="https://static.usenix.org/event/sec09/tech/full_papers/crosby.pdf">CrosbyWallach</eref></t>
          </li>
          <li>
            <t><eref target="https://static.usenix.org/event/sec09/tech/full_papers/crosby.pdf">CrosbyWallachStorage</eref> 3.3 Storing the log on secondary storage</t>
          </li>
          <li>
            <t><eref target="https://research.swtch.com/tlog#appendix_a">PostOrderTlog</eref></t>
          </li>
          <li>
            <t><eref target="https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2016-May/012715.html">PeterTodd</eref></t>
          </li>
          <li>
            <t><eref target="https://www-cs-faculty.stanford.edu/~knuth/taocp.html">KnuthTBT</eref> 2.3.1 Traversing Binary Trees</t>
          </li>
          <li>
            <t><eref target="https://eprint.iacr.org/2021/038.pdf">BNT</eref></t>
          </li>
        </ul>
      </section>
    </section>
    <section anchor="assumed-bit-primitives">
      <name>Assumed bit primitives</name>
      <section anchor="log2floor">
        <name>log2floor</name>
        <t>Returns the floor of log base 2 x</t>
        <sourcecode type="python"><![CDATA[
  def log2floor(x):
    return x.bit_length() - 1
]]></sourcecode>
      </section>
      <section anchor="mostsigbit">
        <name>most_sig_bit</name>
        <t>Returns the mask for the the most significant bit in pos</t>
        <sourcecode type="python"><![CDATA[
  def most_sig_bit(pos) -> int:
    return 1 << (pos.bit_length() - 1)
]]></sourcecode>
        <t>The following primitives are assumed for working with bits as they commonly have library or hardware support.</t>
      </section>
      <section anchor="bitlength">
        <name>bit_length</name>
        <t>The minimum number of bits to represent pos. b011 would be 2, b010 would be 2, and b001 would be 1.</t>
        <sourcecode type="python"><![CDATA[
  def bit_length(pos):
    return pos.bit_length()
]]></sourcecode>
      </section>
      <section anchor="allones">
        <name>all_ones</name>
        <t>Tests if all bits, from the most significant that is set, are 1, b0111 would be true, b0101 would be false.</t>
        <sourcecode type="python"><![CDATA[
  def all_ones(pos) -> bool:
    msb = most_sig_bit(pos)
    mask = (1 << (msb + 1)) - 1
    return pos == mask
]]></sourcecode>
      </section>
      <section anchor="onescount">
        <name>ones_count</name>
        <t>Count of set bits.
For example <tt>ones_count(b101)</tt> is 2</t>
      </section>
      <section anchor="trailingzeros">
        <name>trailing_zeros</name>
        <sourcecode type="python"><![CDATA[
  (v & -v).bit_length() - 1
]]></sourcecode>
      </section>
    </section>
    <section anchor="implementation-status">
      <name>Implementation Status</name>
      <t>Note to RFC Editor: Please remove this section as well as references to BCP205 before AUTH48.</t>
      <t>This section records the status of known implementations of the protocol defined by this specification at the time of posting of this Internet-Draft, and is based on a proposal described in BCP205.
The description of implementations in this section is intended to assist the IETF in its decision processes in progressing drafts to RFCs.
Please note that the listing of any individual implementation here does not imply endorsement by the IETF.
Furthermore, no effort has been spent to verify the information presented here that was supplied by IETF contributors.
This is not intended as, and must not be construed to be, a catalog of available implementations or their features.
Readers are advised to note that other implementations may exist.</t>
      <t>According to BCP205,
"this will allow reviewers and working groups to assign due consideration to documents that have the benefit of running code, which may serve as evidence of valuable experimentation and feedback that have made the implemented protocols more mature.
It is up to the individual working groups to use this information as they see fit".</t>
      <section anchor="implementers">
        <name>Implementers</name>
        <section anchor="datatrails">
          <name>DataTrails</name>
          <t>An open-source implementation was initiated and is maintained by Data Trails Inc. - DataTrails.</t>
          <t>Uses SHA-256 as the hash alg</t>
          <section anchor="implementation-name">
            <name>Implementation Name</name>
            <t>An application demonstrating the concepts is available at <eref target="https://app.datatrails.ai/">https://app.datatrails.ai/</eref>.</t>
          </section>
          <section anchor="implementation-url">
            <name>Implementation URL</name>
            <t>An open-source implementation is available at:</t>
            <ul spacing="normal">
              <li>
                <t>https://github.com/datatrails/go-datatrails-merklelog</t>
              </li>
            </ul>
          </section>
          <section anchor="maturity">
            <name>Maturity</name>
            <t>Used in production.
SEMVER unstable (no backwards compat declared yet)</t>
          </section>
        </section>
        <section anchor="robin-bryce-1">
          <name>Robin Bryce (1)</name>
          <section anchor="implementation-url-1">
            <name>Implementation URL</name>
            <t>A minimal reference implementation of this draft.
Used to generate the test vectors in this draft, is available at:</t>
            <ul spacing="normal">
              <li>
                <t>https://github.com/robinbryce/draft-bryce-cose-merkle-mountain-range-proofs/blob/main/algorithms.py</t>
              </li>
            </ul>
          </section>
          <section anchor="maturity-1">
            <name>Maturity</name>
            <t>Reference only</t>
          </section>
        </section>
        <section anchor="robin-bryce-2">
          <name>Robin Bryce (2)</name>
          <section anchor="implementation-url-2">
            <name>Implementation URL</name>
            <t>A minimal tiled log implementation</t>
            <ul spacing="normal">
              <li>
                <t>https://github.com/robinbryce/mmriver-tiles-ts</t>
              </li>
            </ul>
          </section>
          <section anchor="maturity-2">
            <name>Maturity</name>
            <t>Prototype</t>
          </section>
        </section>
        <section anchor="mimblewimble">
          <name>Mimblewimble</name>
          <t>Is specifically committing to positions as we describe, but is committing zero based indices,
and uses BLAKE2B as the HASH-ALG.
Accounting for those differences, their commitment trees would be compatible with this draft.</t>
          <section anchor="implementation-url-3">
            <name>Implementation URL</name>
            <t>An implementation is available here:</t>
            <ul spacing="normal">
              <li>
                <t>https://github.com/mimblewimble/grin/blob/master/doc/mmr.md (Grin is a rust implementation of the mimblewimble protocol)</t>
              </li>
              <li>
                <t>https://github.com/BeamMW/beam/blob/master/core/merkle.cpp (Beam is a C++ implementation of the mimblewimble protocol)</t>
              </li>
            </ul>
          </section>
        </section>
        <section anchor="herodotus">
          <name> Herodotus</name>
          <section anchor="implementation-url-4">
            <name>Implementation URL</name>
            <t>https://github.com/HerodotusDev/rust-accumulators</t>
            <t>Production, supports keccak, posiedon &amp; pedersen hash algs</t>
            <t>Editors note: test vectors, based on a SHA256 instantiation, are currently provided in a separate document.
These should inlined if the draft is accepted: https://github.com/robinbryce/draft-bryce-cose-merkle-mountain-range-proofs/blob/main/test-vectors.md</t>
          </section>
        </section>
      </section>
    </section>
    <section numbered="false" anchor="acknowledgments">
      <name>Acknowledgments</name>
    </section>
  </back>
  <!-- ##markdown-source:
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

-->

</rfc>
