From dc0061c5d9756fade88c251a075dc311baf4ba29 Mon Sep 17 00:00:00 2001 From: Eitan Chatav Date: Thu, 3 Nov 2016 11:15:31 -0700 Subject: [PATCH 01/12] crypto box initial utility functions for encrypted communication using crypto box (X25519/XSalsa20-Poly1305) --- src/Makefile | 2 ++ src/utils/crypto_box.ml | 21 +++++++++++++++++++++ src/utils/crypto_box.mli | 20 ++++++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 src/utils/crypto_box.ml create mode 100644 src/utils/crypto_box.mli diff --git a/src/Makefile b/src/Makefile index 5425b524f..7e36cde65 100644 --- a/src/Makefile +++ b/src/Makefile @@ -106,6 +106,7 @@ UTILS_LIB_INTFS := \ utils/hex_encode.mli \ utils/utils.mli \ utils/cli_entries.mli \ + utils/crypto_box.mli \ utils/compare.mli \ utils/data_encoding.mli \ utils/time.mli \ @@ -123,6 +124,7 @@ UTILS_LIB_IMPLS := \ utils/utils.ml \ utils/cli_entries.ml \ utils/compare.ml \ + utils/crypto_box.ml \ utils/data_encoding.ml \ utils/time.ml \ utils/hash.ml \ diff --git a/src/utils/crypto_box.ml b/src/utils/crypto_box.ml new file mode 100644 index 000000000..f633f851c --- /dev/null +++ b/src/utils/crypto_box.ml @@ -0,0 +1,21 @@ +(**************************************************************************) +(* *) +(* Copyright (c) 2014 - 2016. *) +(* Dynamic Ledger Solutions, Inc. *) +(* *) +(* All rights reserved. No warranty, explicit or implicit, provided. *) +(* *) +(**************************************************************************) + +(** Tezos - X25519/XSalsa20-Poly1305 cryptography *) + +type secret_key = Sodium.Box.secret_key +type public_key = Sodium.Box.public_key +type channel_key = Sodium.Box.channel_key +type nonce = Sodium.Box.nonce + +let random_keypair = Sodium.Box.random_keypair +let random_nonce = Sodium.Box.random_nonce +let increment_nonce = Sodium.Box.increment_nonce +let box = Sodium.Box.Bigbytes.box +let box_open = Sodium.Box.Bigbytes.box_open diff --git a/src/utils/crypto_box.mli b/src/utils/crypto_box.mli new file mode 100644 index 000000000..1df44ea44 --- /dev/null +++ b/src/utils/crypto_box.mli @@ -0,0 +1,20 @@ +(**************************************************************************) +(* *) +(* Copyright (c) 2014 - 2016. *) +(* Dynamic Ledger Solutions, Inc. *) +(* *) +(* All rights reserved. No warranty, explicit or implicit, provided. *) +(* *) +(**************************************************************************) + +(** Tezos - X25519/XSalsa20-Poly1305 cryptography *) + +type secret_key +type public_key +type nonce + +val random_keypair : unit -> secret_key * public_key +val random_nonce : unit -> nonce +val increment_nonce : ?step:int -> nonce -> nonce +val box : secret_key -> public_key -> MBytes.t -> nonce -> MBytes.t +val box_open : secret_key -> public_key -> MBytes.t -> nonce -> MBytes.t From 438281f1e1dc61bdf4006f8014701c90f1887f04 Mon Sep 17 00:00:00 2001 From: Eitan Chatav Date: Fri, 4 Nov 2016 12:07:03 -0700 Subject: [PATCH 02/12] include a public key in peer record type * include a public key in peer record type * include public key in `Connect` packet * receive/send public keys in `Connect` packet * include public key in `connect_to_peer` * json encode/decode public key * include public key in peer file encode/decode * include public key in bootstrapping --- src/node/net/p2p.ml | 59 ++++++++++++++++++++++++---------------- src/utils/crypto_box.ml | 2 ++ src/utils/crypto_box.mli | 2 ++ 3 files changed, 40 insertions(+), 23 deletions(-) diff --git a/src/node/net/p2p.ml b/src/node/net/p2p.ml index 6ed796845..f19af5cfc 100644 --- a/src/node/net/p2p.ml +++ b/src/node/net/p2p.ml @@ -66,7 +66,7 @@ type point = addr * port not a real kind of packet, it means that something indecypherable was transmitted. *) type packet = - | Connect of gid * int option * version list + | Connect of gid * Crypto_box.public_key * int option * version list | Disconnect | Advertise of (addr * port) list | Message of Netbits.frame @@ -96,12 +96,12 @@ let recv_packet | [ S 2 ] -> return Ping | [ S 12 ] -> return Pong | [ S 3 ] -> return Bootstrap - | [ S 4 ; B gid ; S port ; F rest ] as msg -> + | [ S 4 ; B gid ; B public_key ; S port ; F rest ] as msg -> decode_versions msg rest @@ fun versions -> - return (Connect (MBytes.to_string gid, Some port, versions)) - | [ S 4 ; B gid ; F rest ] as msg -> + return (Connect (MBytes.to_string gid, Crypto_box.to_public_key public_key, Some port, versions)) + | [ S 4 ; B gid ; B public_key ; F rest ] as msg -> decode_versions msg rest @@ fun versions -> - return (Connect (MBytes.to_string gid, None, versions)) + return (Connect (MBytes.to_string gid, Crypto_box.to_public_key public_key, None, versions)) | [ S 5 ; F rest ] as msg -> let rec decode_peers acc = function | F [ B addr ; S port ] :: rest -> begin @@ -127,14 +127,14 @@ let send_packet | Ping -> [ S 2 ] | Pong -> [ S 12 ] | Bootstrap -> [ S 3 ] - | Connect (gid, port, versions) -> + | Connect (gid, public_key, port, versions) -> let rec encode = function | (name, maj, min) :: tl -> let rest = encode tl in F [ B (MBytes.of_string name) ; S maj ; S min ] :: rest | [] -> [] in - [ S 4 ; B (MBytes.of_string gid) ] + [ S 4 ; B (MBytes.of_string gid) ; B (Crypto_box.of_public_key public_key) ] @ (match port with | Some port -> [ S port ] | None -> []) @ [ F (encode versions) ] | Advertise peers -> @@ -170,6 +170,7 @@ type net = { workers (on shutdown of during maintenance). *) and peer = { gid : gid ; + public_key : Crypto_box.public_key ; point : point ; listening_port : port option ; version : version ; @@ -282,7 +283,7 @@ end function for communicating with the main worker using events (including the one sent when the connection is alive). Returns a canceler. *) -let connect_to_peer config limits my_gid socket (addr, port) push white_listed = +let connect_to_peer config limits my_gid my_public_key socket (addr, port) push white_listed = (* a non exception-based cancelation mechanism *) let cancelation, cancel, on_cancel = canceler () in (* a cancelable reception *) @@ -294,11 +295,12 @@ let connect_to_peer config limits my_gid socket (addr, port) push white_listed = connection, both parties must first present themselves. *) let rec connect () = send_packet socket (Connect (my_gid, + my_public_key, config.incoming_port, config.supported_versions)) >>= fun _ -> pick [ (LU.sleep limits.peer_answer_timeout >>= fun () -> return Disconnect) ; recv () ] >>= function - | Connect (gid, listening_port, versions) -> + | Connect (gid, public_key , listening_port, versions) -> debug "(%a) connection requested from %a @ %a:%d" pp_gid my_gid pp_gid gid Ipaddr.pp_hum addr port ; begin match common_version config.supported_versions versions with @@ -310,7 +312,7 @@ let connect_to_peer config limits my_gid socket (addr, port) push white_listed = if config.closed_network then match listening_port with | Some port when white_listed (addr, port) -> - connected version gid listening_port + connected version gid public_key listening_port | Some port -> debug "(%a) connection rejected (out of the closed network) from %a:%d" pp_gid my_gid Ipaddr.pp_hum addr port ; @@ -320,7 +322,7 @@ let connect_to_peer config limits my_gid socket (addr, port) push white_listed = pp_gid my_gid Ipaddr.pp_hum addr ; cancel () else - connected version gid listening_port + connected version gid public_key listening_port end | Advertise peers -> (* alternatively, one can refuse a connection but reply with @@ -338,7 +340,7 @@ let connect_to_peer config limits my_gid socket (addr, port) push white_listed = pp_gid my_gid Ipaddr.pp_hum addr port ; cancel () (* Them we can build the net object and launch the worker. *) - and connected version gid listening_port = + and connected version gid public_key listening_port = (* net object state *) let last = ref (Unix.gettimeofday ()) in (* net object callbaks *) @@ -346,7 +348,7 @@ let connect_to_peer config limits my_gid socket (addr, port) push white_listed = let disconnect () = cancel () in let send p = send_packet socket p >>= fun _ -> return () in (* net object construction *) - let peer = { gid ; point = (addr, port) ; listening_port ; + let peer = { gid ; public_key ; point = (addr, port) ; listening_port ; version ; last_seen ; disconnect ; send } in (* The packet reception loop. *) let rec receiver () = @@ -429,10 +431,18 @@ let addr_encoding = (fun b -> Ipaddr.(V6 (V6.of_bytes_exn b))) ; ]) +let public_key_encoding = + let open Data_encoding in + conv + (fun public_key -> MBytes.to_string (Crypto_box.of_public_key public_key)) + (fun str -> Crypto_box.to_public_key (MBytes.of_string str)) + string + let peers_file_encoding = let open Data_encoding in - obj2 + obj3 (req "gid" string) + (req "public_key" public_key_encoding) (req "peers" (obj3 (req "known" @@ -591,10 +601,12 @@ let bootstrap config limits = on_cancel (fun () -> close_msg_queue () ; return ()) ; (* fill the known peers pools from last time *) Data_encoding.Json.read_file config.peers_file >>= fun res -> - let known_peers, black_list, my_gid = + let known_peers, black_list, my_gid, my_public_key = let init_peers () = let my_gid = fresh_gid () in + let (my_secret_key, my_public_key) = + Crypto_box.random_keypair () in let known_peers = let source = { unreachable_since = None ; @@ -605,19 +617,19 @@ let bootstrap config limits = PeerMap.empty config.known_peers in let black_list = BlackList.empty in - known_peers, black_list, my_gid in + known_peers, black_list, my_gid, my_public_key in match res with | None -> - let known_peers, black_list, my_gid = init_peers () in + let known_peers, black_list, my_gid, my_public_key = init_peers () in debug "(%a) peer cache initiated" pp_gid my_gid ; - ref known_peers, ref black_list, my_gid + ref known_peers, ref black_list, my_gid, my_public_key | Some json -> match Data_encoding.Json.destruct peers_file_encoding json with | exception _ -> - let known_peers, black_list, my_gid = init_peers () in + let known_peers, black_list, my_gid, my_public_key = init_peers () in debug "(%a) peer cache reset" pp_gid my_gid ; - ref known_peers, ref black_list, my_gid - | (my_gid, (k, b, w)) -> + ref known_peers, ref black_list, my_gid, my_public_key + | (my_gid, my_public_key, (k, b, w)) -> let white_list = List.fold_right PointSet.add w PointSet.empty in let known_peers = @@ -642,7 +654,7 @@ let bootstrap config limits = (fun r (a, d) -> BlackList.add a d r) BlackList.empty b in debug "(%a) peer cache loaded" pp_gid my_gid ; - ref known_peers, ref black_list, my_gid + ref known_peers, ref black_list, my_gid, my_public_key in (* some peer reachability predicates *) let black_listed (addr, _) = @@ -660,6 +672,7 @@ let bootstrap config limits = let json = Data_encoding.Json.construct peers_file_encoding @@ (my_gid, + my_public_key, PeerMap.fold (fun (addr, port) gid source (k, b, w) -> let infos = match gid, source.connections with @@ -919,7 +932,7 @@ let bootstrap config limits = main () else let canceler = - connect_to_peer config limits my_gid socket (addr, port) enqueue_event white_listed in + connect_to_peer config limits my_gid my_public_key socket (addr, port) enqueue_event white_listed in debug "(%a) incoming peer at %a:%d" pp_gid my_gid Ipaddr.pp_hum addr port ; incoming := PointMap.add (addr, port) canceler !incoming ; diff --git a/src/utils/crypto_box.ml b/src/utils/crypto_box.ml index f633f851c..d53fa84ec 100644 --- a/src/utils/crypto_box.ml +++ b/src/utils/crypto_box.ml @@ -19,3 +19,5 @@ let random_nonce = Sodium.Box.random_nonce let increment_nonce = Sodium.Box.increment_nonce let box = Sodium.Box.Bigbytes.box let box_open = Sodium.Box.Bigbytes.box_open +let to_public_key = Sodium.Box.Bigbytes.to_public_key +let of_public_key = Sodium.Box.Bigbytes.of_public_key diff --git a/src/utils/crypto_box.mli b/src/utils/crypto_box.mli index 1df44ea44..9e1243ad7 100644 --- a/src/utils/crypto_box.mli +++ b/src/utils/crypto_box.mli @@ -18,3 +18,5 @@ val random_nonce : unit -> nonce val increment_nonce : ?step:int -> nonce -> nonce val box : secret_key -> public_key -> MBytes.t -> nonce -> MBytes.t val box_open : secret_key -> public_key -> MBytes.t -> nonce -> MBytes.t +val to_public_key : MBytes.t -> public_key +val of_public_key : public_key -> MBytes.t From b8b93651af0745be5aad4261ba47ebb7f66a831d Mon Sep 17 00:00:00 2001 From: Eitan Chatav Date: Fri, 4 Nov 2016 12:22:22 -0700 Subject: [PATCH 03/12] composition operator added composition operator to utils module --- src/node/net/p2p.ml | 4 ++-- src/utils/utils.ml | 2 ++ src/utils/utils.mli | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/node/net/p2p.ml b/src/node/net/p2p.ml index f19af5cfc..9bf11f423 100644 --- a/src/node/net/p2p.ml +++ b/src/node/net/p2p.ml @@ -434,8 +434,8 @@ let addr_encoding = let public_key_encoding = let open Data_encoding in conv - (fun public_key -> MBytes.to_string (Crypto_box.of_public_key public_key)) - (fun str -> Crypto_box.to_public_key (MBytes.of_string str)) + (MBytes.to_string << Crypto_box.of_public_key) + (Crypto_box.to_public_key << MBytes.of_string) string let peers_file_encoding = diff --git a/src/utils/utils.ml b/src/utils/utils.ml index ef2fe1f48..97969003d 100644 --- a/src/utils/utils.ml +++ b/src/utils/utils.ml @@ -121,3 +121,5 @@ let rec remove_elem_from_list nb = function | [] -> [] | l when nb <= 0 -> l | _ :: tl -> remove_elem_from_list (nb - 1) tl + +let (<<) g f = fun a -> g (f a) diff --git a/src/utils/utils.mli b/src/utils/utils.mli index a027b783f..f2abbdf92 100644 --- a/src/utils/utils.mli +++ b/src/utils/utils.mli @@ -38,3 +38,5 @@ val remove_elem_from_list: int -> 'a list -> 'a list val filter_map: ('a -> 'b option) -> 'a list -> 'b list +(** Compose functions from right to left. *) +val (<<) : ('b -> 'c) -> ('a -> 'b) -> 'a -> 'c From 3a5368434c22c7f7ceff565f114642f9d74c8929 Mon Sep 17 00:00:00 2001 From: Eitan Chatav Date: Sat, 5 Nov 2016 09:12:25 -0700 Subject: [PATCH 04/12] add secret key to peer file --- src/node/net/p2p.ml | 27 ++++++++++++++++++--------- src/utils/crypto_box.ml | 2 ++ src/utils/crypto_box.mli | 2 ++ 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/node/net/p2p.ml b/src/node/net/p2p.ml index 9bf11f423..bf88a2703 100644 --- a/src/node/net/p2p.ml +++ b/src/node/net/p2p.ml @@ -438,11 +438,19 @@ let public_key_encoding = (Crypto_box.to_public_key << MBytes.of_string) string +let secret_key_encoding = + let open Data_encoding in + conv + (MBytes.to_string << Crypto_box.of_secret_key) + (Crypto_box.to_secret_key << MBytes.of_string) + string + let peers_file_encoding = let open Data_encoding in - obj3 + obj4 (req "gid" string) (req "public_key" public_key_encoding) + (req "secret_key" secret_key_encoding) (req "peers" (obj3 (req "known" @@ -601,7 +609,7 @@ let bootstrap config limits = on_cancel (fun () -> close_msg_queue () ; return ()) ; (* fill the known peers pools from last time *) Data_encoding.Json.read_file config.peers_file >>= fun res -> - let known_peers, black_list, my_gid, my_public_key = + let known_peers, black_list, my_gid, my_public_key, my_secret_key = let init_peers () = let my_gid = fresh_gid () in @@ -617,19 +625,19 @@ let bootstrap config limits = PeerMap.empty config.known_peers in let black_list = BlackList.empty in - known_peers, black_list, my_gid, my_public_key in + known_peers, black_list, my_gid, my_public_key, my_secret_key in match res with | None -> - let known_peers, black_list, my_gid, my_public_key = init_peers () in + let known_peers, black_list, my_gid, my_public_key, my_secret_key = init_peers () in debug "(%a) peer cache initiated" pp_gid my_gid ; - ref known_peers, ref black_list, my_gid, my_public_key + ref known_peers, ref black_list, my_gid, my_public_key, my_secret_key | Some json -> match Data_encoding.Json.destruct peers_file_encoding json with | exception _ -> - let known_peers, black_list, my_gid, my_public_key = init_peers () in + let known_peers, black_list, my_gid, my_public_key, my_secret_key = init_peers () in debug "(%a) peer cache reset" pp_gid my_gid ; - ref known_peers, ref black_list, my_gid, my_public_key - | (my_gid, my_public_key, (k, b, w)) -> + ref known_peers, ref black_list, my_gid, my_public_key, my_secret_key + | (my_gid, my_public_key, my_secret_key, (k, b, w)) -> let white_list = List.fold_right PointSet.add w PointSet.empty in let known_peers = @@ -654,7 +662,7 @@ let bootstrap config limits = (fun r (a, d) -> BlackList.add a d r) BlackList.empty b in debug "(%a) peer cache loaded" pp_gid my_gid ; - ref known_peers, ref black_list, my_gid, my_public_key + ref known_peers, ref black_list, my_gid, my_public_key, my_secret_key in (* some peer reachability predicates *) let black_listed (addr, _) = @@ -673,6 +681,7 @@ let bootstrap config limits = Data_encoding.Json.construct peers_file_encoding @@ (my_gid, my_public_key, + my_secret_key, PeerMap.fold (fun (addr, port) gid source (k, b, w) -> let infos = match gid, source.connections with diff --git a/src/utils/crypto_box.ml b/src/utils/crypto_box.ml index d53fa84ec..e9ea2f904 100644 --- a/src/utils/crypto_box.ml +++ b/src/utils/crypto_box.ml @@ -19,5 +19,7 @@ let random_nonce = Sodium.Box.random_nonce let increment_nonce = Sodium.Box.increment_nonce let box = Sodium.Box.Bigbytes.box let box_open = Sodium.Box.Bigbytes.box_open +let to_secret_key = Sodium.Box.Bigbytes.to_secret_key +let of_secret_key = Sodium.Box.Bigbytes.of_secret_key let to_public_key = Sodium.Box.Bigbytes.to_public_key let of_public_key = Sodium.Box.Bigbytes.of_public_key diff --git a/src/utils/crypto_box.mli b/src/utils/crypto_box.mli index 9e1243ad7..1908e18b3 100644 --- a/src/utils/crypto_box.mli +++ b/src/utils/crypto_box.mli @@ -18,5 +18,7 @@ val random_nonce : unit -> nonce val increment_nonce : ?step:int -> nonce -> nonce val box : secret_key -> public_key -> MBytes.t -> nonce -> MBytes.t val box_open : secret_key -> public_key -> MBytes.t -> nonce -> MBytes.t +val to_secret_key : MBytes.t -> secret_key +val of_secret_key : secret_key -> MBytes.t val to_public_key : MBytes.t -> public_key val of_public_key : public_key -> MBytes.t From bdab9b6c0586046b41f308d893bc1d5d1fc8d89b Mon Sep 17 00:00:00 2001 From: Eitan Chatav Date: Sat, 5 Nov 2016 09:32:32 -0700 Subject: [PATCH 05/12] peer public keys add peer public keys to known peers in peers file --- src/node/net/p2p.ml | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/node/net/p2p.ml b/src/node/net/p2p.ml index bf88a2703..3a4057110 100644 --- a/src/node/net/p2p.ml +++ b/src/node/net/p2p.ml @@ -458,10 +458,11 @@ let peers_file_encoding = (req "addr" addr_encoding) (req "port" int31) (opt "infos" - (obj3 + (obj4 (req "connections" int31) (req "lastSeen" float) - (req "gid" string)))))) + (req "gid" string) + (req "public_key" public_key_encoding)))))) (req "blacklisted" (list (obj2 (req "addr" addr_encoding) @@ -474,7 +475,7 @@ let peers_file_encoding = (* Info on peers maintained between connections *) type source = { unreachable_since : float option; - connections : (int * float) option ; + connections : (int * float * Crypto_box.public_key) option ; white_listed : bool } (* Ad hoc comparison on sources such as good source < bad source *) @@ -487,7 +488,7 @@ let compare_sources s1 s2 = | _, _ -> match s1.connections, s2.connections with | Some _, None -> -1 | None, Some _ -> 1 | None, None -> 0 - | Some (n1, t1), Some (n2, t2) -> + | Some (n1, t1, _), Some (n2, t2, _) -> if n1 = n2 then compare t2 t1 else compare n2 n1 @@ -650,10 +651,10 @@ let bootstrap config limits = connections = None ; white_listed = true } in PeerMap.update (addr, port) source r - | Some (c, t, gid) -> + | Some (c, t, gid, pk) -> let source = { unreachable_since = None ; - connections = Some (c, t) ; + connections = Some (c, t, pk) ; white_listed = PointSet.mem (addr, port) white_list } in PeerMap.update (addr, port) ~gid source r) PeerMap.empty k in @@ -685,7 +686,7 @@ let bootstrap config limits = PeerMap.fold (fun (addr, port) gid source (k, b, w) -> let infos = match gid, source.connections with - | Some gid, Some (n, t) -> Some (n, t, gid) + | Some gid, Some (n, t, pk) -> Some (n, t, gid, pk) | _ -> None in ((addr, port, infos) :: k, b, @@ -891,15 +892,15 @@ let bootstrap config limits = in update @@ try match PeerMap.by_gid peer.gid !known_peers with | { connections = None ; white_listed } -> - { connections = Some (1, Unix.gettimeofday ()) ; + { connections = Some (1, Unix.gettimeofday (), peer.public_key) ; unreachable_since = None ; white_listed } - | { connections = Some (n, _) ; white_listed } -> - { connections = Some (n + 1, Unix.gettimeofday ()) ; + | { connections = Some (n, _, _) ; white_listed } -> + { connections = Some (n + 1, Unix.gettimeofday (), peer.public_key) ; unreachable_since = None ; white_listed} with Not_found -> - { connections = Some (1, Unix.gettimeofday ()) ; + { connections = Some (1, Unix.gettimeofday (), peer.public_key) ; unreachable_since = None ; white_listed = white_listed point } in From 69bc2a33e2cecf679dfcbb1fffa967f3118e1ddd Mon Sep 17 00:00:00 2001 From: Eitan Chatav Date: Sat, 5 Nov 2016 12:16:48 -0700 Subject: [PATCH 06/12] encryption and decryption MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I don’t think this is secure since the receiver decrypts the message and then sends the clear message as a `Recv` event --- src/node/net/p2p.ml | 20 ++++++++++++++++---- src/utils/crypto_box.ml | 2 ++ src/utils/crypto_box.mli | 2 ++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/node/net/p2p.ml b/src/node/net/p2p.ml index 3a4057110..4b5a27c09 100644 --- a/src/node/net/p2p.ml +++ b/src/node/net/p2p.ml @@ -70,6 +70,7 @@ type packet = | Disconnect | Advertise of (addr * port) list | Message of Netbits.frame + | Box of (Crypto_box.nonce * MBytes.t) | Ping | Pong | Bootstrap @@ -115,6 +116,7 @@ let recv_packet | _ -> Unknown msg in return (decode_peers [] rest) | [ S 6 ; F rest ] -> return (Message rest) + | [ S 7 ; B nonce ; B msg ] -> return (Box (Crypto_box.to_nonce nonce, msg)) | msg -> return (Unknown msg) (* send a packet over a TCP socket *) @@ -144,7 +146,8 @@ let send_packet F [ B (MBytes.of_string @@ Ipaddr.to_string addr) ; S port ] :: rest | [] -> [] in [ S 5 ; F (encode peers) ] - | Message message -> [ S 6 ; F message ] in + | Message message -> [ S 6 ; F message ] + | Box (nonce , message) -> [ S 7 ; B (Crypto_box.of_nonce nonce) ; B message ] in Netbits.write socket frame (* A net handler, as a record-encoded object, abstract from the @@ -177,6 +180,7 @@ and peer = { last_seen : unit -> float ; disconnect : unit -> unit Lwt.t; send : packet -> unit Lwt.t ; + send_encr : MBytes.t -> unit Lwt.t ; } (* The (internal) type of network events, those dispatched from peer @@ -283,7 +287,7 @@ end function for communicating with the main worker using events (including the one sent when the connection is alive). Returns a canceler. *) -let connect_to_peer config limits my_gid my_public_key socket (addr, port) push white_listed = +let connect_to_peer config limits my_gid my_public_key my_secret_key socket (addr, port) push white_listed = (* a non exception-based cancelation mechanism *) let cancelation, cancel, on_cancel = canceler () in (* a cancelable reception *) @@ -347,9 +351,14 @@ let connect_to_peer config limits my_gid my_public_key socket (addr, port) push let last_seen () = !last in let disconnect () = cancel () in let send p = send_packet socket p >>= fun _ -> return () in + let send_encr msg = + let nonce = Crypto_box.random_nonce () in + let msg_encr = Crypto_box.box my_secret_key public_key msg nonce in + let packet = Box (nonce, msg_encr) in + send_packet socket packet >>= fun _ -> return () in (* net object construction *) let peer = { gid ; public_key ; point = (addr, port) ; listening_port ; - version ; last_seen ; disconnect ; send } in + version ; last_seen ; disconnect ; send ; send_encr } in (* The packet reception loop. *) let rec receiver () = recv () >>= fun packet -> @@ -370,6 +379,9 @@ let connect_to_peer config limits my_gid my_public_key socket (addr, port) push | Pong -> receiver () | Message msg -> push (Recv (peer, msg)) ; receiver () + | Box (nonce, msg_encr) -> + let msg = Crypto_box.box_open my_secret_key public_key msg_encr nonce in + push (Recv (peer, [B msg])) ; receiver () in (* The polling loop *) let rec pulse_monitor ping = @@ -942,7 +954,7 @@ let bootstrap config limits = main () else let canceler = - connect_to_peer config limits my_gid my_public_key socket (addr, port) enqueue_event white_listed in + connect_to_peer config limits my_gid my_public_key my_secret_key socket (addr, port) enqueue_event white_listed in debug "(%a) incoming peer at %a:%d" pp_gid my_gid Ipaddr.pp_hum addr port ; incoming := PointMap.add (addr, port) canceler !incoming ; diff --git a/src/utils/crypto_box.ml b/src/utils/crypto_box.ml index e9ea2f904..cdef24b97 100644 --- a/src/utils/crypto_box.ml +++ b/src/utils/crypto_box.ml @@ -23,3 +23,5 @@ let to_secret_key = Sodium.Box.Bigbytes.to_secret_key let of_secret_key = Sodium.Box.Bigbytes.of_secret_key let to_public_key = Sodium.Box.Bigbytes.to_public_key let of_public_key = Sodium.Box.Bigbytes.of_public_key +let to_nonce = Sodium.Box.Bigbytes.to_nonce +let of_nonce = Sodium.Box.Bigbytes.of_nonce diff --git a/src/utils/crypto_box.mli b/src/utils/crypto_box.mli index 1908e18b3..d870b0bb2 100644 --- a/src/utils/crypto_box.mli +++ b/src/utils/crypto_box.mli @@ -22,3 +22,5 @@ val to_secret_key : MBytes.t -> secret_key val of_secret_key : secret_key -> MBytes.t val to_public_key : MBytes.t -> public_key val of_public_key : public_key -> MBytes.t +val to_nonce : MBytes.t -> nonce +val of_nonce : nonce -> MBytes.t From b3efe1ad0ad261bfd226d58c1c7256de2baea8ca Mon Sep 17 00:00:00 2001 From: Eitan Chatav Date: Sat, 5 Nov 2016 14:32:13 -0700 Subject: [PATCH 07/12] testing code --- src/node/net/p2p.ml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/node/net/p2p.ml b/src/node/net/p2p.ml index 4b5a27c09..e59274a78 100644 --- a/src/node/net/p2p.ml +++ b/src/node/net/p2p.ml @@ -355,6 +355,7 @@ let connect_to_peer config limits my_gid my_public_key my_secret_key socket (add let nonce = Crypto_box.random_nonce () in let msg_encr = Crypto_box.box my_secret_key public_key msg nonce in let packet = Box (nonce, msg_encr) in + Format.printf "encoding %s as %s" (MBytes.to_string msg) (MBytes.to_string msg_encr); send_packet socket packet >>= fun _ -> return () in (* net object construction *) let peer = { gid ; public_key ; point = (addr, port) ; listening_port ; @@ -381,6 +382,7 @@ let connect_to_peer config limits my_gid my_public_key my_secret_key socket (add push (Recv (peer, msg)) ; receiver () | Box (nonce, msg_encr) -> let msg = Crypto_box.box_open my_secret_key public_key msg_encr nonce in + Format.printf "decoding %s as %s" (MBytes.to_string msg_encr) (MBytes.to_string msg); push (Recv (peer, [B msg])) ; receiver () in (* The polling loop *) @@ -1069,7 +1071,8 @@ let bootstrap config limits = and recv_from () = dequeue_msg () and send_to (peer, msg) = - peer.send (Message msg) >>= fun _ -> return () + peer.send (Message msg) <&> + peer.send_encr (MBytes.of_string "Eitan") and push (peer, msg) = Lwt.async (fun () -> peer.send (Message msg)) and broadcast msg = From 001ba994a8124a812fa54f004fc99cbcc91671ed Mon Sep 17 00:00:00 2001 From: Eitan Chatav Date: Mon, 7 Nov 2016 11:30:13 -0800 Subject: [PATCH 08/12] negotiate nonce during peer connection --- src/node/net/p2p.ml | 74 ++++++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 35 deletions(-) diff --git a/src/node/net/p2p.ml b/src/node/net/p2p.ml index e59274a78..c479fe683 100644 --- a/src/node/net/p2p.ml +++ b/src/node/net/p2p.ml @@ -66,11 +66,11 @@ type point = addr * port not a real kind of packet, it means that something indecypherable was transmitted. *) type packet = - | Connect of gid * Crypto_box.public_key * int option * version list + | Connect of gid * Crypto_box.public_key * Crypto_box.nonce * int option * version list | Disconnect | Advertise of (addr * port) list | Message of Netbits.frame - | Box of (Crypto_box.nonce * MBytes.t) + | Box of MBytes.t | Ping | Pong | Bootstrap @@ -97,12 +97,12 @@ let recv_packet | [ S 2 ] -> return Ping | [ S 12 ] -> return Pong | [ S 3 ] -> return Bootstrap - | [ S 4 ; B gid ; B public_key ; S port ; F rest ] as msg -> + | [ S 4 ; B gid ; B public_key ; B nonce ; S port ; F rest ] as msg -> decode_versions msg rest @@ fun versions -> - return (Connect (MBytes.to_string gid, Crypto_box.to_public_key public_key, Some port, versions)) - | [ S 4 ; B gid ; B public_key ; F rest ] as msg -> + return (Connect (MBytes.to_string gid, Crypto_box.to_public_key public_key, Crypto_box.to_nonce nonce, Some port, versions)) + | [ S 4 ; B gid ; B public_key ; B nonce ; F rest ] as msg -> decode_versions msg rest @@ fun versions -> - return (Connect (MBytes.to_string gid, Crypto_box.to_public_key public_key, None, versions)) + return (Connect (MBytes.to_string gid, Crypto_box.to_public_key public_key, Crypto_box.to_nonce nonce, None, versions)) | [ S 5 ; F rest ] as msg -> let rec decode_peers acc = function | F [ B addr ; S port ] :: rest -> begin @@ -116,7 +116,7 @@ let recv_packet | _ -> Unknown msg in return (decode_peers [] rest) | [ S 6 ; F rest ] -> return (Message rest) - | [ S 7 ; B nonce ; B msg ] -> return (Box (Crypto_box.to_nonce nonce, msg)) + | [ S 7 ; B msg ] -> return (Box msg) | msg -> return (Unknown msg) (* send a packet over a TCP socket *) @@ -129,14 +129,14 @@ let send_packet | Ping -> [ S 2 ] | Pong -> [ S 12 ] | Bootstrap -> [ S 3 ] - | Connect (gid, public_key, port, versions) -> + | Connect (gid, public_key, nonce, port, versions) -> let rec encode = function | (name, maj, min) :: tl -> let rest = encode tl in F [ B (MBytes.of_string name) ; S maj ; S min ] :: rest | [] -> [] in - [ S 4 ; B (MBytes.of_string gid) ; B (Crypto_box.of_public_key public_key) ] + [ S 4 ; B (MBytes.of_string gid) ; B (Crypto_box.of_public_key public_key) ; B (Crypto_box.of_nonce nonce) ] @ (match port with | Some port -> [ S port ] | None -> []) @ [ F (encode versions) ] | Advertise peers -> @@ -147,7 +147,7 @@ let send_packet | [] -> [] in [ S 5 ; F (encode peers) ] | Message message -> [ S 6 ; F message ] - | Box (nonce , message) -> [ S 7 ; B (Crypto_box.of_nonce nonce) ; B message ] in + | Box message -> [ S 7 ; B message ] in Netbits.write socket frame (* A net handler, as a record-encoded object, abstract from the @@ -174,6 +174,7 @@ type net = { and peer = { gid : gid ; public_key : Crypto_box.public_key ; + current_nonce : unit -> Crypto_box.nonce ; point : point ; listening_port : port option ; version : version ; @@ -287,7 +288,7 @@ end function for communicating with the main worker using events (including the one sent when the connection is alive). Returns a canceler. *) -let connect_to_peer config limits my_gid my_public_key my_secret_key socket (addr, port) push white_listed = +let connect_to_peer config limits my_gid my_public_key my_nonce my_secret_key socket (addr, port) push white_listed = (* a non exception-based cancelation mechanism *) let cancelation, cancel, on_cancel = canceler () in (* a cancelable reception *) @@ -300,11 +301,12 @@ let connect_to_peer config limits my_gid my_public_key my_secret_key socket (add let rec connect () = send_packet socket (Connect (my_gid, my_public_key, + my_nonce, config.incoming_port, config.supported_versions)) >>= fun _ -> pick [ (LU.sleep limits.peer_answer_timeout >>= fun () -> return Disconnect) ; recv () ] >>= function - | Connect (gid, public_key , listening_port, versions) -> + | Connect (gid, public_key , nonce, listening_port, versions) -> debug "(%a) connection requested from %a @ %a:%d" pp_gid my_gid pp_gid gid Ipaddr.pp_hum addr port ; begin match common_version config.supported_versions versions with @@ -316,7 +318,7 @@ let connect_to_peer config limits my_gid my_public_key my_secret_key socket (add if config.closed_network then match listening_port with | Some port when white_listed (addr, port) -> - connected version gid public_key listening_port + connected version gid public_key nonce listening_port | Some port -> debug "(%a) connection rejected (out of the closed network) from %a:%d" pp_gid my_gid Ipaddr.pp_hum addr port ; @@ -326,7 +328,7 @@ let connect_to_peer config limits my_gid my_public_key my_secret_key socket (add pp_gid my_gid Ipaddr.pp_hum addr ; cancel () else - connected version gid public_key listening_port + connected version gid public_key nonce listening_port end | Advertise peers -> (* alternatively, one can refuse a connection but reply with @@ -344,21 +346,22 @@ let connect_to_peer config limits my_gid my_public_key my_secret_key socket (add pp_gid my_gid Ipaddr.pp_hum addr port ; cancel () (* Them we can build the net object and launch the worker. *) - and connected version gid public_key listening_port = + and connected version gid public_key nonce listening_port = (* net object state *) let last = ref (Unix.gettimeofday ()) in + let the_nonce = ref nonce in (* net object callbaks *) let last_seen () = !last in + let current_nonce () = !the_nonce in + let next_nonce () = the_nonce := Crypto_box.increment_nonce !the_nonce in let disconnect () = cancel () in let send p = send_packet socket p >>= fun _ -> return () in let send_encr msg = - let nonce = Crypto_box.random_nonce () in - let msg_encr = Crypto_box.box my_secret_key public_key msg nonce in - let packet = Box (nonce, msg_encr) in - Format.printf "encoding %s as %s" (MBytes.to_string msg) (MBytes.to_string msg_encr); - send_packet socket packet >>= fun _ -> return () in + let msg_encr = Crypto_box.box my_secret_key public_key msg (current_nonce ()) in + let packet = Box msg_encr in + next_nonce (); send_packet socket packet >>= fun _ -> return () in (* net object construction *) - let peer = { gid ; public_key ; point = (addr, port) ; listening_port ; + let peer = { gid ; public_key ; current_nonce ; point = (addr, port) ; listening_port ; version ; last_seen ; disconnect ; send ; send_encr } in (* The packet reception loop. *) let rec receiver () = @@ -380,9 +383,8 @@ let connect_to_peer config limits my_gid my_public_key my_secret_key socket (add | Pong -> receiver () | Message msg -> push (Recv (peer, msg)) ; receiver () - | Box (nonce, msg_encr) -> - let msg = Crypto_box.box_open my_secret_key public_key msg_encr nonce in - Format.printf "decoding %s as %s" (MBytes.to_string msg_encr) (MBytes.to_string msg); + | Box msg_encr -> + let msg = Crypto_box.box_open my_secret_key public_key msg_encr (peer.current_nonce ()) in push (Recv (peer, [B msg])) ; receiver () in (* The polling loop *) @@ -624,12 +626,14 @@ let bootstrap config limits = on_cancel (fun () -> close_msg_queue () ; return ()) ; (* fill the known peers pools from last time *) Data_encoding.Json.read_file config.peers_file >>= fun res -> - let known_peers, black_list, my_gid, my_public_key, my_secret_key = + let known_peers, black_list, my_gid, my_public_key, my_nonce, my_secret_key = let init_peers () = let my_gid = fresh_gid () in let (my_secret_key, my_public_key) = Crypto_box.random_keypair () in + let my_nonce = + Crypto_box.random_nonce () in let known_peers = let source = { unreachable_since = None ; @@ -640,18 +644,18 @@ let bootstrap config limits = PeerMap.empty config.known_peers in let black_list = BlackList.empty in - known_peers, black_list, my_gid, my_public_key, my_secret_key in + known_peers, black_list, my_gid, my_public_key, my_nonce, my_secret_key in match res with | None -> - let known_peers, black_list, my_gid, my_public_key, my_secret_key = init_peers () in + let known_peers, black_list, my_gid, my_public_key, my_nonce, my_secret_key = init_peers () in debug "(%a) peer cache initiated" pp_gid my_gid ; - ref known_peers, ref black_list, my_gid, my_public_key, my_secret_key + ref known_peers, ref black_list, my_gid, my_public_key, my_nonce, my_secret_key | Some json -> match Data_encoding.Json.destruct peers_file_encoding json with | exception _ -> - let known_peers, black_list, my_gid, my_public_key, my_secret_key = init_peers () in + let known_peers, black_list, my_gid, my_public_key, my_nonce, my_secret_key = init_peers () in debug "(%a) peer cache reset" pp_gid my_gid ; - ref known_peers, ref black_list, my_gid, my_public_key, my_secret_key + ref known_peers, ref black_list, my_gid, my_public_key, my_nonce, my_secret_key | (my_gid, my_public_key, my_secret_key, (k, b, w)) -> let white_list = List.fold_right PointSet.add w PointSet.empty in @@ -676,8 +680,10 @@ let bootstrap config limits = List.fold_left (fun r (a, d) -> BlackList.add a d r) BlackList.empty b in + let my_nonce = + Crypto_box.random_nonce () in debug "(%a) peer cache loaded" pp_gid my_gid ; - ref known_peers, ref black_list, my_gid, my_public_key, my_secret_key + ref known_peers, ref black_list, my_gid, my_public_key, my_nonce, my_secret_key in (* some peer reachability predicates *) let black_listed (addr, _) = @@ -956,7 +962,7 @@ let bootstrap config limits = main () else let canceler = - connect_to_peer config limits my_gid my_public_key my_secret_key socket (addr, port) enqueue_event white_listed in + connect_to_peer config limits my_gid my_public_key my_nonce my_secret_key socket (addr, port) enqueue_event white_listed in debug "(%a) incoming peer at %a:%d" pp_gid my_gid Ipaddr.pp_hum addr port ; incoming := PointMap.add (addr, port) canceler !incoming ; @@ -1070,9 +1076,7 @@ let bootstrap config limits = fst peer.point, snd peer.point, peer.version and recv_from () = dequeue_msg () - and send_to (peer, msg) = - peer.send (Message msg) <&> - peer.send_encr (MBytes.of_string "Eitan") + and send_to (peer, msg) = peer.send (Message msg) and push (peer, msg) = Lwt.async (fun () -> peer.send (Message msg)) and broadcast msg = From 1733cd499a6396b84d77bca6885a55af8ffb5906 Mon Sep 17 00:00:00 2001 From: Eitan Chatav Date: Mon, 7 Nov 2016 14:38:02 -0800 Subject: [PATCH 09/12] handle decryption exceptions --- src/node/net/p2p.ml | 7 +++++-- src/utils/crypto_box.ml | 4 +++- src/utils/crypto_box.mli | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/node/net/p2p.ml b/src/node/net/p2p.ml index c479fe683..e6e97f961 100644 --- a/src/node/net/p2p.ml +++ b/src/node/net/p2p.ml @@ -384,8 +384,11 @@ let connect_to_peer config limits my_gid my_public_key my_nonce my_secret_key so | Message msg -> push (Recv (peer, msg)) ; receiver () | Box msg_encr -> - let msg = Crypto_box.box_open my_secret_key public_key msg_encr (peer.current_nonce ()) in - push (Recv (peer, [B msg])) ; receiver () + Crypto_box.box_open my_secret_key public_key msg_encr (peer.current_nonce ()) + |> function + | None -> debug "(%a) cannot decrypt message (from peer) %a @ %a:%d" + pp_gid my_gid pp_gid gid Ipaddr.pp_hum addr port ; receiver () + | Some msg -> push (Recv (peer, [B msg])) ; receiver () in (* The polling loop *) let rec pulse_monitor ping = diff --git a/src/utils/crypto_box.ml b/src/utils/crypto_box.ml index cdef24b97..8931436c9 100644 --- a/src/utils/crypto_box.ml +++ b/src/utils/crypto_box.ml @@ -18,7 +18,9 @@ let random_keypair = Sodium.Box.random_keypair let random_nonce = Sodium.Box.random_nonce let increment_nonce = Sodium.Box.increment_nonce let box = Sodium.Box.Bigbytes.box -let box_open = Sodium.Box.Bigbytes.box_open +let box_open sk pk msg nonce = + try Some (Sodium.Box.Bigbytes.box_open sk pk msg nonce) with + | Sodium.Verification_failure -> None let to_secret_key = Sodium.Box.Bigbytes.to_secret_key let of_secret_key = Sodium.Box.Bigbytes.of_secret_key let to_public_key = Sodium.Box.Bigbytes.to_public_key diff --git a/src/utils/crypto_box.mli b/src/utils/crypto_box.mli index d870b0bb2..c1d1b9e47 100644 --- a/src/utils/crypto_box.mli +++ b/src/utils/crypto_box.mli @@ -17,7 +17,7 @@ val random_keypair : unit -> secret_key * public_key val random_nonce : unit -> nonce val increment_nonce : ?step:int -> nonce -> nonce val box : secret_key -> public_key -> MBytes.t -> nonce -> MBytes.t -val box_open : secret_key -> public_key -> MBytes.t -> nonce -> MBytes.t +val box_open : secret_key -> public_key -> MBytes.t -> nonce -> MBytes.t option val to_secret_key : MBytes.t -> secret_key val of_secret_key : secret_key -> MBytes.t val to_public_key : MBytes.t -> public_key From 56e5fc3213aadc2652f68eb21dbfe5781f51da9d Mon Sep 17 00:00:00 2001 From: Eitan Chatav Date: Mon, 7 Nov 2016 14:50:22 -0800 Subject: [PATCH 10/12] encrypt arbitrary net frames --- src/node/net/p2p.ml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/node/net/p2p.ml b/src/node/net/p2p.ml index e6e97f961..9452db98e 100644 --- a/src/node/net/p2p.ml +++ b/src/node/net/p2p.ml @@ -181,7 +181,7 @@ and peer = { last_seen : unit -> float ; disconnect : unit -> unit Lwt.t; send : packet -> unit Lwt.t ; - send_encr : MBytes.t -> unit Lwt.t ; + send_encr : frame -> unit Lwt.t ; } (* The (internal) type of network events, those dispatched from peer @@ -357,7 +357,7 @@ let connect_to_peer config limits my_gid my_public_key my_nonce my_secret_key so let disconnect () = cancel () in let send p = send_packet socket p >>= fun _ -> return () in let send_encr msg = - let msg_encr = Crypto_box.box my_secret_key public_key msg (current_nonce ()) in + let msg_encr = Crypto_box.box my_secret_key public_key (to_raw msg) (current_nonce ()) in let packet = Box msg_encr in next_nonce (); send_packet socket packet >>= fun _ -> return () in (* net object construction *) @@ -388,7 +388,10 @@ let connect_to_peer config limits my_gid my_public_key my_nonce my_secret_key so |> function | None -> debug "(%a) cannot decrypt message (from peer) %a @ %a:%d" pp_gid my_gid pp_gid gid Ipaddr.pp_hum addr port ; receiver () - | Some msg -> push (Recv (peer, [B msg])) ; receiver () + | Some bytes -> of_raw bytes |> function + | None -> debug "(%a) cannot decode message (from peer) %a @ %a:%d" + pp_gid my_gid pp_gid gid Ipaddr.pp_hum addr port ; receiver () + | Some msg -> push (Recv (peer, msg)) ; receiver () in (* The polling loop *) let rec pulse_monitor ping = From e9ff110d08680d856de4a8f92c13d158fbb26d17 Mon Sep 17 00:00:00 2001 From: Eitan Chatav Date: Tue, 8 Nov 2016 18:18:09 -0800 Subject: [PATCH 11/12] proof of work start --- src/node/net/p2p.ml | 1 + src/utils/crypto_box.ml | 7 +++++++ src/utils/crypto_box.mli | 3 +++ 3 files changed, 11 insertions(+) diff --git a/src/node/net/p2p.ml b/src/node/net/p2p.ml index 9452db98e..6d8e0de68 100644 --- a/src/node/net/p2p.ml +++ b/src/node/net/p2p.ml @@ -174,6 +174,7 @@ type net = { and peer = { gid : gid ; public_key : Crypto_box.public_key ; + (*proof_of_work_nonce : Crypto_box.nonce ;*) current_nonce : unit -> Crypto_box.nonce ; point : point ; listening_port : port option ; diff --git a/src/utils/crypto_box.ml b/src/utils/crypto_box.ml index 8931436c9..c0cc4248e 100644 --- a/src/utils/crypto_box.ml +++ b/src/utils/crypto_box.ml @@ -13,6 +13,7 @@ type secret_key = Sodium.Box.secret_key type public_key = Sodium.Box.public_key type channel_key = Sodium.Box.channel_key type nonce = Sodium.Box.nonce +type difficulty = int let random_keypair = Sodium.Box.random_keypair let random_nonce = Sodium.Box.random_nonce @@ -27,3 +28,9 @@ let to_public_key = Sodium.Box.Bigbytes.to_public_key let of_public_key = Sodium.Box.Bigbytes.of_public_key let to_nonce = Sodium.Box.Bigbytes.to_nonce let of_nonce = Sodium.Box.Bigbytes.of_nonce +let check_proof_of_work pk nonce difficulty = assert false +let generate_proof_of_work pk difficulty = + let rec loop nonce = + if check_proof_of_work pk nonce difficulty then nonce + else loop (increment_nonce nonce) in + loop (random_nonce ()) diff --git a/src/utils/crypto_box.mli b/src/utils/crypto_box.mli index c1d1b9e47..1bb45c606 100644 --- a/src/utils/crypto_box.mli +++ b/src/utils/crypto_box.mli @@ -12,6 +12,7 @@ type secret_key type public_key type nonce +type difficulty val random_keypair : unit -> secret_key * public_key val random_nonce : unit -> nonce @@ -24,3 +25,5 @@ val to_public_key : MBytes.t -> public_key val of_public_key : public_key -> MBytes.t val to_nonce : MBytes.t -> nonce val of_nonce : nonce -> MBytes.t +val check_proof_of_work : public_key -> nonce -> difficulty -> bool +val generate_proof_of_work : public_key -> difficulty -> nonce From 4cd86b7ca83e7a1775ea24227d8d5ab1062ddcc3 Mon Sep 17 00:00:00 2001 From: Eitan Chatav Date: Wed, 9 Nov 2016 18:29:57 -0800 Subject: [PATCH 12/12] check proof of work --- src/utils/crypto_box.ml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/utils/crypto_box.ml b/src/utils/crypto_box.ml index c0cc4248e..d5190d5fd 100644 --- a/src/utils/crypto_box.ml +++ b/src/utils/crypto_box.ml @@ -28,7 +28,20 @@ let to_public_key = Sodium.Box.Bigbytes.to_public_key let of_public_key = Sodium.Box.Bigbytes.of_public_key let to_nonce = Sodium.Box.Bigbytes.to_nonce let of_nonce = Sodium.Box.Bigbytes.of_nonce -let check_proof_of_work pk nonce difficulty = assert false +let check_proof_of_work pk nonce difficulty = + let hash_bytes l = + let hash = Cryptokit.Hash.sha256 () in + List.iter (fun b -> hash#add_string (MBytes.to_string b)) l; + let r = hash#result in hash#wipe; r in + let hash = hash_bytes [of_public_key pk; of_nonce nonce] in + let bytes = MBytes.of_string hash in + let len = MBytes.length bytes * 8 in + try + for i = len - 1 downto (len - difficulty) do + if MBytes.get_bool bytes i then raise Exit + done; + true + with Exit -> false let generate_proof_of_work pk difficulty = let rec loop nonce = if check_proof_of_work pk nonce difficulty then nonce