135 lines
4.8 KiB
OCaml
135 lines
4.8 KiB
OCaml
(*****************************************************************************)
|
|
(* *)
|
|
(* Open Source License *)
|
|
(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. <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. *)
|
|
(* *)
|
|
(*****************************************************************************)
|
|
|
|
(* Tezos Protocol Implementation - Random number generation *)
|
|
|
|
type seed = B of State_hash.t
|
|
|
|
type t = T of State_hash.t
|
|
|
|
type sequence = S of State_hash.t
|
|
|
|
type nonce = MBytes.t
|
|
|
|
let nonce_encoding = Data_encoding.Fixed.bytes Constants_repr.nonce_length
|
|
|
|
let init = "Laissez-faire les proprietaires."
|
|
|
|
let zero_bytes = MBytes.of_string (String.make Nonce_hash.size '\000')
|
|
|
|
let state_hash_encoding =
|
|
let open Data_encoding in
|
|
conv
|
|
State_hash.to_bytes
|
|
State_hash.of_bytes_exn
|
|
(Fixed.bytes Nonce_hash.size)
|
|
|
|
let seed_encoding =
|
|
let open Data_encoding in
|
|
conv (fun (B b) -> b) (fun b -> B b) state_hash_encoding
|
|
|
|
let empty = B (State_hash.hash_bytes [MBytes.of_string init])
|
|
|
|
let nonce (B state) nonce =
|
|
B (State_hash.hash_bytes [State_hash.to_bytes state; nonce])
|
|
|
|
let initialize_new (B state) append =
|
|
T (State_hash.hash_bytes (State_hash.to_bytes state :: zero_bytes :: append))
|
|
|
|
let xor_higher_bits i b =
|
|
let higher = MBytes.get_int32 b 0 in
|
|
let r = Int32.logxor higher i in
|
|
let res = MBytes.copy b in
|
|
MBytes.set_int32 res 0 r ; res
|
|
|
|
let sequence (T state) n =
|
|
State_hash.to_bytes state |> xor_higher_bits n
|
|
|> fun b -> S (State_hash.hash_bytes [b])
|
|
|
|
let take (S state) =
|
|
let b = State_hash.to_bytes state in
|
|
let h = State_hash.hash_bytes [b] in
|
|
(State_hash.to_bytes h, S h)
|
|
|
|
let take_int32 s bound =
|
|
if Compare.Int32.(bound <= 0l) then invalid_arg "Seed_repr.take_int32"
|
|
(* FIXME *)
|
|
else
|
|
let rec loop s =
|
|
let (bytes, s) = take s in
|
|
let r = Int32.abs (MBytes.get_int32 bytes 0) in
|
|
let drop_if_over =
|
|
Int32.sub Int32.max_int (Int32.rem Int32.max_int bound)
|
|
in
|
|
if Compare.Int32.(r >= drop_if_over) then loop s
|
|
else
|
|
let v = Int32.rem r bound in
|
|
(v, s)
|
|
in
|
|
loop s
|
|
|
|
type error += Unexpected_nonce_length (* `Permanent *)
|
|
|
|
let () =
|
|
register_error_kind
|
|
`Permanent
|
|
~id:"unexpected_nonce_length"
|
|
~title:"Unexpected nonce length"
|
|
~description:"Nonce length is incorrect."
|
|
~pp:(fun ppf () ->
|
|
Format.fprintf
|
|
ppf
|
|
"Nonce length is not %i bytes long as it should."
|
|
Constants_repr.nonce_length)
|
|
Data_encoding.empty
|
|
(function Unexpected_nonce_length -> Some () | _ -> None)
|
|
(fun () -> Unexpected_nonce_length)
|
|
|
|
let make_nonce nonce =
|
|
if Compare.Int.(MBytes.length nonce <> Constants_repr.nonce_length) then
|
|
error Unexpected_nonce_length
|
|
else ok nonce
|
|
|
|
let hash nonce = Nonce_hash.hash_bytes [nonce]
|
|
|
|
let check_hash nonce hash =
|
|
Compare.Int.(MBytes.length nonce = Constants_repr.nonce_length)
|
|
&& Nonce_hash.equal (Nonce_hash.hash_bytes [nonce]) hash
|
|
|
|
let nonce_hash_key_part = Nonce_hash.to_path
|
|
|
|
let initial_nonce_0 = zero_bytes
|
|
|
|
let initial_nonce_hash_0 = hash initial_nonce_0
|
|
|
|
let deterministic_seed seed = nonce seed zero_bytes
|
|
|
|
let initial_seeds n =
|
|
let rec loop acc elt i =
|
|
if Compare.Int.(i = 1) then List.rev (elt :: acc)
|
|
else loop (elt :: acc) (deterministic_seed elt) (i - 1)
|
|
in
|
|
loop [] (B (State_hash.hash_bytes [])) n
|