188 lines
5.6 KiB
OCaml
188 lines
5.6 KiB
OCaml
|
(**************************************************************************)
|
||
|
(* *)
|
||
|
(* Copyright (c) 2014 - 2018. *)
|
||
|
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
|
||
|
(* *)
|
||
|
(* All rights reserved. No warranty, explicit or implicit, provided. *)
|
||
|
(* *)
|
||
|
(**************************************************************************)
|
||
|
|
||
|
open Tezos_crypto
|
||
|
open Error_monad
|
||
|
|
||
|
module Extend(H : Tezos_crypto.S.HASH) = struct
|
||
|
|
||
|
include H
|
||
|
|
||
|
let encoding =
|
||
|
let open Data_encoding in
|
||
|
splitted
|
||
|
~binary:
|
||
|
(conv H.to_bytes H.of_bytes_exn (Fixed.bytes H.size))
|
||
|
~json:
|
||
|
(describe ~title: (H.title ^ " (Base58Check-encoded Blake2B hash)") @@
|
||
|
conv H.to_b58check (Data_encoding.Json.wrap_error H.of_b58check_exn) string)
|
||
|
|
||
|
let of_b58check s =
|
||
|
match H.of_b58check_opt s with
|
||
|
| Some x -> Ok x
|
||
|
| None ->
|
||
|
generic_error "Failed to read a base58-encoded hash (%s)" H.name
|
||
|
|
||
|
let of_bytes s =
|
||
|
match H.of_bytes_opt s with
|
||
|
| Some x -> Ok x
|
||
|
| None ->
|
||
|
generic_error "Failed to deserialize a hash (%s)" H.name
|
||
|
|
||
|
let rpc_arg =
|
||
|
RPC_arg.make
|
||
|
~name:(Format.asprintf "hash.%s" H.name)
|
||
|
~descr:(Format.asprintf "A b58check-encoded hash (%s)" H.name)
|
||
|
~destruct:
|
||
|
(fun s ->
|
||
|
match H.of_b58check_opt s with
|
||
|
| None ->
|
||
|
Error (Format.asprintf
|
||
|
"failed to decode b58check-encoded hash (%s): %S"
|
||
|
H.name s)
|
||
|
| Some v -> Ok v)
|
||
|
~construct:H.to_b58check
|
||
|
()
|
||
|
|
||
|
let param ?(name=H.name) ?(desc=H.title) t =
|
||
|
Cli_entries.param
|
||
|
~name
|
||
|
~desc (Cli_entries.parameter (fun _ str -> Lwt.return (of_b58check str))) t
|
||
|
|
||
|
module Set = struct
|
||
|
include Set.Make(struct type nonrec t = t let compare = compare end)
|
||
|
exception Found of elt
|
||
|
let random_elt s =
|
||
|
let n = Random.int (cardinal s) in
|
||
|
try
|
||
|
ignore
|
||
|
(fold (fun x i -> if i = n then raise (Found x) ; i+1) s 0 : int) ;
|
||
|
assert false
|
||
|
with Found x -> x
|
||
|
let encoding =
|
||
|
Data_encoding.conv
|
||
|
elements
|
||
|
(fun l -> List.fold_left (fun m x -> add x m) empty l)
|
||
|
Data_encoding.(list encoding)
|
||
|
end
|
||
|
|
||
|
module Table = struct
|
||
|
include Hashtbl.Make(struct
|
||
|
type t = H.t
|
||
|
let hash =
|
||
|
if H.size >= 64 then
|
||
|
fun h -> Int64.to_int (MBytes.get_int64 (H.to_bytes h) 0)
|
||
|
else if H.size >= 32 then
|
||
|
fun h -> Int32.to_int (MBytes.get_int32 (H.to_bytes h) 0)
|
||
|
else
|
||
|
fun h ->
|
||
|
let r = ref 0 in
|
||
|
let h = H.to_bytes h in
|
||
|
for i = 0 to H.size / 8 - 1 do
|
||
|
r := MBytes.get_uint8 h i + 8 * !r
|
||
|
done ;
|
||
|
!r
|
||
|
let equal = H.equal
|
||
|
end)
|
||
|
let encoding arg_encoding =
|
||
|
Data_encoding.conv
|
||
|
(fun h -> fold (fun k v l -> (k, v) :: l) h [])
|
||
|
(fun l ->
|
||
|
let h = create (List.length l) in
|
||
|
List.iter (fun (k,v) -> add h k v) l ;
|
||
|
h)
|
||
|
Data_encoding.(list (tup2 encoding arg_encoding))
|
||
|
end
|
||
|
|
||
|
module Map = struct
|
||
|
include Map.Make(struct type nonrec t = t let compare = compare end)
|
||
|
let encoding arg_encoding =
|
||
|
Data_encoding.conv
|
||
|
bindings
|
||
|
(fun l -> List.fold_left (fun m (k,v) -> add k v m) empty l)
|
||
|
Data_encoding.(list (tup2 encoding arg_encoding))
|
||
|
end
|
||
|
|
||
|
end
|
||
|
|
||
|
module Extend_merkle_tree(H : Tezos_crypto.S.MERKLE_TREE) = struct
|
||
|
|
||
|
include Extend(H)
|
||
|
|
||
|
type elt = H.elt
|
||
|
let elt_bytes = H.elt_bytes
|
||
|
|
||
|
let empty = hash_bytes []
|
||
|
|
||
|
include Tezos_crypto.Blake2B.Generic_Merkle_tree(struct
|
||
|
type nonrec t = t
|
||
|
type nonrec elt = elt
|
||
|
let empty = empty
|
||
|
let leaf x = hash_bytes [H.elt_bytes x]
|
||
|
let node x y = hash_bytes [to_bytes x; to_bytes y]
|
||
|
end)
|
||
|
|
||
|
let path_encoding =
|
||
|
let open Data_encoding in
|
||
|
mu "path"
|
||
|
(fun path_encoding ->
|
||
|
union [
|
||
|
case (Tag 240)
|
||
|
(obj2
|
||
|
(req "path" path_encoding)
|
||
|
(req "right" encoding))
|
||
|
(function Left (p, r) -> Some (p, r) | _ -> None)
|
||
|
(fun (p, r) -> Left (p, r)) ;
|
||
|
case (Tag 15)
|
||
|
(obj2
|
||
|
(req "left" encoding)
|
||
|
(req "path" path_encoding))
|
||
|
(function Right (r, p) -> Some (r, p) | _ -> None)
|
||
|
(fun (r, p) -> Right (r, p)) ;
|
||
|
case (Tag 0)
|
||
|
unit
|
||
|
(function Op -> Some () | _ -> None)
|
||
|
(fun () -> Op)
|
||
|
])
|
||
|
|
||
|
end
|
||
|
|
||
|
module type Name = Blake2B.Name
|
||
|
module type PrefixedName = Blake2B.PrefixedName
|
||
|
module Make_minimal = Blake2B.Make_minimal
|
||
|
module Make
|
||
|
(R : sig
|
||
|
val register_encoding:
|
||
|
prefix: string ->
|
||
|
length:int ->
|
||
|
to_raw: ('a -> string) ->
|
||
|
of_raw: (string -> 'a option) ->
|
||
|
wrap: ('a -> Base58.data) ->
|
||
|
'a Base58.encoding
|
||
|
end)
|
||
|
(K : Blake2B.PrefixedName) =
|
||
|
Extend(Blake2B.Make(R)(K))
|
||
|
module Make_merkle_tree
|
||
|
(R : sig
|
||
|
val register_encoding:
|
||
|
prefix: string ->
|
||
|
length:int ->
|
||
|
to_raw: ('a -> string) ->
|
||
|
of_raw: (string -> 'a option) ->
|
||
|
wrap: ('a -> Base58.data) ->
|
||
|
'a Base58.encoding
|
||
|
end)
|
||
|
(K : PrefixedName)
|
||
|
(Contents: sig
|
||
|
type t
|
||
|
val to_bytes: t -> MBytes.t
|
||
|
end) =
|
||
|
Extend_merkle_tree(Blake2B.Make_merkle_tree(R)(K)(Contents))
|
||
|
module Generic_Merkle_tree = Blake2B.Generic_Merkle_tree
|