123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065(*****************************************************************************)(* *)(* MIT License *)(* Copyright (c) 2022 Nomadic Labs <contact@nomadic-labs.com> *)(* *)(* 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. *)(* *)(*****************************************************************************)(** Plompiler standard library. *)openLang_core(** The {!LIB} module type extends the core language defined in {!Lang_core.COMMON}
by adding functions that build upon those primitives.
*)moduletypeLIB=sigincludeCOMMON(** [foldiM] is the monadic version of a fold over a natural number. *)valfoldiM:('a->int->'at)->'a->int->'at(** [fold2M] is the monadic version of [List.fold_left2]. *)valfold2M:('a->'b->'c->'at)->'a->'blist->'clist->'at(** [mapM] is the monadic version of [List.map]. *)valmapM:('a->'bt)->'alist->'blistt(** [map2M] is the monadic version of [List.map2]. *)valmap2M:('a->'b->'ct)->'alist->'blist->'clistt(** [iterM] is the monadic version of [List.iter]. *)valiterM:('a->unitreprt)->'alist->unitreprt(** [iter2M] is the monadic version of [List.iter2]. *)valiter2M:('a->'b->unitreprt)->'alist->'blist->unitreprtmoduleBool:sigincludeBOOL(** Returns the pair (s, c_out), as per
https://en.wikipedia.org/wiki/Adder_(electronics)#Full_adder *)valfull_adder:boolrepr->boolrepr->boolrepr->(bool*bool)reprtendwithtypescalar=scalarandtype'arepr='areprandtype'at='atmoduleNum:sigincludeNUM(** [square a] returns the value [a^2]. *)valsquare:scalarrepr->scalarreprt(** [pow b e_bits] returns the value [b^e] where [e] is the
number represented by the binary decomposition [e_bits]. *)valpow:scalarrepr->boolreprlist->scalarreprt(** [add_list ~qc ~coeffs l] returns the sum of the elements of [l]
weighted by [coeffs].
Note: if [coeffs] is defined, it should be of the same length
as [l].
*)valadd_list:?qc:S.t->?coeffs:S.tlist->scalarlistrepr->scalarreprt(** [mul_list l] returns the product of the elements of [l]. *)valmul_list:scalarlistrepr->scalarreprt(** [mul_by_constant k a] returns the value [k * a]. *)valmul_by_constant:S.t->scalarrepr->scalarreprt(* [scalar_of_bytes bs] returns the scalar represented by the binary
sequence [bs].
Specifically, it evaluates P(X) = \sum_i bᵢ Xⁱ at 2. *)valscalar_of_bytes:boollistrepr->scalarreprt(** [is_eq_const a k] returns whether [a] is equal to [k]. *)valis_eq_const:scalarrepr->S.t->boolreprt(** [assert_eq_const a k] asserts that [a] is equal to [k]. *)valassert_eq_const:scalarrepr->S.t->unitreprt(** [is_upper_bounded ~bound x] returns whether the scalar [x] is
strictly lower than [bound] when [x] is interpreted as an integer
from [0] to [p-1] (being [p] the scalar field order).
This circuit is total (and more expensive than our version below). *)valis_upper_bounded:bound:Z.t->scalarrepr->boolreprt(** Same as [is_upper_bounded] but cheaper and partial.
[is_upper_bounded_unsafe ~bound l] is unsatisfiable if l cannot be
represented in binary with [Z.numbits bound] bits. *)valis_upper_bounded_unsafe:?nb_bits:int->bound:Z.t->scalarrepr->boolreprt(** [geq (a, bound_a) (b, bound_b)] returns the boolean wire representing
a >= b.
Pre-condition: [a ∈ \[0, bound_a) ∧ b ∈ \[0, bound_b)] *)valgeq:scalarrepr*Z.t->scalarrepr*Z.t->boolreprtendwithtypescalar=scalarandtype'arepr='areprandtype'at='at(** Enumerations, represented as a list of cases. *)moduleEnum(N:sigvaln:intend):sig(** [switch_case k l] returns the k-th element of the list [l] if
k ∈ \[0,n) or the first element of [l] otherwise. *)valswitch_case:scalarrepr->'alistrepr->'areprtend(** Representation of bytes. *)moduleBytes:sig(** Little-endian representation of bytes.
First element of the list is the Least Significant Bit. *)typebl=boollist(** [input_bytes ~le bs] returns the representation of [bs]
that Plompiler expects as input. *)valinput_bytes:le:bool->bytes->blInput.t(** [constant ~le bs] returns a value holding the bytes [bs].
[le] can be used to set the endianness. *)valconstant:le:bool->bytes->blreprt(** [constant_uint32 ~le n] returns a value holding the bytes correspoding
to the uint [n].
[le] can be used to set the endianness. *)valconstant_uint32:le:bool->Stdint.uint32->blreprt(** [length b] returns the length of [b] in bits. *)vallength:blrepr->int(** [concat bs] returns the concatenation of the bitlists in [bs]. *)valconcat:blreprarray->blrepr(** [add b1 b2] computes the addition of [b1] and [b2]. *)valadd:?ignore_carry:bool->blrepr->blrepr->blreprt(** [xor b1 b2] computes the bitwise xor between [b1] and [b2]. *)valxor:blrepr->blrepr->blreprt(** [not b] computes the bitwise negation of [b]. *)valnot:blrepr->blreprt(** [band b1 b2] computes the bitwise conjunction between [b1] and [b2]. *)valband:blrepr->blrepr->blreprt(** [rotate_left bl n] shifts the bits left by n positions,
so that each bit is more significant.
The most significant bit becomes the least significant
i.e. it is "rotated".
[rotate_left bl (length bl) = bl] *)valrotate_left:blrepr->int->blreprt(** [rotate_right bl n] shifts the bits right by n positions.
Similar to {!rotate_left}, but to the right. *)valrotate_right:blrepr->int->blreprt(** [shift_left bl n] shifts all bits left by n positions,
so that each bit is more significant.
The most signigicant bit is lost and the least significant bit is
set to zero.
More precisely, if we interpret the [bl] as an integer
[shift_left bl i = bl * 2^i mod 2^{length a}] *)valshift_left:blrepr->int->blreprt(** [shift_right bl n] shifts all bits right by n positions.
Similar to {!shift_left}, but to the right. *)valshift_right:blrepr->int->blreprtmoduleInternal:sigvalxor_lookup:blrepr->blrepr->blreprtvalband_lookup:blrepr->blrepr->blreprtvalnot_lookup:blrepr->blreprtendendmoduleLimbs(N:sigvalnb_bits:intend):sig(* This module is a more generic version of Bytes, where each scalar
stores an [nb_bits]-bit number. *)typesl=scalarlistvalof_bytes:Bytes.blrepr->slreprtvalto_bytes:slrepr->Bytes.blreprtvalto_scalar:slrepr->scalarreprtvalof_scalar:total_nb_bits:int->scalarrepr->slreprtvalconstant:le:bool->bytes->slreprtvalxor_lookup:slrepr->slrepr->slreprtvalband_lookup:slrepr->slrepr->slreprtvalbnot_lookup:slrepr->slreprtvalrotate_right_lookup:slrepr->int->slreprtvalshift_right_lookup:slrepr->int->slreprtend(** [add2 p1 p2] returns the pair [(fst p1 + fst p2, snd p1 + snd p2)]. *)valadd2:(scalar*scalar)repr->(scalar*scalar)repr->(scalar*scalar)reprtmoduleEncodings:sig(**
Encoding type for encapsulating encoding/decoding/input functions.
This type enables us to use more structured types for data
in circuits.
For that, encoding is parameterized by 3 types:
- 'oh is the type of the high-level OCaml representation
- 'u is the unpacked type, i.e. a collection of atomic reprs.
- `p is the packed type, i.e the inner type of Plompiler's repr.
For example, for the representation of a point (pair of scalars),
one might have:
{[
( {x:int; y:int},
scalar repr * scalar repr,
scalar * scalar
) encoding
]}
The first type, the record [{x:int; y:int}], represents an OCaml point,
which becomes the argument taken by the [input] function.
The second type, [scalar repr * scalar repr], is an unpacking of the
encoding. This is used for the result of [decode]. We can use any type
isomorphic to [scalar repr * scalar repr] here.
The last type must be [scalar * scalar], as an encoding of a point will be
of the type [(scalar * scalar) repr].
*)type('oh,'u,'p)encoding={encode:'u->'prepr;decode:'prepr->'u;input:'oh->'pInput.input;of_input:'pInput.input->'oh;}(**
The function [conv] defines conversions for [encoding]s, by changing
the higher-level ['u] and and ['oh] types.
*)valconv:('u1->'u0)->('u0->'u1)->('o1->'o0)->('o0->'o1)->('o0,'u0,'p)encoding->('o1,'u1,'p)encodingvalwith_implicit_bool_check:('prepr->boolreprt)->('o,'u,'p)encoding->('o,'u,'p)encodingvalwith_assertion:('prepr->unitreprt)->('o,'u,'p)encoding->('o,'u,'p)encodingvalscalar_encoding:(Bls12_381.Fr.t,scalarrepr,scalar)encodingvalbool_encoding:(bool,boolrepr,bool)encodingvallist_encoding:('a,'b,'c)encoding->('alist,'blist,'clist)encodingvalatomic_list_encoding:('a,'brepr,'c)encoding->('alist,'blistrepr,'clist)encodingvalobj2_encoding:('a,'b,'c)encoding->('d,'e,'f)encoding->('a*'d,'b*'e,'c*'f)encodingvalatomic_obj2_encoding:('a,'brepr,'c)encoding->('d,'erepr,'f)encoding->('a*'d,('b*'e)repr,'c*'f)encodingvalobj3_encoding:('a,'b,'c)encoding->('d,'e,'f)encoding->('g,'h,'i)encoding->('a*('d*'g),'b*('e*'h),'c*('f*'i))encodingvalatomic_obj3_encoding:('a,'brepr,'c)encoding->('d,'erepr,'f)encoding->('g,'hrepr,'i)encoding->('a*('d*'g),('b*('e*'h))repr,'c*('f*'i))encodingvalobj4_encoding:('a,'b,'c)encoding->('d,'e,'f)encoding->('g,'h,'i)encoding->('j,'k,'l)encoding->('a*('d*('g*'j)),'b*('e*('h*'k)),'c*('f*('i*'l)))encodingvalatomic_obj4_encoding:('a,'brepr,'c)encoding->('d,'erepr,'f)encoding->('g,'hrepr,'i)encoding->('j,'krepr,'l)encoding->('a*('d*('g*'j)),('b*('e*('h*'k)))repr,'c*('f*('i*'l)))encodingvalobj5_encoding:('a,'b,'c)encoding->('d,'e,'f)encoding->('g,'h,'i)encoding->('j,'k,'l)encoding->('m,'n,'o)encoding->('a*('d*('g*('j*'m))),'b*('e*('h*('k*'n))),'c*('f*('i*('l*'o))))encodingvalatomic_obj5_encoding:('a,'brepr,'c)encoding->('d,'erepr,'f)encoding->('g,'hrepr,'i)encoding->('j,'krepr,'l)encoding->('m,'nrepr,'o)encoding->('a*('d*('g*('j*'m))),('b*('e*('h*('k*'n))))repr,'c*('f*('i*('l*'o))))encodingvalobj6_encoding:('a,'b,'c)encoding->('d,'e,'f)encoding->('g,'h,'i)encoding->('j,'k,'l)encoding->('m,'n,'o)encoding->('p,'q,'r)encoding->('a*('d*('g*('j*('m*'p)))),'b*('e*('h*('k*('n*'q)))),'c*('f*('i*('l*('o*'r)))))encodingvalatomic_obj6_encoding:('a,'brepr,'c)encoding->('d,'erepr,'f)encoding->('g,'hrepr,'i)encoding->('j,'krepr,'l)encoding->('m,'nrepr,'o)encoding->('p,'qrepr,'r)encoding->('a*('d*('g*('j*('m*'p)))),('b*('e*('h*('k*('n*'q)))))repr,'c*('f*('i*('l*('o*'r)))))encodingvalobj7_encoding:('a,'b,'c)encoding->('d,'e,'f)encoding->('g,'h,'i)encoding->('j,'k,'l)encoding->('m,'n,'o)encoding->('p,'q,'r)encoding->('s,'t,'u)encoding->('a*('d*('g*('j*('m*('p*'s))))),'b*('e*('h*('k*('n*('q*'t))))),'c*('f*('i*('l*('o*('r*'u))))))encodingvalatomic_obj7_encoding:('a,'brepr,'c)encoding->('d,'erepr,'f)encoding->('g,'hrepr,'i)encoding->('j,'krepr,'l)encoding->('m,'nrepr,'o)encoding->('p,'qrepr,'r)encoding->('s,'trepr,'u)encoding->('a*('d*('g*('j*('m*('p*'s))))),('b*('e*('h*('k*('n*('q*'t))))))repr,'c*('f*('i*('l*('o*('r*'u))))))encodingvalobj8_encoding:('a,'b,'c)encoding->('d,'e,'f)encoding->('g,'h,'i)encoding->('j,'k,'l)encoding->('m,'n,'o)encoding->('p,'q,'r)encoding->('s,'t,'u)encoding->('v,'w,'x)encoding->('a*('d*('g*('j*('m*('p*('s*'v)))))),'b*('e*('h*('k*('n*('q*('t*'w)))))),'c*('f*('i*('l*('o*('r*('u*'x)))))))encodingvalatomic_obj8_encoding:('a,'brepr,'c)encoding->('d,'erepr,'f)encoding->('g,'hrepr,'i)encoding->('j,'krepr,'l)encoding->('m,'nrepr,'o)encoding->('p,'qrepr,'r)encoding->('s,'trepr,'u)encoding->('v,'wrepr,'x)encoding->('a*('d*('g*('j*('m*('p*('s*'v)))))),('b*('e*('h*('k*('n*('q*('t*'w)))))))repr,'c*('f*('i*('l*('o*('r*('u*'x)))))))encodingvalobj9_encoding:('a,'b,'c)encoding->('d,'e,'f)encoding->('g,'h,'i)encoding->('j,'k,'l)encoding->('m,'n,'o)encoding->('p,'q,'r)encoding->('s,'t,'u)encoding->('v,'w,'x)encoding->('y,'z,'a1)encoding->('a*('d*('g*('j*('m*('p*('s*('v*'y))))))),'b*('e*('h*('k*('n*('q*('t*('w*'z))))))),'c*('f*('i*('l*('o*('r*('u*('x*'a1))))))))encodingvalatomic_obj9_encoding:('a,'brepr,'c)encoding->('d,'erepr,'f)encoding->('g,'hrepr,'i)encoding->('j,'krepr,'l)encoding->('m,'nrepr,'o)encoding->('p,'qrepr,'r)encoding->('s,'trepr,'u)encoding->('v,'wrepr,'x)encoding->('y,'zrepr,'a1)encoding->('a*('d*('g*('j*('m*('p*('s*('v*'y))))))),('b*('e*('h*('k*('n*('q*('t*('w*'z))))))))repr,'c*('f*('i*('l*('o*('r*('u*('x*'a1))))))))encodingvalobj10_encoding:('a,'b,'c)encoding->('d,'e,'f)encoding->('g,'h,'i)encoding->('j,'k,'l)encoding->('m,'n,'o)encoding->('p,'q,'r)encoding->('s,'t,'u)encoding->('v,'w,'x)encoding->('y,'z,'a1)encoding->('b1,'c1,'d1)encoding->('a*('d*('g*('j*('m*('p*('s*('v*('y*'b1)))))))),'b*('e*('h*('k*('n*('q*('t*('w*('z*'c1)))))))),'c*('f*('i*('l*('o*('r*('u*('x*('a1*'d1)))))))))encodingvalatomic_obj10_encoding:('a,'brepr,'c)encoding->('d,'erepr,'f)encoding->('g,'hrepr,'i)encoding->('j,'krepr,'l)encoding->('m,'nrepr,'o)encoding->('p,'qrepr,'r)encoding->('s,'trepr,'u)encoding->('v,'wrepr,'x)encoding->('y,'zrepr,'a1)encoding->('b1,'c1repr,'d1)encoding->('a*('d*('g*('j*('m*('p*('s*('v*('y*'b1)))))))),('b*('e*('h*('k*('n*('q*('t*('w*('z*'c1)))))))))repr,'c*('f*('i*('l*('o*('r*('u*('x*('a1*'d1)))))))))encodingendendmoduleLib(C:COMMON)=structincludeCletfoldiM:('a->int->'at)->'a->int->'at=funfen->foldMfe(List.initn(funi->i))letfold2Mfacclsrs=foldM(funacc(l,r)->facclr)acc(List.combinelsrs)letmapMfl=let*l=foldM(funacce->let*e=feinret@@(e::acc))[]linret@@List.revlletmap2Mflsrs=mapM(fun(l,r)->flr)(List.combinelsrs)letiterMfl=foldM(fun_a->fa)unitlletiter2Mflr=iterM(fun(l,r)->flr)(List.combinelr)moduleBool=structincludeBoolletfull_adderabc_in=with_label~label:"Bool.full_adder"@@let*a_xor_b=xorabinlet*a_xor_b_xor_c=xora_xor_bc_ininlet*a_xor_b_and_c=banda_xor_bc_ininlet*a_and_b=bandabinlet*c=bora_xor_b_and_ca_and_binret(paira_xor_b_xor_cc)endmoduleNum=structincludeNumletsquarel=mulllletpowxn_list=let*init=let*left=Num.oneinret(left,x)inlet*res,_acc=foldM(fun(res,acc)bool->let*res_true=mulresaccinlet*res=Bool.ifthenelseboolres_trueresinlet*acc=mulaccaccinret(res,acc))initn_listinretresletadd_list?(qc=S.zero)?(coeffs=[])l=letl=of_listlinletq=ifcoeffs!=[]thencoeffselseList.init(List.lengthl)(fun_->S.one)inassert(List.compare_lengthsql=0);match(l,q)with|x1::x2::xs,ql::qr::qs->let*res=Num.add~qc~ql~qrx1x2infold2M(funaccxql->Num.add~qlxacc)resxsqs|[x],[ql]->Num.add_constant~qlqcx|[],[]->Num.constantqc|_,_->assertfalseletmul_listl=matchof_listlwith[]->assertfalse|x::xs->foldMNum.mulxxsletmul_by_constantsx=Num.add_constant~ql:sS.zeroxletscalar_of_bytesb=letsb=List.mapscalar_of_bool(of_listb)inscalar_of_limbs~nb_bits:1(to_listsb)letassert_eq_constls=Num.assert_custom~ql:S.mone~qc:slllletis_eq_constls=let*diff=add_constant~ql:S.moneslinis_zerodiff(* Function used by [is_upper_bounded(_unsafe)] *)letignore_leading_zeros~nb_bits~boundxbits=(* We can ignore all leading zeros in the bound's little-endian binary
decomposition. The assertion cannot be satisfied if they are all zeros. *)letrecshave_zeros=function|[]->raise(Invalid_argument"is_upper_bounded cannot be satisfied on bound = 0")|(x,true)::tl->(x,tl)|(_,false)::tl->shave_zerostlinList.combine(of_listxbits)(Utils.bool_list_of_z~nb_bitsbound)|>shave_zeros(* Let [(bn,...,b0)] and [(xn,...,x0)] be binary representations
of [bound] and [x] respectively where the least significant bit is
indexed by [0]. Let [op_i = if b_i = 1 then band else bor] for all [i].
Predicate [x] < [bound] can be expressed as the negation of predicate:
[ xn op_n (... (x1 op_1 (x0 op_0 true))) ].
Intuitively we need to carry through a flag that indicates if up to
step i, x is greater than b. In order for x[0,i] to be greater than
b[0,i]:
- if b_i = one then x_i will need to match it and the flag must be true.
- if b_i = zero then x needs to be one if the flag is false or it can
have any value if the flag is already true. *)letis_upper_bounded_unsafe?nb_bits~boundx=assert(Z.zero<=bound&&bound<S.order);letnb_bits=Option.value~default:(ifZ.(equalboundzero)then1elseZ.numbitsbound)nb_bitsinlet*xbits=bits_of_scalar~nb_bitsxinletinit,xibi=ignore_leading_zeros~nb_bits~boundxbitsinlet*geq=foldM(funacc(xi,bi)->letop=ifbithenBool.bandelseBool.borinopxiacc)initxibiinBool.bnotgeqletis_upper_bounded~boundx=assert(Z.zero<=bound&&bound<S.order);letnb_bits=Z.numbitsS.orderinletbound_plus_alpha=Z.(bound+Utils.alpha)inlet*xbits=bits_of_scalar~shift:Utils.alpha~nb_bitsxinletinit,xibi=ignore_leading_zeros~nb_bits~bound:bound_plus_alphaxbitsinlet*geq=foldM(funacc(xi,bi)->letop=ifbithenBool.bandelseBool.borinopxiacc)initxibiinBool.bnotgeqletgeq(a,bound_a)(b,bound_b)=(* (a - b) + bound_b - 1 ∈ [0, bound_a + bound_b - 1) *)let*shifted_diff=Num.add~qr:S.mone~qc:(S.of_zZ.(predbound_b))abinletnb_bits=Z.(numbits@@pred(addbound_abound_b))inlet*bits=bits_of_scalar~nb_bitsshifted_diffinletinit,xibi=ignore_leading_zeros~nb_bits~bound:Z.(predbound_b)bitsinfoldM(funacc(xi,bi)->letop=ifbithenBool.bandelseBool.borinopxiacc)initxibiendmoduleEnum(N:sigvaln:intend)=structletswitch_casekcases=letcases=of_listcasesinassert(List.compare_length_withcasesN.n=0);letindexed=List.mapi(funix->(i,x))casesinfoldM(func(i,ci)->let*f=Num.is_eq_constk(S.of_z(Z.of_inti))inBool.ifthenelsefcic)(snd@@List.hdindexed)(List.tlindexed)endmoduleBytes=struct(* first element of the list is the Least Significant Bit *)typebl=boollistletinput_bitlistl=Input.list(List.mapInput.booll)letinput_bytes~leb=input_bitlist@@Utils.bitlist~lebletconstant~leb=letbl=Utils.bitlist~lebinlet*ws=foldM(funwsbit->let*w=Bool.constantbitinret(w::ws))[]blinret@@to_list@@List.revwsletconstant_uint32~leu32=letb=Stdlib.Bytes.create4inStdint.Uint32.to_bytes_big_endianu32b0;constant~lebletlengthb=List.length(of_listb)letconcat:blreprarray->blrepr=funbs->letbs=Array.to_listbsinletbs=List.revbsinletbs=List.mapof_listbsinletbs=List.concatbsinto_listbsletcheck_args_lengthnameab=letla=lengthainletlb=lengthbinifla!=lbthenraise(Invalid_argument(Format.sprintf"%s arguments of different lengths %i %i"namelalb))letadd?(ignore_carry=true)ab=check_args_length"Bytes.add"ab;with_label~label:"Bytes.add"@@letha,ta=(List.hd(of_lista),List.tl(of_lista))inlethb,tb=(List.hd(of_listb),List.tl(of_listb))inlet*a_xor_b=Bool.xorhahbinlet*a_and_b=Bool.bandhahbinlet*res,carry=fold2M(fun(res,c)ab->let*p=Bool.full_adderabcinlets,c=of_pairpinret(s::res,c))([a_xor_b],a_and_b)tatbinret@@to_list@@List.rev(ifignore_carrythenreselsecarry::res)letxorab=check_args_length"Bytes.xor"ab;let*l=map2MBool.xor(of_lista)(of_listb)inret@@to_listlletnota=let*l=mapMBool.bnot(of_lista)inret@@to_listlletbandab=check_args_length"Bytes.band"ab;let*l=map2MBool.band(of_lista)(of_listb)inret@@to_listlletrotate_rightai=letsplit_nnl=letrecauxacckl=ifk=nthen(List.revacc,l)elsematchlwith|h::t->aux(h::acc)(k+1)t|[]->raise(Invalid_argument(Printf.sprintf"split_n: n=%d >= List.length l=%d"nk))inaux[]0linlethead,tail=split_ni(of_lista)inret@@to_list@@tail@headletrotate_leftai=rotate_righta(lengtha-i)letshift_leftai=let*zero=Bool.constantfalseinletl=of_listainletlength=List.lengthl-iinassert(length>=0);letres=List.initi(fun_->zero)@List.filteri(funj_x->j<length)linret@@to_listresletshift_rightai=let*zero=Bool.constantfalseinletl=of_listainassert(List.compare_length_withli>=0);letres=List.filteri(funj_x->j>=i)l@List.initi(fun_->zero)inret@@to_listresmoduleInternal=structletxor_lookupab=check_args_length"Bytes.xor_lookup"ab;let*l=map2MBool.Internal.xor_lookup(of_lista)(of_listb)inret@@to_listlletband_lookupab=check_args_length"Bytes.band_lookup"ab;let*l=map2MBool.Internal.band_lookup(of_lista)(of_listb)inret@@to_listlletnot_lookupb=let*l=mapMBool.Internal.bnot_lookup(of_listb)inret@@to_listlendendmoduleLimbs(N:sigvalnb_bits:intend)=structmoduleLimb=Limb(N)typesl=scalarlistletnb_bits=N.nb_bitsletof_bytesx=letbl=Utils.split_exactly(of_listx)nb_bitsinlet*r=mapM(funx->Num.scalar_of_bytes(to_listx))blinret@@to_listrletto_bytesl=let*lb=mapM(funz->let*bz=bits_of_scalar~nb_bitszinret@@of_listbz)(of_listl)inret@@to_list(List.concatlb)letto_scalarb=scalar_of_limbs~nb_bitsbletof_scalar~total_nb_bitsb=limbs_of_scalar~total_nb_bits~nb_bitsbletconstant~leb=letbl=Utils.bitlist~lebinletlimbs=Utils.limbs_of_bool_list~nb_bitsblinlet*r=mapM(funx->Num.constant@@S.of_intx)limbsinret@@to_listrletxor_lookupab=let*r=map2MLimb.xor_lookup(of_lista)(of_listb)inret@@to_listrletband_lookupab=let*r=map2MLimb.band_lookup(of_lista)(of_listb)inret@@to_listrletbnot_lookupb=let*r=mapMLimb.bnot_lookup(of_listb)inret@@to_listrletrotate_or_shift_right_rem0~is_shiftaind=leta=Array.of_list(of_lista)inletlen=Array.lengthainlet*zero=Num.zeroinletr=List.init(len-ind)(funi->a.(i+ind))@List.initind(funi->ifis_shiftthenzeroelsea.(i))inret@@to_listrletrotate_or_shift_right_rem~is_shiftarem=assert(rem<nb_bits);leta=Array.of_list(of_lista)inletlen=Array.lengthainletget_ii:scalarreprt=ifi<len-1thenLimb.rotate_right_lookupa.(i)a.(i+1)remelselet*zero=Num.zeroinleta0=ifis_shiftthenzeroelsea.(0)inLimb.rotate_right_lookupa.(i)a0reminlet*r=mapMget_i(List.initlen(funi->i))inret@@to_listrletrotate_or_shift_right~is_shiftai=letind=i/nb_bitsinletrem=imodnb_bitsinlet*res=rotate_or_shift_right_rem0~is_shiftaindinifrem>0thenrotate_or_shift_right_rem~is_shiftresremelseretresletrotate_right_lookupai=rotate_or_shift_right~is_shift:falseailetshift_right_lookupai=rotate_or_shift_right~is_shift:trueaiendletadd2p1p2=letx1,y1=of_pairp1inletx2,y2=of_pairp2inlet*x3=Num.addx1x2inlet*y3=Num.addy1y2inret(pairx3y3)moduleEncodings=structtype('oh,'u,'p)encoding={encode:'u->'prepr;decode:'prepr->'u;input:'oh->'pInput.t;of_input:'pInput.t->'oh;}letconv:('u1->'u0)->('u0->'u1)->('o1->'o0)->('o0->'o1)->('o0,'u0,'p)encoding->('o1,'u1,'p)encoding=funfgfigie->letencodea=e.encode@@fainletdecodeb=g@@e.decodebinletinputx=e.input@@fixinletof_inputx=gi@@e.of_inputxin{encode;decode;input;of_input}letwith_implicit_bool_check:('prepr->boolreprt)->('o,'u,'p)encoding->('o,'u,'p)encoding=funbce->{ewithinput=(funx->Input.with_implicit_bool_checkbc@@e.inputx)}letwith_assertion:('prepr->unitreprt)->('o,'u,'p)encoding->('o,'u,'p)encoding=funassertione->{ewithinput=(funx->Input.with_assertionassertion@@e.inputx)}(** Encoding combinators *)letscalar_encoding=letencodex=xinletdecodex=xinletinput=Input.scalarinletof_input=Input.to_scalarin{encode;decode;input;of_input}letbool_encoding=letencodex=xinletdecodex=xinletinput=Input.boolinletof_input=Input.to_boolin{encode;decode;input;of_input}letlist_encoding(e:_encoding)=letencodea=to_list@@List.mape.encodeainletdecodex=List.mape.decode(of_listx)inletinputa=Input.list@@List.mape.inputainletof_inputx=List.mape.of_input(Input.to_listx)in{encode;decode;input;of_input}(* Encoding for lists, where we keep the repr of the list itself, not a list
of repr *)letatomic_list_encoding:('a,'brepr,'c)encoding->('alist,'blistrepr,'clist)encoding=fune->letencodea=to_list@@List.mape.encode(of_lista)inletdecodex=to_list@@List.mape.decode(of_listx)inletinputa=Input.list@@List.mape.inputainletof_inputx=List.mape.of_input(Input.to_listx)in{encode;decode;input;of_input}letobj2_encoding(el:_encoding)(er:_encoding)=letencode(a,b)=pair(el.encodea)(er.encodeb)inletdecodep=leta,b=of_pairpin(el.decodea,er.decodeb)inletinput(a,f)=Input.pair(el.inputa)(er.inputf)inletof_inputp=leta,b=Input.to_pairpin(el.of_inputa,er.of_inputb)in{encode;decode;input;of_input}letatomic_obj2_encoding:('a,'brepr,'c)encoding->('d,'erepr,'f)encoding->('a*'d,('b*'e)repr,'c*'f)encoding=funeler->letencodep=leta,b=of_pairpinpair(el.encodea)(er.encodeb)inletdecodep=leta,b=of_pairpinpair(el.decodea)(er.decodeb)inletinput(a,f)=Input.pair(el.inputa)(er.inputf)inletof_inputp=leta,b=Input.to_pairpin(el.of_inputa,er.of_inputb)in{encode;decode;input;of_input}letobj3_encodinge0e1e2=obj2_encodinge0(obj2_encodinge1e2)letatomic_obj3_encodinge0e1e2=atomic_obj2_encodinge0(atomic_obj2_encodinge1e2)letobj4_encodinge0e1e2e3=obj2_encodinge0(obj3_encodinge1e2e3)letatomic_obj4_encodinge0e1e2e3=atomic_obj2_encodinge0(atomic_obj3_encodinge1e2e3)letobj5_encodinge0e1e2e3e4=obj2_encodinge0(obj4_encodinge1e2e3e4)letatomic_obj5_encodinge0e1e2e3e4=atomic_obj2_encodinge0(atomic_obj4_encodinge1e2e3e4)letobj6_encodinge0e1e2e3e4e5=obj2_encodinge0(obj5_encodinge1e2e3e4e5)letatomic_obj6_encodinge0e1e2e3e4e5=atomic_obj2_encodinge0(atomic_obj5_encodinge1e2e3e4e5)letobj7_encodinge0e1e2e3e4e5e6=obj2_encodinge0(obj6_encodinge1e2e3e4e5e6)letatomic_obj7_encodinge0e1e2e3e4e5e6=atomic_obj2_encodinge0(atomic_obj6_encodinge1e2e3e4e5e6)letobj8_encodinge0e1e2e3e4e5e6e7=obj2_encodinge0(obj7_encodinge1e2e3e4e5e6e7)letatomic_obj8_encodinge0e1e2e3e4e5e6e7=atomic_obj2_encodinge0(atomic_obj7_encodinge1e2e3e4e5e6e7)letobj9_encodinge0e1e2e3e4e5e6e7e8=obj2_encodinge0(obj8_encodinge1e2e3e4e5e6e7e8)letatomic_obj9_encodinge0e1e2e3e4e5e6e7e8=atomic_obj2_encodinge0(atomic_obj8_encodinge1e2e3e4e5e6e7e8)letobj10_encodinge0e1e2e3e4e5e6e7e8e9=obj2_encodinge0(obj9_encodinge1e2e3e4e5e6e7e8e9)letatomic_obj10_encodinge0e1e2e3e4e5e6e7e8e9=atomic_obj2_encodinge0(atomic_obj9_encodinge1e2e3e4e5e6e7e8e9)endend