123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2020 Nomadic Labs <contact@tezos.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. *)(* *)(*****************************************************************************)(* ------------------------------------------------------------------------- *)(* Primitives for sampling basic data *)type'asampler=Random.State.t->'a(* range (inclusive) *)typerange={min:int;max:int}letrange_encoding=letopenData_encodinginconv(fun{min;max}->(min,max))(fun(min,max)->{min;max})(obj2(req"min"int31)(req"max"int31))letsample_in_interval~range:{min;max}state=ifmax-min>=0thenmin+Random.State.intstate(max-min+1)elseinvalid_arg"Base_samplers.sample_in_interval"letsample_float_in_interval~min~maxstate=letdiff=max-.mininifdiff>0.thenmin+.Random.State.floatstatediffelseinvalid_arg"Base_samplers.sample_float_in_interval"letuniform_bool=Random.State.boolletuniform_bytestate=Char.chr(Random.State.intstate256)letuniform_partial_byte~nbitsstate=ifnbits<1||nbits>8theninvalid_arg"Base_samplers.uniform_partial_byte";leti=Random.State.intstate256inChar.chr(ilsr(8-nbits))letuniform_string~nbytesstate=String.initnbytes(fun_->uniform_bytestate)letuniform_bytes~nbytesstate=Bytes.initnbytes(fun_->uniform_bytestate)letuniform_nat~nbytesstate=Z.of_bits(uniform_stringstate~nbytes)letuniform_int~nbytesstate=letn=uniform_nat~nbytesstateinifRandom.State.boolstatethenZ.negnelsenletnat~sizestate=letnbytes=sample_in_intervalstate~range:sizeinuniform_natstate~nbytesletint~sizestate=ifsize.min<0theninvalid_arg"Base_samplers.int";letnat=natstate~sizeinlets=Random.State.boolstateinifsthennatelseZ.negnatletuniform_readable_asciistate=(* Consult the ascii table for the meaning of this. *)leti=Random.State.intstate96inifi=95then'\n'elseChar.chr(32+i)letuniform_readable_ascii_string~nbytesstate=String.initnbytes(fun_->uniform_readable_asciistate)letreadable_ascii_string~sizestate=ifsize.min<0theninvalid_arg"Base_samplers.readable_ascii_string";letnbytes=sample_in_intervalstate~range:sizeinuniform_readable_ascii_string~nbytesstateletstring~sizestate=ifsize.min<0theninvalid_arg"Base_samplers.string";letnbytes=sample_in_intervalstate~range:sizeinuniform_stringstate~nbytesletbytes~sizestate=ifsize.min<0theninvalid_arg"Base_samplers.bytes";letnbytes=sample_in_intervalstate~range:sizeinuniform_bytesstate~nbytes(* ------------------------------------------------------------------------- *)(* Sampling of "adversarial" values in the sense that they exhibit the
worst-case performance of COMPARE. *)moduleAdversarial=struct(* random string generator with a good probabiliy that sampling [n] times
will yield distinct results. *)letsalt_stringstate(n:int):unit->string=ifn<=0thenStdlib.failwith"salt_string: n <= 0";letsalt_length=2*Z.log2(Z.of_intn)infun()->uniform_stringstate~nbytes:salt_length(* random bytes generator with a good probabiliy that sampling [n] times
will yield distinct results. *)letsalt_bytesstate(n:int):unit->bytes=ifn<=0thenStdlib.failwith"salt_bytes: n <= 0";letsalt_length=2*Z.log2(Z.of_intn)infun()->uniform_bytesstate~nbytes:salt_length(* Adversarial Z.t *)letintegers~prefix_size~cardstate=ifcard<=0theninvalid_arg"Base_samplers.Adversarial.integers";ifprefix_size.min<0theninvalid_arg"Base_samplers.Adversarial.integers";letcommon_prefix=stringstate~size:prefix_sizeinletrand_suffix=salt_stringstatecardinletelements=Stdlib.List.initcard(fun_->Z.of_bits(rand_suffix()^common_prefix))in(Z.of_bitscommon_prefix,elements)(* Adversarial strings *)letstrings~prefix_size~cardstate=ifcard<=0theninvalid_arg"Base_samplers.Adversarial.strings";ifprefix_size.min<0theninvalid_arg"Base_samplers.Adversarial.strings";letcommon_prefix=stringstate~size:prefix_sizeinletrand_suffix=salt_stringstatecardinletelements=List.init~when_negative_length:()card(fun_->common_prefix^rand_suffix())|>(* see [invalid_arg] above *)WithExceptions.Result.get_ok~loc:__LOC__in(common_prefix,elements)(* Adversarial bytes *)letbytes~prefix_size~cardstate=ifcard<=0theninvalid_arg"Base_samplers.Adversarial.bytes";ifprefix_size.min<0theninvalid_arg"Base_samplers.Adversarial.bytes";letcommon_prefix=bytesstate~size:prefix_sizeinletrand_suffix=salt_bytesstatecardinletelements=List.init~when_negative_length:()card(fun_->Bytes.catcommon_prefix(rand_suffix()))|>(* see [invalid_arg] above *)WithExceptions.Result.get_ok~loc:__LOC__in(common_prefix,elements)end