123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2022 DaiLambda, Inc. <contact@dailambda.jp> *)(* *)(* Permission is hereby granted, free of charge, to any person obtaining a *)(* copy of this software and associated documentation files (the "Software"),*)(* to deal in the Software without restriction, including without limitation *)(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *)(* and/or sell copies of the Software, and to permit persons to whom the *)(* Software is furnished to do so, subject to the following conditions: *)(* *)(* The above copyright notice and this permission notice shall be included *)(* in all copies or substantial portions of the Software. *)(* *)(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*)(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *)(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *)(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*)(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *)(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *)(* DEALINGS IN THE SOFTWARE. *)(* *)(*****************************************************************************)(* Using vanilla Data_encoding. Easier to parse but less efficient *)moduleMake_V1(Conf:sigvalentries:intend)=structopenTezos_context_sigs.Context.Proof_typesopenData_encodingletentries=Conf.entries(* The code only supports branching factors 2 and 32 *)let()=assert(entries=2||entries=32)letvalue_encoding:valueData_encoding.t=bytesletlength_field=req"length"(convInt64.of_intInt64.to_intint64)letstep_encoding:stepData_encoding.t=Bounded.string'Hex255lethash_encoding=Context_hash.encodingletindex_encoding=uint8(* This works for entries <= 32 but specialized for entries = 32 *)letsegment_encoding_32=(* The segment int is in 5bits. *)(* Format
* Required bytes = (n * 5 + 8) / 8
* Maximum length allowed: 406
* 10* is filled at the end of the bytes
ex: Encoding of [aaaaa; bbbbb; ccccc; ddddd; eeeee; ..; zzzzz]
|76543210|76543210|7654.. .. |76543210|
|aaaaabbb|bbcccccd|ddde.. .. zzzzz100|
|76543210|76543210|7654.. .. 43210|76543210|
|aaaaabbb|bbcccccd|ddde.. .. yzzzz|z1000000|
|76543210|76543210|7654.. .. 543210|76543210|
|aaaaabbb|bbcccccd|ddde.. .. yzzzzz|10000000|
*)letencodeis=letbuf=Buffer.create0inletpushc=Buffer.add_charbuf@@Char.chrcinletclosecbit=push(clor(1lsl(7-bit)))inletwritecbiti=ifbit<3then(clor(ilsl(3-bit)),bit+5)elseleti=ilsl(11-bit)inpush(clor(i/256));(iland255,bit-3)inletrecfcbit=function|[]->closecbit|i::is->letc,bit=writecbitiinfcbitisinf00is;Buffer.to_bytesbufinletdecodeb=letopenResult_syntaxinleterror=Error"invalid 5bit list"inlet*l=letsl=Bytes.lengthbinifsl=0thenerrorelseletc=Char.code@@Bytes.getb(sl-1)inlet*last_bit=ifc=0thenerrorelseletrecauxi=ifcland(1lsli)=0thenaux(i+1)elsei+1inOk(aux0)inletbits=(sl*8)-last_bitinifbitsmod5=0thenOk(bits/5)elseerrorinlets=Bytes.to_seqbinletheads=(* This assertion won't fail even with malformed input. *)matchs()with|Seq.Nil->assertfalse|Seq.Cons(c,s)->(Char.codec,s)inletrecreadcrembitls=ifl=0then[]elseletc,s,rembit=ifrembit>=5then(c,s,rembit)elseletc',s=headsin((c*256)+c',s,rembit+8)inletrembit=rembit-5inleti=clsrrembitinletc=cland((1lslrembit)-1)ini::readcrembit(l-1)sinOk(read00ls)inconv_with_guardencodedecode(Bounded.bytes255)(* This works only for entries = 2 *)letsegment_encoding_2=(* Format
* Required bytes = (n + 8) / 8
* Maximum length allowed: 2032
* 10* is filled at the end of the bytes
*)letencodeis=letbuf=Buffer.create0inletpushc=Buffer.add_charbuf@@Char.chrcinletclosecbit=push(clor(1lsl(7-bit)))inletwritecbiti=ifbit<7then(clor(ilsl(7-bit)),bit+1)elseleti=ilsl(15-bit)inpush(clor(i/256));(iland255,bit-7)inletrecfcbit=function|[]->closecbit|i::is->letc,bit=writecbitiinfcbitisinf00is;Buffer.to_bytesbufinletdecodeb=letopenResult_syntaxinleterror=Error"invalid binary list"inlet*l=letsl=Bytes.lengthbinifsl=0thenerrorelseletc=Char.code@@Bytes.getb(sl-1)inlet*last_bit=ifc=0thenerrorelseletrecauxi=ifcland(1lsli)=0thenaux(i+1)elsei+1inOk(aux0)inletbits=(sl*8)-last_bitinOkbitsinlets=Bytes.to_seqbinletheads=(* This assertion won't fail even with malformed input. *)matchs()with|Seq.Nil->assertfalse|Seq.Cons(c,s)->(Char.codec,s)inletrecreadcrembitls=ifl=0then[]elseletc,s,rembit=ifrembit>=1then(c,s,rembit)elseletc',s=headsin((c*256)+c',s,rembit+8)inletrembit=rembit-1inleti=clsrrembitinletc=cland((1lslrembit)-1)ini::readcrembit(l-1)sinOk(read00ls)inconv_with_guardencodedecode(Bounded.bytes255)letsegment_encoding=matchentrieswith|32->segment_encoding_32|2->segment_encoding_2|_->(* Unsupported *)assertfalseletinode_proofs_encoding_2a=conv_with_guard(function|[(0,x);(1,y)]->(Somex,Somey)|[(0,x)]->(Somex,None)|[(1,y)]->(None,Somey)|[]->invalid_arg"cannot encode ill-formed Merkle proof"|_->invalid_arg"cannot encode non binary proof tree")(function|Somex,Somey->Ok[(0,x);(1,y)]|Somex,None->Ok[(0,x)]|None,Somey->Ok[(1,y)]|None,None->Error"cannot decode ill-formed Merkle proof")(tup2aa)letinode_proofs_encoding_gena=(* When the number of proofs is large enough (>= Context.Conf.entries / 2),
proofs are encoded as `array` instead of `list` for compactness. *)(* This encode assumes that proofs are ordered by its index. *)letencode_typev=ifCompare.List_length_with.(v>=entries/2)then`Arrayelse`Listinunion~tag_size:`Uint8[case~title:"sparse_proof"(Tag0)(obj1(req"sparse_proof"(conv_with_guard(funv->List.map(fun(i,d)->(i,Somed))v)(funv->List.fold_right_e(fun(i,d)acc->matchdwith|None->Error"cannot decode ill-formed Merkle proof"|Somed->Ok((i,d)::acc))v[])(list(tup2index_encodinga)))))(funv->ifencode_typev=`ListthenSomevelseNone)(funv->v);case~title:"dense_proof"(Tag1)(obj1(req"dense_proof"(Fixed.arrayentriesa)))(funv->ifencode_typev=`Arraythen(letarr=Array.makeentriesNonein(* The `a` passed to this encoding will be
`option_inode_tree_encoding` and `option_inode_tree_encoding`,
both encode `option` tags with its variant tag,
thus this `option` wrapping won't increase the encoding size. *)List.iter(fun(i,d)->arr.(i)<-Somed)v;Somearr)elseNone)(funv->letres=ref[]infori=Array.lengthv-1downto0domatchv.(i)withNone->()|Somed->res:=(i,d)::!resdone;!res);]letinode_proofs_encoding=matchentrieswith|2->inode_proofs_encoding_2|_->inode_proofs_encoding_genletinode_encodinga=conv(fun{length;proofs}->(length,proofs))(fun(length,proofs)->{length;proofs})@@obj2length_field(req"proofs"(inode_proofs_encodinga))letinode_extender_encodinga=conv(fun{length;segment;proof}->(length,segment,proof))(fun(length,segment,proof)->{length;segment;proof})@@obj3length_field(req"segment"segment_encoding)(req"proof"a)(* data-encoding.0.4/test/mu.ml for building mutually recursive data_encodings *)let_inode_tree_encoding,tree_encoding=letunoptionizeenc=conv_with_guard(funv->Somev)(function|Somev->Okv|None->Error"cannot decode ill-formed Merkle proof")encinletmu_option_inode_tree_encodingtree_encoding=mu"inode_tree"(funoption_inode_tree_encoding->letinode_tree_encoding=unoptionizeoption_inode_tree_encodinginunion[case~title:"Blinded_inode"(Tag0)(obj1(req"blinded_inode"hash_encoding))(functionSome(Blinded_inodeh)->Someh|_->None)(funh->Some(Blinded_inodeh));case~title:"Inode_values"(Tag1)(obj1(req"inode_values"(list(tup2step_encodingtree_encoding))))(functionSome(Inode_valuesxs)->Somexs|_->None)(funxs->Some(Inode_valuesxs));case~title:"Inode_tree"(Tag2)(obj1(req"inode_tree"(inode_encodingoption_inode_tree_encoding)))(functionSome(Inode_treei)->Somei|_->None)(funi->Some(Inode_treei));case~title:"Inode_extender"(Tag3)(obj1(req"inode_extender"(inode_extender_encodinginode_tree_encoding)))(function|Some(Inode_extenderi:inode_tree)->Somei|_->None)(funi:inode_treeoption->Some(Inode_extenderi));case~title:"None"(Tag4)(obj1(req"none"null))(functionNone->Some()|Some_->None)(fun()->None);])inletmu_option_tree_encoding:treeoptionencoding=mu"tree_encoding"(funoption_tree_encoding->lettree_encoding=unoptionizeoption_tree_encodinginletoption_inode_tree_encoding=mu_option_inode_tree_encodingtree_encodinginletinode_tree_encoding=unoptionizeoption_inode_tree_encodinginunion[case~title:"Value"(Tag0)(obj1(req"value"value_encoding))(functionSome(Valuev:tree)->Somev|_->None)(funv->Some(Valuev));case~title:"Blinded_value"(Tag1)(obj1(req"blinded_value"hash_encoding))(functionSome(Blinded_valuehash)->Somehash|_->None)(funhash->Some(Blinded_valuehash));case~title:"Node"(Tag2)(obj1(req"node"(list(tup2step_encodingtree_encoding))))(functionSome(Nodests:tree)->Somests|_->None)(funsts->Some(Nodests));case~title:"Blinded_node"(Tag3)(obj1(req"blinded_node"hash_encoding))(functionSome(Blinded_nodehash)->Somehash|_->None)(funhash->Some(Blinded_nodehash));case~title:"Inode"(Tag4)(obj1(req"inode"(inode_encodingoption_inode_tree_encoding)))(functionSome(Inodei:tree)->Somei|_->None)(funi->Some(Inodei));case~title:"Extender"(Tag5)(obj1(req"extender"(inode_extender_encodinginode_tree_encoding)))(functionSome(Extenderi)->Somei|_->None)(funi->Some(Extenderi));case~title:"None"(Tag6)(obj1(req"none"null))(functionNone->Some()|Some_->None)(fun()->None);])inlettree_encoding=unoptionizemu_option_tree_encodinginletinode_tree_encoding=unoptionize@@mu_option_inode_tree_encodingtree_encodingin(inode_tree_encoding,tree_encoding)letkinded_hash_encoding=union[case~title:"Value"(Tag0)(obj1(req"value"hash_encoding))(function`Valuech->Somech|_->None)(funch->`Valuech);case~title:"Node"(Tag1)(obj1(req"node"hash_encoding))(function`Nodech->Somech|_->None)(funch->`Nodech);]letelt_encoding=letopenStreaminunion[case~title:"Value"(Tag0)(obj1(req"value"value_encoding))(functionValuev->Somev|_->None)(funv->Valuev);case~title:"Node"(Tag1)(obj1(req"node"(list(tup2step_encodingkinded_hash_encoding))))(functionNodesks->Somesks|_->None)(funsks->Nodesks);case~title:"Inode"(Tag2)(* This option wrapping increases the encoding size.
But stream encoding is basically larger than proof encoding,
so I temporarily won't mind this increment. *)(obj1(req"inode"(inode_encoding(optionhash_encoding))))(functionInodehinode->Somehinode|_->None)(funhinode->Inodehinode);case~title:"Inode_extender"(Tag3)(obj1(req"inode_extender"(inode_extender_encodinghash_encoding)))(functionInode_extendere->Somee|_->None)(fune->Inode_extendere);]letstream_encoding=convList.of_seqList.to_seq(listelt_encoding)letencodinga=conv(fun{version;before;after;state}->(version,before,after,state))(fun(version,before,after,state)->{version;before;after;state})@@obj4(req"version"int16)(req"before"kinded_hash_encoding)(req"after"kinded_hash_encoding)(req"state"a)lettree_proof_encoding=encodingtree_encodingletstream_proof_encoding=encodingstream_encodingend(* Using `Data_encoding.Compact`. Harder to parse but more efficient *)moduleMake_V2(Conf:sigvalentries:intend)=structopenTezos_context_sigs.Context.Proof_typesmoduleV1=Make_V1(Conf)openData_encodingletentries=Conf.entries(* The code only supports branching factors 2 and 32 *)let()=assert(entries=2||entries=32)letvalue_encoding:valueCompact.t=letopenCompactinletbytes_casenameab=letcheck_lengths=letl=Bytes.lengthsina<=l&&l<bincase~title:name(payload@@Bounded.bytes(b-1))(funs->ifcheck_lengthsthenSomeselseNone)(funs->ifcheck_lengthsthenselseinvalid_arg"cannot decode ill-formed Merkle proof")inunion~union_tag_bits:2~cases_tag_bits:0[bytes_case"short_bytes"0256;bytes_case"medium_bytes"256(256*256);(* The following case will be introduced
when uint24 field is implemented in Data_enopding. *)(* bytes_case "long_bytes" (256 * 256 * 256); *)void_case~title:"long_bytes";(letcheck_lengths=256*256<=Bytes.lengthsincase~title:"unlimited_bytes"(payloadbytes)(funs->ifcheck_lengthsthenSomeselseNone)(funs->ifcheck_lengthsthenselseinvalid_arg"cannot decode ill-formed Merkle proof"));]letlength_field:intCompact.field=letopenCompactinreq"length"@@convInt64.of_intInt64.to_intint64letstep_encoding:stepData_encoding.t=V1.step_encodinglethash_encoding=Compact.payloadV1.hash_encodingletsegment_encoding=Compact.payloadV1.segment_encodingletinode_proofs_encoding_2a=letopenCompactinconv(function|[(0,x);(1,y)]->(Somex,Somey)|[(0,x)]->(Somex,None)|[(1,y)]->(None,Somey)|[]->invalid_arg"cannot encode ill-formed Merkle proof"|_->invalid_arg"cannot encode non binary proof tree")(function|Somex,Somey->[(0,x);(1,y)]|Somex,None->[(0,x)]|None,Somey->[(1,y)]|None,None->invalid_arg"cannot decode ill-formed Merkle proof")(tup2aa)letinode_proofs_encoding_32a=(* When the number of proofs is large enough (>= Context.Conf.entries / 2),
proofs are encoded as `array` instead of `list` for compactness. *)(* Due to the limitation of tag bits,
we encode lists whose length is 15 as an array. *)(* This encode assumes that proofs are ordered by its index. *)letencode_typev=ifCompare.List_length_with.(v<15)then`Listelse`ArrayinletopenCompactin(* When mu is introduced to `Data_encoding.Compact`,
we may better use 5bit union as index_encoding. *)letindex_encoding=uint8inleta=make~tag_size:(iftag_bit_counta=0then`Uint0else`Uint8)ainunion~union_tag_bits:1~cases_tag_bits:4[case~title:"sparse_proof"(obj1(req"sparse_proof"(conv(funv->List.map(fun(i,d)->(i,Somed))v)(funv->List.fold_right(fun(i,d)acc->matchdwith|None->invalid_arg"cannot decode ill-formed Merkle proof"|Somed->(i,d)::acc)v[])(* 4bit share tag is required to store the length of sparse proof (0..14) *)(list~bits:4Data_encoding.(tup2index_encodinga)))))(funv->ifencode_typev=`ListthenSomevelseNone)(funv->v);case~title:"dense_proof"(obj1(req"dense_proof"(payload@@Fixed.arrayentriesa)))(funv->ifencode_typev=`Arraythen(letarr=Array.makeentriesNonein(* The `a` passed to this encoding will be
`option_inode_tree_encoding` and `option_inode_tree_encoding`,
both encode `option` tags with its variant tag,
thus this `option` wrapping won't increase the encoding size. *)List.iter(fun(i,d)->arr.(i)<-Somed)v;Somearr)elseNone)(funv->letres=ref[]infori=Array.lengthv-1downto0domatchv.(i)withNone->()|Somed->res:=(i,d)::!resdone;!res);]letinode_proofs_encoding=matchentrieswith|2->inode_proofs_encoding_2|32->inode_proofs_encoding_32|_->(* Unsupported *)assertfalseletinode_encodinga=letopenCompactinconv(fun{length;proofs}->(length,proofs))(fun(length,proofs)->{length;proofs})@@obj2length_field(req"proofs"(inode_proofs_encodinga))letinode_extender_encodinga=letopenCompactinconv(fun{length;segment;proof}->(length,segment,proof))(fun(length,segment,proof)->{length;segment;proof})@@obj3length_field(req"segment"segment_encoding)(req"proof"a)letbits_of_node_list=matchentrieswith|32->6(* 6bit :: 0 - 62 *)|2->2(* 2bit :: 0 - 2 *)|_->(* Unsupported *)assertfalse(* data-encoding.0.4/test/mu.ml for building mutually recursive data_encodings *)let_inode_tree_encoding,tree_encoding=letunoptionizeenc=conv_with_guard(funv->Somev)(function|Somev->Okv|None->Error"cannot decode ill-formed Merkle proof")encinletmu_option_inode_tree_encodingtree_encoding=mu"inode_tree"(funoption_inode_tree_encoding->letinode_tree_encoding=unoptionizeoption_inode_tree_encodinginletopenCompactin(* Variant layouts and required shared tag bits.
0xxxxxxx :: Inode_tree (requires 7bits)
10xxxxxx :: Inode_values (requires 6bits)
1100xxxx :: Blinded_inode (requires 0bits)
1101xxxx :: Inode_extender (requires 2bits)
1110xxxx :: None (requires 0bits) *)make~tag_size:`Uint8@@union~union_tag_bits:1~cases_tag_bits:7[case~title:"Inode_tree"(obj1(req"inode_tree"(inode_encoding(payloadoption_inode_tree_encoding))))(functionSome(Inode_treei)->Somei|_->None)(funi->Some(Inode_treei));case~title:"other_inode_trees"(obj1(req"other_inode_trees"(union~union_tag_bits:1~cases_tag_bits:6[case~title:"Inode_values"(obj1(req"inode_values"(list~bits:bits_of_node_listData_encoding.(tup2step_encodingtree_encoding))))(function|Some(Inode_valuesxs)->Somexs|_->None)(funxs->Some(Inode_valuesxs));case~title:"other_inode_trees"(obj1(req"other_inode_trees"(union~union_tag_bits:2~cases_tag_bits:4[case~title:"Blinded_inode"(obj1(req"blinded_inode"hash_encoding))(function|Some(Blinded_inodeh)->Someh|_->None)(funh->Some(Blinded_inodeh));case~title:"Inode_extender"(obj1(req"inode_extender"(inode_extender_encoding(payloadinode_tree_encoding))))(function|Some(Inode_extenderi:inode_tree)->Somei|_->None)(funi:inode_treeoption->Some(Inode_extenderi));case(obj1(req"none"unit))~title:"None"(function|None->Some()|Some_->None)(fun()->None);])))(function|Some(Inode_values_)->None|v->Somev)(funv->v);])))(functionSome(Inode_tree_)->None|v->Somev)(funv->v);])inletmu_option_tree_encoding:treeoptionencoding=mu"tree_encoding"(funoption_tree_encoding->lettree_encoding=unoptionizeoption_tree_encodinginletoption_inode_tree_encoding=mu_option_inode_tree_encodingtree_encodinginletinode_tree_encoding=unoptionizeoption_inode_tree_encodinginletopenCompactin(* Variant layouts and required shared tag bits.
0xxxxxxx :: Inode (requires 7bits)
10xxxxxx :: Node (requires 6bits)
11000xxx :: Value (requires 2bits)
11001xxx :: Blinded_value (requires 0bits)
11010xxx :: Blinded_node (requires 0bits)
11011xxx :: Extender (requires 2bits)
11100xxx :: None (requires 0bits) *)make~tag_size:`Uint8@@union~union_tag_bits:1~cases_tag_bits:7[case~title:"Inode"(obj1(req"inode"(inode_encoding(payloadoption_inode_tree_encoding))))(functionSome(Inodei:tree)->Somei|_->None)(funi->Some(Inodei));case~title:"other_trees"(obj1(req"other_trees"(union~union_tag_bits:1~cases_tag_bits:6[case~title:"Node"(obj1(req"node"(list~bits:bits_of_node_listData_encoding.(tup2step_encodingtree_encoding))))(function|Some(Nodests:tree)->Somests|_->None)(funsts->Some(Nodests));case~title:"other_trees"(obj1(req"other_trees"(union~union_tag_bits:3~cases_tag_bits:3[case~title:"Value"(obj1(req"value"value_encoding))(function|Some(Valuev:tree)->Somev|_->None)(funv->Some(Valuev));case~title:"Blinded_value"(obj1(req"blinded_value"hash_encoding))(function|Some(Blinded_valuehash)->Somehash|_->None)(funhash->Some(Blinded_valuehash));case~title:"Blinded_node"(obj1(req"blinded_node"hash_encoding))(function|Some(Blinded_nodehash)->Somehash|_->None)(funhash->Some(Blinded_nodehash));case~title:"Extender"(obj1(req"extender"(inode_extender_encoding(payloadinode_tree_encoding))))(function|Some(Extenderi)->Somei|_->None)(funi->Some(Extenderi));case(obj1(req"none"unit))~title:"None"(function|None->Some()|Some_->None)(fun()->None);])))(functionSome(Node_)->None|v->Somev)(funv->v);])))(functionSome(Inode_)->None|v->Somev)(funv->v);])inlettree_encoding=unoptionizemu_option_tree_encodinginletinode_tree_encoding=unoptionize@@mu_option_inode_tree_encodingtree_encodingin(inode_tree_encoding,tree_encoding)letkinded_hash_encoding=letopenCompactinunion~union_tag_bits:1~cases_tag_bits:0[case~title:"Value"(obj1(req"value"hash_encoding))(function`Valuech->Somech|_->None)(funch->`Valuech);case~title:"Node"(obj1(req"node"hash_encoding))(function`Nodech->Somech|_->None)(funch->`Nodech);]letelt_encoding=letopenStreaminletopenCompactin(* Variant layouts and required shared tag bits.
0xxxxxxx :: Inode (requires 7bits)
10xxxxxx :: Node (requires 6bits)
11000xxx :: Value (requires 2bits)
11011xxx :: Inode_extender (requires 2bits) *)union~union_tag_bits:1~cases_tag_bits:7[case~title:"Inode"(obj1(req"inode"(inode_encoding(optionhash_encoding))))(functionInodehinode->Somehinode|_->None)(funhinode->Inodehinode)(* This option wrapping increases the encoding size when `entries = 32`.
But stream encoding is basically larger than proof encoding,
so I temporarily won't mind this increment. *);case~title:"other_elts"(obj1(req"other_elts"(union~union_tag_bits:1~cases_tag_bits:6[case~title:"Node"(obj1(req"node"(list~bits:bits_of_node_listData_encoding.(tup2step_encoding(make~tag_size:`Uint8kinded_hash_encoding)))))(functionNodesks->Somesks|_->None)(funsks->Nodesks);case~title:"other_elts"(obj1(req"other_elts"(union~union_tag_bits:1~cases_tag_bits:5[case~title:"Value"(obj1(req"value"value_encoding))(functionValuev->Somev|_->None)(funv->Valuev);case~title:"Inode_extender"(obj1(req"inode_extender"(inode_extender_encodinghash_encoding)))(function|Inode_extendere->Somee|_->None)(fune->Inode_extendere);])))(functionNode_->None|e->Somee)(fune->e);])))(functionInode_->None|e->Somee)(fune->e);]letstream_encoding=(* Encoding method should be revisited after the actual stream length is determined. *)convList.of_seqList.to_seq(list@@Compact.make~tag_size:`Uint8elt_encoding)letencodinga=letopenCompactinconv(fun{version;before;after;state}->(version,before,after,state))(fun(version,before,after,state)->{version;before;after;state})@@obj4(req"version"(payloadint16))(req"before"kinded_hash_encoding)(req"after"kinded_hash_encoding)(req"state"a)lettree_proof_encoding=letopenCompactinmake~tag_size:`Uint8@@encoding(payloadtree_encoding)letstream_proof_encoding=letopenCompactinmake~tag_size:`Uint8@@encoding(payloadstream_encoding)endmoduleV1=structmoduleTree32=Make_V1(structletentries=32end)moduleTree2=Make_V1(structletentries=2end)endmoduleV2=structmoduleTree32=Make_V2(structletentries=32end)moduleTree2=Make_V2(structletentries=2end)end