123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389let[@inlinealways]char_chrch=(* Char.chr contains a branch on [ch] and a plt indirection, this
* implementation ensures well-formedness by construction and avoids that: *)Char.unsafe_chr(chland0xff)let[@inline]getxi=String.unsafe_getxi|>Char.code(* XXX(dinosaure): we use [unsafe_get] to avoid jump to exception:
sarq $1, %rbx
movzbq (%rax,%rbx), %rax
leaq 1(%rax,%rax), %rax
ret
*)externalunsafe_get_int16:string->int->int="%caml_string_get16u"let[@inline]get16xi=unsafe_get_int16xi(* XXX(dinosaure): same as [unsafe_get] but for [int16]:
sarq $1, %rbx
movzwq (%rax,%rbx), %rax
leaq 1(%rax,%rax), %rax
ret
*)letequal~lnab=letl1=lnasr1in(*
sarq $1, %rcx
orq $1, %rcx
*)letr=ref0in(*
movq $1, %rdx
*)fori=0topredl1dor:=!rlor(get16a(i*2)lxorget16b(i*2))done;(*
movq $1, %rsi
addq $-2, %rcx
cmpq %rcx, %rsi
jg .L104
.L105:
leaq -1(%rsi,%rsi), %r8
sarq $1, %r8
movzwq (%rdi,%r8), %r9
leaq 1(%r9,%r9), %r9
movzwq (%rbx,%r8), %r8
leaq 1(%r8,%r8), %r8
// [unsafe_get_int16 a i] and [unsafe_get_int6 b i]
xorq %r9, %r8
orq $1, %r8
orq %r8, %rdx
movq %rsi, %r8
addq $2, %rsi
cmpq %rcx, %r8
jne .L105
.L104:
*)for_=1tolnland1dor:=!rlor(geta(ln-1)lxorgetb(ln-1))done;(*
movq $3, %rsi
movq %rax, %rcx
andq $3, %rcx
cmpq %rcx, %rsi
jg .L102
.L103:
movq %rax, %r8
addq $-2, %r8
sarq $1, %r8
movzbq (%rdi,%r8), %r9
leaq 1(%r9,%r9), %r9
movzbq (%rbx,%r8), %r8
leaq 1(%r8,%r8), %r8
// [unsafe_get a i] and [unsafe_get b i]
xorq %r9, %r8
orq $1, %r8
orq %r8, %rdx
movq %rsi, %r8
addq $2, %rsi
cmpq %rcx, %r8
jne .L103
.L102:
*)!r=0(*
cmpq $1, %rdx
sete %al
movzbq %al, %rax
leaq 1(%rax,%rax), %rax
ret
*)letequalab=letal=String.lengthainletbl=String.lengthbinifal<>blthenfalseelseequal~ln:alablet[@inlinealways]compare(a:int)b=a-blet[@inlinealways]sixteen_if_minus_one_or_lessn=(nasrSys.int_size)land16let[@inlinealways]eight_if_one_or_moren=((-n)asrSys.int_size)land8letcompare_le~lnab=letr=ref0inleti=ref(predln)inwhile!i>=0doletxa=geta!iandxb=getb!iinletc=comparexaxbinr:=!rlor((sixteen_if_minus_one_or_lessc+eight_if_one_or_morec)lsr!r);decri;done;(!rland8)-(!rland16)letcompare_le_with_len~len:lnab=letal=String.lengthainletbl=String.lengthbinifln=0then0elseif(allxorln)lor(bllxorln)<>0theninvalid_arg"compare_le_with_len"elsecompare_le~lnabletcompare_leab=letal=String.lengthainletbl=String.lengthbinifal<blthen1elseifal>blthen(-1)elsecompare_le~ln:al(* = bl *)abletcompare_be~lnab=letr=ref0inleti=ref0inwhile!i<lndoletxa=geta!iandxb=getb!iinletc=comparexaxbinr:=!rlor((sixteen_if_minus_one_or_lessc+eight_if_one_or_morec)lsr!r);incri;done;(!rland8)-(!rland16)letcompare_be_with_len~len:lnab=letal=String.lengthainletbl=String.lengthbinifln=0then0elseif(allxorln)lor(bllxorln)<>0theninvalid_arg"compare_be_with_len"elsecompare_be~lnabletcompare_beab=letal=String.lengthainletbl=String.lengthbinifal<blthen1elseifal>blthen(-1)elsecompare_be~ln:al(* = bl *)ablet[@inlinealways]minus_one_or_lessn=nlsr(Sys.int_size-1)let[@inlinealways]one_if_not_zeron=minus_one_or_less((-n)lorn)let[@inlinealways]zero_if_not_zeron=(one_if_not_zeron)-1let[@inlinealways]select_intchoose_bab=letmask=((-choose_b)lorchoose_b)asrSys.int_sizein(aland(lnotmask))lor(blandmask)externalint_of_bool:bool->int="%identity"externalunsafe_bool_of_int:int->bool="%identity"let[@inline]bool_of_intn=unsafe_bool_of_int(one_if_not_zeron)let[@inlinealways]find_uint8~off~len~fstr=leti=ref(len-1)inleta=ref(lnot0)inwhile!i>=offdoletbyte=getstr!iinletpred=int_of_bool(fbyte)in(* XXX(dinosaure): a composition of [f] with [bool_of_int] such as
[let f = bool_of_int <.> f in] implies an allocation (of a closure).
To be GC-free, we must store result of [f] into a register, and apply
[bool_of_int] then (introspection was done on OCaml 4.08.1). *)a:=select_int(((!i-off)landmin_int)lorpred)!a!i;decri;done;!aletfind_uint8?(off=0)~fstr=(* XXX(dinosaure): with this overload, OCaml is able to produce 2 [find_uint8].
One with [off= 0] and one other where [off] is an argument. I think it's about
cross-module optimization where a call to [find_uint8 ~f v] will directly call
the first one and a call to [find_uint8 ~off:x ~f v] will call the second one. *)letlen=String.lengthstrinfind_uint8~off~len~fstrletexists_uint8?off~fstr=letv=find_uint8?off~fstrinletr=select_int(v+1)01inunsafe_bool_of_intrletdivmod~(x:int32)~(m:int32):int32*int32=(* Division and remainder being constant-time with respect to [x]
* ( NOT [m] !). The OCaml variant would be:
* [(x / m , x mod m)] where [x] is a secret and [m] is not secret.
* Adapted from the NTRU Prime team's algorithm from
* supercop/crypto_kem/sntrup761/ref/uint32.c
* cite the round-2 ntru prime submission to nistpqc (march 2019)
* Note that in practice this works for at least some much larger [x] and [m],
* but it's unclear to me how to evaluate *which*, so leaving the original
* restrictions in.
*)let(-),(+),(*)=Int32.(sub,add,mul)inlet(>>)=Int32.shift_right_logicalinif(m<=0l)thenraise(Invalid_argument"m <= 0");if(m>=16348l)thenraise(Invalid_argument"m >= 16348 not supported");letof_uint32uint=(* apparently Int64.of_int32 sign-extends ... great... avoid that: *)letb=Bytes.make8'\x00'inUnsafe.set_int32_leb0uint;Unsafe.get_int64_leb0inletx_0=xinletx_2,q_1=letint32_div_unsignednd=(* can be replaced by Int32.unsigned_div
* from OCaml >= 4.10 *)letsub,min_int=Int32.(sub,min_int)inletint32_unsigned_comparenm=Int32.compare(subnmin_int)(submmin_int)inifd<0_lthenifint32_unsigned_comparend<0then0_lelse1_lelseletq=letopenInt32inshift_left(Int32.div(Int32.shift_right_logicaln1)d)1inletr=subn(Int32.mulqd)inifint32_unsigned_comparerd>=0thenInt32.succqelseqinletv=int32_div_unsignedInt32.min_intm|>of_uint32in(*let v = 0x80_00_00_00 / m in*)(* floored div *)letx_1,q_0=letqpart_0=letopenInt64inshift_right_logical(mul(of_uint32x_0)v)31|>to_int32inx_0-(qpart_0*m),qpart_0inletqpart_1=letopenInt64inshift_right_logical(mul(of_uint32x_1)v)31|>to_int32inx_1-(qpart_1*m),(q_0+qpart_1+1l)inletx_3=x_2-minletmask=0l-(x_3>>31)inq_1+mask,x_3+(Int32.logandmaskm)letascii_of_int32~digits(n:int32):string=(* Recursively calls [divmod n 10]; the remainder is turned into ASCII
and the quotient is used for the next division.*)ifdigits<0thenraise(Invalid_argument"digits < 0");letout=Bytes.makedigits'0'inletrecloopx=function|-1->Bytes.unsafe_to_stringout|idx->letnext,this=divmod~x~m:10linBytes.setoutidx@@char_chr(0x30lor(Int32.to_intthis));loopnext(predidx)inloopn(preddigits)let[@inlinealways]to_hex_nibblef:char=leta=86+finletc=1+((a-71*((aland0x10)lsr4))lor0x20)inchar_chrclethex_of_stringrawbytes=String.init(2*String.lengthrawbytes)(funidx->letbyt=String.getrawbytes(idxlsr1)|>Char.codein(* select which 4 bits to use, this can probably be done faster:*)letnib=0xfland(bytlsr(((lnotidx)land1)lsl2))into_hex_nibblenib)lethex_of_bytesrawbytes=hex_of_string(Bytes.unsafe_to_stringrawbytes)let[@inlinealways]select_a_if_in_range~low~high~nab=(* select [a] if [low <= n <= high] and [b] if [n] is out of range.*)(* NB: ONLY WORKS FOR [0 <= low <= high <= max_int]*)(* The idea being that:
1.a) if low <= n : (n - low) is positive +
1.b) if low > n : (n - low) is negative -
2.a) if n <= high: (high - n) is positive +
2.b) if n > high: (high - n) is negative -
We OR the numbers together; we only really care about the sign bit
which is set when negative.
Thus both numbers are positive iff (low <= n && n <= high).
We then select the sign bit with (land min_int) and use that to choose:
*)letout_of_range=(* choose b if out of range *)((n-low)lor(high-n)landmin_int)inselect_intout_of_rangeabletlowercase_asciisrc=(* ct version of String.lowercase_ascii *)String.map(funch->letn=Char.codechin(* 0x41 is 'A'; 0x5a is 'Z'; 0x20 controls case for ASCII letters *)select_a_if_in_range~low:0x41~high:0x5a~n(nlor0x20)(n)|>char_chr)srcletuppercase_asciisrc=(* ct version of String.uppercase_ascii *)String.map(funch->letn=Char.codechin(* 0x61 is 'a'; 0x7a is 'z'; 0x20 controls case for ASCII letters *)select_a_if_in_range~low:0x61~high:0x7a~n(nlxor0x20)(n)|>char_chr)srcletbytes_of_hexrawhex=(* hex length must be multiple of 2: *)leterror_bitmap=ref((String.lengthrawhexland1)lsl4)inletdecoded=Bytes.init(String.lengthrawhexlsr1)(funidx->letidx=idxlsl1inletnibidx=String.getrawhexidx|>Char.code|>funn->(* uppercase -> lowercase: *)select_a_if_in_range~low:0x41~high:0x5a~n(nlor0x20)(* set case bit *)n(* leave as-is *)|>funn->(* now either invalid; lowercase; numeric*)(select_a_if_in_range~low:0x30~high:0x39~n(n-0x30)(* numeric: subtract '0' to get [0..9] *)(select_a_if_in_range~low:0x61~high:0x66~n(* a-f: subtract 'a' and add 10 to get [10..15]: *)(n-0x61+10)(0xff)(* invalid, ensure we set upper bits of error_bitmap *)))inletnibf0=nibidxandnib0f=nib(succidx)inerror_bitmap:=!error_bitmaplornibf0lornib0f;char_chr((nibf0lsl4)lornib0f))in(* if any non-nibble bits were set in !error_bitmap, decoding failed: *)decoded,!error_bitmapland(lnot0xf)letstring_of_hexrawhex=letbyt,error=bytes_of_hexrawhexinBytes.unsafe_to_stringbyt,error