123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204(*****************************************************************************)(* *)(* 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. *)(* *)(*****************************************************************************)openBytesletbytes_and=logandletbytes_or=logorletbytes_xor=logxorletbytes_not=lognotletbytes_lslan=(* We have to limit the number of shifts for LSL *)matchScript_int.to_intnwith|SomenwhenCompare.Int.(n<=64000)->Some(shift_leftan)|_->Noneletbytes_lsran=(* No limit on the number of shifts for LSR *)matchScript_int.to_intnwith|None->(* [LSR bytes max_int] can shift out completely the longest
possible [bytes]. *)Bytes.empty|Somen->shift_rightanmoduleConversion_BE:sig(** Convert a natural number to bytes using big-endian encoding.
Returns [None] when the argument is negative.
Examples:
- [bytes_of_nat_be (Z.of_int 0x00) = Some Bytes.empty]
- [bytes_of_nat_be (Z.of_int 0x01) = Some (Bytes.of_string "\x01")]
- [bytes_of_nat_be (Z.of_int 0xff) = Some (Bytes.of_string "\xff")]
- [bytes_of_nat_be (Z.of_int 0x100) = Some (Bytes.of_strnig "\x01\x00")]
- [bytes_of_nat_be (Z.of_int (-1)) = None]
*)valbytes_of_nat_be:Z.t->bytesoption(** Convert bytes to a natural number using big-endian encoding.
Examples:
- [nat_of_bytes_be Bytes.empty = Z.of_int 0x00]
- [nat_of_bytes_be (Bytes.of_string "\x00") = Z.of_int 0x00]
- [nat_of_bytes_be (Bytes.of_string "\x01") = Z.of_int 0x01]
- [nat_of_bytes_be (Bytes.of_string "\x00\x01") = Z.of_int 0x01]
- [nat_of_bytes_be (Bytes.of_string "\xff") = Z.of_int 0xff]
- [nat_of_bytes_be (Bytes.of_string "\x00\x00\xff") = Z.of_int 0xff]
- [nat_of_bytes_be (Bytes.of_string "\x01\x00") = Z.of_int 0x0100]
*)valnat_of_bytes_be:bytes->Z.t(** Convert an integer to bytes using big-endian encoding.
Negative numbers are handled by two's-complement.
Examples:
- [bytes_of_int_be (Z.of_int 0x00) = Bytes.empty]
- [bytes_of_int_be (Z.of_int 0x01) = Bytes.of_string "\x01"]
- [bytes_of_int_be (Z.of_int 0x7f) = Bytes.of_string "\x7f"]
- [bytes_of_int_be (Z.of_int (-0x80)) = Bytes.of_string "\x80"]
- [bytes_of_int_be (Z.of_int 0x80) = Bytes.of_string "\x00\x80"] (not ["\x80"])
- [bytes_of_int_be (Z.of_int (-0x81)) = Bytes.of_string "\xff\x7f"] (not ["\x7f"])
- [bytes_of_int_be (Z.of_int 0x8000) = Bytes.of_string "\x00\x80\x00"], (not ["\x80\x00"])
*)valbytes_of_int_be:Z.t->bytes(** Convert bytes to an integer using big-endian encoding.
Negative numbers are handled by two's-complement.
Examples:
- [int_of_bytes_be Bytes.empty = Z.of_int 0x00]
- [int_of_bytes_be (Bytes.of_string "\x01") = Z.of_int 0x01]
- [int_of_bytes_be (Bytes.of_string "\x00\x01") = Z.of_int 0x01]
- [int_of_bytes_be (Bytes.of_string "\x7f") = Z.of_int 0x7f]
- [int_of_bytes_be (Bytes.of_string "\x00\x7f") = Z.of_int 0x7f]
- [int_of_bytes_be (Bytes.of_string "\x80") = Z.of_int (-0x80)] (not [0x80])
- [int_of_bytes_be (Bytes.of_string "\xff\x80") = Z.of_int (-0x80)]
- [int_of_bytes_be (Bytes.of_string "\xff\x8f") = Z.of_int (-0x81)]
*)valint_of_bytes_be:bytes->Z.tend=structletencode_nat_benbytesdefaultz=(* [nbytes] is the exact number of the bytes to encode [z].
When encoding an integer to bytes, it is first converted to
a natural number using 2's complement, and then sent to this function.
[default] is the prefix byte which may be required for the integer
encoding. [Some '\000'] when the integer is zero or positive.
[Some '\255'] when negative.
*)assert(Compare.Z.(z>=Z.zero));(* [Z.to_bits] encodes zero and positive numbers in the little endian.
The result string can be zero trailed to make its length multiple
of 4 or 8.
*)letstring_le=Z.to_bitszinletslen=String.lengthstring_lein(* If [slen = nbytes]:
string_le aabbcc
the final output ccbbaa
else if [slen > nbytes]:
string_le aabbcc0000
the final output ccbbaa
else if [slen < nbytes] and [default= Some DD]:
This is to encode an integer which requires an extra byte.
string_le aabbcc
encoded DDccbbaa
otherwise: error, which should not happen.
*)Bytes.initnbytes(funi->letj=nbytes-i-1inifCompare.Int.(j>=slen)thenOption.value_fdefault~default:(fun()->assertfalse(* it never happens *))elsestring_le.[j])letbytes_of_nat_bez=matchZ.comparezZ.zerowith|-1->None|0->SomeBytes.empty|_->letnbits=Z.log2up(Z.succz)inletnbytes=(nbits+7)/8inSome(encode_nat_benbytesNonez)letbytes_of_int_bez=matchZ.comparezZ.zerowith|0->Bytes.empty|1->letnbits=Z.log2up(Z.succz)+1(* The top bit must be 0 *)inletnbytes=(nbits+7)/8inencode_nat_benbytes(Some'\000')z|_->letnbits=Z.log2upZ.(negz)+1(* The top bit must be 1 *)inletnbytes=(nbits+7)/8inletnbits'=nbytes*8inletz''=Z.(add(shift_leftonenbits')z)inencode_nat_benbytes(Some'\255')z''letnat_of_bytes_bebytes=(* [Z.of_bits] ignores trailing zeros *)letlen=Bytes.lengthbytesin(* Z.of_bits uses little-endian encoding but we want a big-endian
encoding so we reverse [bytes] while converting it to `string`. *)Z.of_bits@@String.initlen(funi->Bytes.getbytes(len-i-1))letint_of_bytes_bebytes=letnbytes=Bytes.lengthbytesinifCompare.Int.(nbytes=0)thenZ.zeroelselettop_bit=Compare.Int.(Char.code(Bytes.getbytes0)land128<>0)iniftop_bitthen(* negative *)letz=nat_of_bytes_bebytesinletnbits=nbytes*8inZ.(subz(shift_leftonenbits))elsenat_of_bytes_bebytesendopenScript_intletbytes_of_nat_be(n:nnum)=(* The function always succeeds since the argument is 0 or positive *)matchConversion_BE.bytes_of_nat_be@@to_zintnwith|Somebytes->bytes|None->assertfalseletnat_of_bytes_beb=abs@@of_zint@@Conversion_BE.nat_of_bytes_bebletbytes_of_int_be(z:znum)=Conversion_BE.bytes_of_int_be@@to_zintzletint_of_bytes_beb=of_zint@@Conversion_BE.int_of_bytes_beb