Skip to content

Commit

Permalink
optimization: ⚡ pre-computed public key embedded on private key itsel…
Browse files Browse the repository at this point in the history
…f - public key derivation is O(1)

Signed-off-by: Marco Aurélio da Silva <marcoonroad@gmail.com>
  • Loading branch information
marcoonroad committed Sep 15, 2019
1 parent 9a7c2ee commit 855272b
Show file tree
Hide file tree
Showing 10 changed files with 108 additions and 40 deletions.
10 changes: 10 additions & 0 deletions lib/encoding.ml
@@ -0,0 +1,10 @@
module Base64 = Nocrypto.Base64
module Option = Core.Option

let encode payload =
Cstruct.to_string @@ Base64.encode @@ Cstruct.of_string payload


let decode blob =
let open Option in
blob |> Cstruct.of_string |> Base64.decode >>| Cstruct.to_string
3 changes: 3 additions & 0 deletions lib/encoding.mli
@@ -0,0 +1,3 @@
val encode : string -> string

val decode : string -> string option
7 changes: 3 additions & 4 deletions lib/encryption.ml
Expand Up @@ -22,7 +22,8 @@ let encrypt msg ~pass =
let proof = Hash.mine pass ~difficulty:5 in
let key = of_secret proof in
let iv = __compute_iv proof in
let result = encrypt ~iv ~key (Utils.pad ~basis:16 msg) in
let blob = Utils.pad ~basis:16 msg in
let result = encrypt ~iv ~key blob in
result |> Base64.encode |> Cstruct.to_string


Expand All @@ -32,6 +33,4 @@ let decrypt cipher ~pass =
let iv = __compute_iv proof in
let result = cipher |> Cstruct.of_string |> Base64.decode in
let open Option in
result
>>= fun msg ->
msg |> decrypt ~iv ~key |> Cstruct.to_string |> Utils.unpad |> some
result >>= fun msg -> msg |> decrypt ~iv ~key |> Utils.unpad |> some
42 changes: 34 additions & 8 deletions lib/keys.ml
Expand Up @@ -3,6 +3,7 @@ module String = Core.String
module Float = Core.Float
module Int64 = Core.Int64
module Option = Core.Option
module Base64 = Nocrypto.Base64
module Defer = Utils.Defer

let generate () = Random.generate512 ()
Expand All @@ -14,26 +15,51 @@ let genpub priv =
List.map pieces ~f:__force_digest


let derive priv = Utils.bytes_of_string @@ Serialization.digest @@ genpub priv
let derive priv = Utils.bytes_of_hex @@ Serialization.digest @@ genpub priv

let export ~priv ~pass = Encryption.encrypt ~pass @@ Utils.bytes_to_string priv
let export ~priv ~pass =
let priv' = Bytes.to_string priv in
let payload = Encoding.encode priv' in
Encryption.encrypt ~pass payload

let validate_key plain =
if String.length plain == Utils._HASH_LENGTH then Some plain else None

let validate_key blob =
try
let plain =
blob
|> Cstruct.of_string
|> Base64.decode
|> (fun opt -> Option.value_exn opt)
|> Cstruct.to_string
in
let parts =
String.split ~on:'\n' plain
|> List.map ~f:Cstruct.of_string
|> List.map ~f:Base64.decode
|> List.map ~f:(fun opt -> Option.value_exn opt)
|> List.map ~f:Cstruct.to_bytes
|> List.map ~f:Utils.bytes_to_hex
in
assert (Utils._HASH_LENGTH == String.length @@ List.nth_exn parts 0) ;
assert (Utils._HASH_LENGTH == String.length @@ List.nth_exn parts 1) ;
Some plain
with
| _ ->
None


let import ~cipher ~pass =
let open Option in
Encryption.decrypt ~pass cipher >>= validate_key >>| Utils.bytes_of_string
Encryption.decrypt ~pass cipher >>= validate_key >>| Bytes.of_string


let address pub = Utils.to_hex @@ Utils.bytes_to_string pub
let address pub = Utils.with_hex_prefix @@ Utils.bytes_to_hex pub

let sign = Signing.sign

let verify = Verification.verify

let show = Utils.bytes_to_string
let show = Utils.bytes_to_hex

let load dump =
if Utils.is_hash dump then Some (Utils.bytes_of_string dump) else None
if Utils.is_hash dump then Some (Utils.bytes_of_hex dump) else None
48 changes: 38 additions & 10 deletions lib/main.ml
@@ -1,10 +1,13 @@
module Option = Core.Option
module String = Core.String
module List = Core.List
module Bytes = Core.Bytes

type priv = bytes

type pub = bytes

let derive = Keys.derive
let __derive = Keys.derive

let import = Keys.import

Expand All @@ -22,36 +25,61 @@ let verify = Keys.verify

(*** wrappers *****************************************************************)

let __check priv =
let pub = derive priv in
let id = "0x" ^ Utils.bytes_to_string pub in
let __decode blob : string =
let payload : string option = Encoding.decode blob in
Option.value_exn payload


let __split priv =
let parts = String.split ~on:'\n' @@ Bytes.to_string priv in
List.map ~f:__decode parts


let derive priv = Bytes.of_string @@ List.nth_exn (__split priv) 1

let __check_tail pub =
let id = "0x" ^ Utils.bytes_to_hex pub in
if Blacklist.exists id then None else Some pub


let sign ~priv ~msg =
let __check priv = __check_tail @@ __derive priv

let check priv = __check_tail @@ derive priv

let sign ~priv:priv' ~msg =
let priv = Bytes.of_string @@ List.nth_exn (__split priv') 0 in
let success pub =
let signature = sign ~priv ~msg in
Blacklist.add @@ "0x" ^ Utils.bytes_to_string pub ;
Blacklist.add @@ "0x" ^ Utils.bytes_to_hex pub ;
Some signature
in
let open Option in
__check priv >>= success
check priv' >>= success


let import ~cipher ~pass =
let open Option in
import ~cipher ~pass
>>= function priv -> __check priv >>= (function _ -> Some priv)
>>= function priv -> check priv >>= (function _ -> Some priv)


let rec generate () =
let rec __generate () =
let priv = Keys.generate () in
let const _ _ = priv in
let option = __check priv in
let step = Option.value_map option ~default:generate ~f:const in
let step = Option.value_map option ~default:__generate ~f:const in
step ()


(* precomputed public key together with private key *)
let generate () =
let priv = __generate () in
let pub = __derive priv in
let priv' = Encoding.encode @@ Bytes.to_string priv in
let pub' = Encoding.encode @@ Bytes.to_string pub in
Bytes.of_string (priv' ^ "\n" ^ pub')


let pair () =
let priv = generate () in
let pub = derive priv in
Expand Down
4 changes: 2 additions & 2 deletions lib/serialization.ml
Expand Up @@ -4,15 +4,15 @@ module Option = Core.Option

let show pub =
pub
|> List.map ~f:Utils.bytes_to_string
|> List.map ~f:Utils.bytes_to_hex
|> List.reduce_exn ~f:Utils.concat_hashes


let load text =
let list = String.split text ~on:':' in
let open Option in
Utils.validate_key list
>>= fun list -> some @@ List.map ~f:Utils.bytes_of_string list
>>= fun list -> some @@ List.map ~f:Utils.bytes_of_hex list


let digest pub = pub |> show |> Hash.digest
2 changes: 1 addition & 1 deletion lib/signing.ml
Expand Up @@ -2,7 +2,7 @@ module List = Core.List
module Defer = Utils.Defer

let digest_to_string lazy_bytes =
Utils.bytes_to_string @@ Hash.digest_bytes @@ Defer.force lazy_bytes
Utils.bytes_to_hex @@ Hash.digest_bytes @@ Defer.force lazy_bytes


let sign ~priv ~msg =
Expand Down
16 changes: 8 additions & 8 deletions lib/utils.ml
Expand Up @@ -4,18 +4,18 @@ module Char = Core.Char
module Int = Core.Int
module Lazy = Core.Lazy
module Str = Re.Str
module Option = Core.Option
module Base64 = Nocrypto.Base64

module Defer = struct
let force = Lazy.force_val

let bind deferred ~f = lazy (force @@ f @@ force deferred)
end

let bytes_of_string string = Cstruct.to_bytes @@ Cstruct.of_hex string

let bytes_to_string bytes =
Hex.show @@ Hex.of_cstruct @@ Cstruct.of_bytes bytes
let bytes_of_hex string = Cstruct.to_bytes @@ Cstruct.of_hex string

let bytes_to_hex bytes = Hex.show @@ Hex.of_cstruct @@ Cstruct.of_bytes bytes

(* 16 hex chars and 128 chars/string length for hash under hex string format *)
let _HASH_LENGTH = 128
Expand Down Expand Up @@ -47,12 +47,12 @@ let validate_key list =
if List.length filtered = _KEY_LENGTH then Some list else None


let to_hex text = "0x" ^ text
let with_hex_prefix text = "0x" ^ text

let calculate_index (position, key) = (position * _HEX_SPACE) + key

let index_at ~list position =
bytes_to_string @@ Defer.force @@ List.nth_exn list position
bytes_to_hex @@ Defer.force @@ List.nth_exn list position


let replace_index ~matrix pairs = List.map pairs ~f:(index_at ~list:matrix)
Expand All @@ -72,7 +72,7 @@ let verify_with ~matrix ~digest pairs =
let concat_hashes left right = left ^ ":" ^ right

let char_to_hex_int index char =
let value = char |> Char.to_string |> to_hex |> Int.of_string in
let value = char |> Char.to_string |> with_hex_prefix |> Int.of_string in
(index, value)


Expand All @@ -93,7 +93,7 @@ let pad ~basis msg =

let nonzero char = char != nullchar

let unpad msg = String.filter ~f:nonzero msg
let unpad msg = String.filter ~f:nonzero @@ Cstruct.to_string msg

let digest_hex_string hex =
hex
Expand Down
8 changes: 4 additions & 4 deletions lib/utils.mli
Expand Up @@ -10,7 +10,7 @@ val _KEY_LENGTH : int

val is_hash : string -> bool

val to_hex : string -> string
val with_hex_prefix : string -> string

val concat_hashes : string -> string -> string

Expand All @@ -30,10 +30,10 @@ val verify_with :

val pad : basis:int -> string -> Cstruct.t

val unpad : string -> string
val unpad : Cstruct.t -> string

val bytes_of_string : string -> bytes
val bytes_of_hex : string -> bytes

val bytes_to_string : bytes -> string
val bytes_to_hex : bytes -> string

val digest_hex_string : string -> string
8 changes: 5 additions & 3 deletions lib/verification.ml
Expand Up @@ -5,7 +5,7 @@ module Defer = Utils.Defer

let digest = Utils.digest_hex_string

let delay_string_cast bytes = lazy (Utils.bytes_to_string bytes)
let delay_string_cast bytes = lazy (Utils.bytes_to_hex bytes)

let verify ~pub ~msg ~signature =
try
Expand All @@ -21,6 +21,8 @@ let verify ~pub ~msg ~signature =
if verified
then
let fingerprint = Serialization.digest ver_key_bytes in
fingerprint = Utils.bytes_to_string pub
fingerprint = Utils.bytes_to_hex pub
else false
with _ -> false
with
| _ ->
false

0 comments on commit 855272b

Please sign in to comment.