Crypto: add PVSS support

This commit is contained in:
Arthur B 2018-08-31 11:00:55 +02:00 committed by Grégoire Henry
parent 7206ccd560
commit 7a8fadb2f6
No known key found for this signature in database
GPG Key ID: 50D984F20BD445D2
15 changed files with 1394 additions and 4 deletions

View File

@ -344,6 +344,8 @@ module Prefix = struct
(* 33 *)
let secp256k1_public_key = "\003\254\226\086" (* sppk(55) *)
let p256_public_key = "\003\178\139\127" (* p2pk(55) *)
let secp256k1_scalar = "\038\248\136" (* SSp(53) *)
let secp256k1_element = "\005\092\000" (* GSp(54) *)
(* 64 *)
let ed25519_secret_key = "\043\246\078\007" (* edsk(98) *)

View File

@ -53,6 +53,8 @@ module Prefix : sig
val generic_signature: string
val chain_id: string
val secp256k1_element: string
val secp256k1_scalar: string
end

321
src/lib_crypto/pvss.ml Normal file
View File

@ -0,0 +1,321 @@
(*****************************************************************************)
(* *)
(* 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. *)
(* *)
(*****************************************************************************)
module H = Blake2B
(** Polynomial ring (/q)[X] *)
module PZ_q (Z_q : Znz.ZN) : sig
type t
module Z_q : Znz.ZN
(** Evaluates the polynomial p at point x *)
val eval : p:t -> x:Z_q.t -> Z_q.t
(** Builds the polynomial from a list of coefficient, ordered by power.
That is, of_list [a; a; a; ] = a + a x + a x² + *)
val of_list : Z_q.t list -> t
end with type Z_q.t = Z_q.t = struct
module Z_q = Z_q
type t = Z_q.t list
let eval ~p ~x = List.fold_right (fun c y -> Z_q.(y * x + c)) p Z_q.zero
let of_list l = l
end
(** Functor type for an Cyclic group *)
module type CYCLIC_GROUP = sig
type t
include S.B58_DATA with type t := t
include S.ENCODER with type t := t
val name : string
module Z_m : Znz.ZN
val e : t
val g1 : t
val g2 : t
val ( * ) : t -> t -> t
val (=) : t -> t -> bool
val pow : t -> Z_m.t -> t
val to_bits : t -> String.t
val of_bits : String.t -> t option
end
(** Type of a module that handles proofs for the discrete logarithm
equality equation. *)
module type DLEQ = sig
(** A DLEQ equation. *)
type equation
(** A non-interactive zero-knowledge proof-of-knowledge of an
exponent solving the equation. *)
type proof
val proof_encoding : proof Data_encoding.t
(** Group element. *)
type element
(** Exponent, i.e. an integer modulo the group's order. *)
type exponent
(** Sets up a equation of the form
i, x(i), bˣ = h and bᵢˣ = h. The arguments
are given as b, h, b, h *)
val setup_equation :
element -> element list -> element list -> element list -> equation
(** Creates a zero-knowledge proof of knowledge of the exponent list *)
val make_proof : equation -> exponent list -> proof
(** Checkes the proof created by make_proof for a given equation *)
val check_proof : equation -> proof -> bool
end
(** Functor for creating a module handling proofs for the discrete logarithm
equality in cyclic group G *)
module MakeDleq (G : CYCLIC_GROUP) :
DLEQ with type element = G.t and type exponent = G.Z_m.t =
struct
type element = G.t
type exponent = G.Z_m.t
type equation = element * (element list) * (element list) * (element list)
type proof = exponent * (exponent list)
let proof_encoding = Data_encoding.(
tup2 G.Z_m.encoding (list G.Z_m.encoding))
(* Fiat-Shamir heuristic to derive a random element of /m from the
hash of a list of group elements *)
let fiat_shamir ?(exponents=[]) elements =
String.concat "||" (
"tezosftw" :: (List.map G.to_bits elements) @ (List.map G.Z_m.to_bits exponents)
) |> (fun x -> H.hash_string [x]) |> H.to_string |> G.Z_m.of_bits_exn
let setup_equation b1 h1_n b2_n h2_n = (b1, h1_n, b2_n, h2_n)
let make_proof (b1, h1_n, b2_n, h2_n) x_n =
(* First, draw blinding factors. Normally these should be picked randomly. To maximize
reproducibility and avoid weak random number generation, we generate the blinding
factor deterministically from the problem parameters and the secret x_n.
TODO: review with cryptographer
*)
let
pseudo_seed = fiat_shamir (b1::(List.concat [h1_n; b2_n; h2_n])) ~exponents:x_n in
let
w_n = List.mapi (fun i __ -> fiat_shamir [] ~exponents:[pseudo_seed; G.Z_m.of_int i]) h1_n in let
a1_n = List.map (G.pow b1) w_n and
a2_n = List.map2 G.pow b2_n w_n in let
(* Pick the challenge, c, following the Fiat-Shamir heuristic. *)
c = fiat_shamir (List.concat [h1_n; h2_n; a1_n; a2_n]) in let
(* rᵢ = wᵢ - c * xᵢ *)
r_n = List.map2 (fun w x -> G.Z_m.(w - c * x)) w_n x_n in
(c, r_n)
let check_proof (b1, h1_n, b2_n, h2_n) (c, r_n) =
(* First check that the lists have the same sizes. *)
let same_sizes = List.(
Compare.Int.((length h1_n) = (length b2_n) && (length b2_n) = (length h2_n) &&
(length h2_n) = (length r_n))) in
if not same_sizes then false
else
let
a1_n = List.map2 G.( * )
(List.map (G.pow b1) r_n)
(List.map (fun h1 -> G.pow h1 c) h1_n)
and
a2_n = List.map2 G.( * )
(List.map2 G.pow b2_n r_n)
(List.map (fun h2 -> G.pow h2 c) h2_n)
in
G.Z_m.(c = fiat_shamir (List.concat [h1_n; h2_n; a1_n; a2_n]))
end
module type PVSS = sig
module type ENCODED = sig
type t
include S.B58_DATA with type t := t
include S.ENCODER with type t := t
end
module Commitment : ENCODED
module Encrypted_share : ENCODED
module Clear_share : ENCODED
module Public_key : ENCODED
module Secret_key : sig
include ENCODED
val to_public_key : t -> Public_key.t
end
type proof
val proof_encoding : proof Data_encoding.t
val dealer_shares_and_proof:
secret:Secret_key.t -> t:int -> public_keys:Public_key.t list ->
(Encrypted_share.t list * Commitment.t list * proof)
val check_dealer_proof:
Encrypted_share.t list -> Commitment.t list -> proof:proof ->
public_keys:Public_key.t list -> bool
val reveal_share : Encrypted_share.t -> secret_key:Secret_key.t
-> public_key:Public_key.t -> Clear_share.t * proof
val check_revealed_share:
Encrypted_share.t -> Clear_share.t -> public_key:Public_key.t -> proof
-> bool
val reconstruct: Clear_share.t list -> int list -> Public_key.t
end
module MakePvss (G : CYCLIC_GROUP) : PVSS = struct
module type ENCODED = sig
type t
include S.B58_DATA with type t := t
include S.ENCODER with type t := t
end
(* Module to make discrete logarithm equality proofs *)
module Dleq = MakeDleq (G)
type proof = Dleq.proof
(* Polynomials over /m *)
module PZ_m = PZ_q (G.Z_m)
(* A public key is a group element *)
module Public_key = G
module Secret_key = struct
include G.Z_m
let to_public_key x = G.(pow g2 x)
end
module Encrypted_share = G
module Clear_share = G
module Commitment = G
let proof_encoding = Dleq.proof_encoding
(* generate a "random": polynomial of degree t to hide secret `secret` *)
let random_polynomial secret t =
(* the t-1 coefficients are computed deterministically from
the secret and mapped to G.Z_m *)
let nonce = [String.concat "||" [G.Z_m.to_bits secret]]
|> H.hash_string |> H.to_string in
(* TODO: guard against buffer overlow *)
let rec make_coefs = function
| 0 -> []
| k -> let h =
( H.hash_string [string_of_int k; "||"; nonce])
|> H.to_string |> G.Z_m.of_bits_exn in
h :: make_coefs (k-1) in
let coefs = secret :: (make_coefs (t-1)) in
(* let coefs = secret :: List_Utils.list_init ~f:G.Z_m.random ~n:(t-1) in *)
let poly = PZ_m.of_list coefs
in (coefs, poly)
(* Hides secret s in a random polynomial of degree t, publishes t commitments
to the polynomial coefficients and n encrypted shares for the holders of
the public keys *)
let dealer_shares_and_proof ~secret ~t ~public_keys =
let coefs, poly = random_polynomial secret t in
let
(* Cⱼ represents the commitment to the coefficients of the polynomial
Cⱼ = g^(aⱼ) for j in 0 to t-1 *)
cC_j = List.map G.(pow g1) coefs and
(* pᵢ = p(i) for i in 1…n, with i ∈ /m: points of the polynomial. *)
p_i = List.mapi (fun i _ ->
PZ_m.eval ~p:poly ~x:(i+1 |> G.Z_m.of_int)) public_keys in let
(* yᵢ = pkᵢᵖ⁽ⁱ⁾ for i ∈ 1…n: the value of p(i) encrypted with pkᵢ,
the public key of the party receiving the iᵗʰ party. The public
keys use the g generator of G. Thus pkᵢ = gˢᵏⁱ *)
y_i = List.map2 G.pow public_keys p_i and
(* xᵢ = g₁ᵖ⁽ⁱ⁾ for in in 1…n: commitment to polynomial points *)
x_i = List.map G.(pow g1) p_i in let
equation = Dleq.setup_equation G.g1 x_i public_keys y_i in let
proof = Dleq.make_proof equation p_i
in (y_i, cC_j, proof)
let check_dealer_proof y_i cC_j ~proof ~public_keys =
(* Reconstruct Xᵢ from Cⱼ *)
let x_i =
(* prod_C_j_to_the__i_to_the_j = i ↦ Πⱼ₌₀ᵗ⁻¹ Cⱼ^() *)
let prod_C_j_to_the__i_to_the_j i =
List.mapi (fun j cC ->G.pow cC (G.Z_m.pow i (Z.of_int j)))
cC_j |> (List.fold_left G.( * ) G.e)
in
List.mapi (fun i _ ->
prod_C_j_to_the__i_to_the_j (i+1 |> G.Z_m.of_int)) y_i
in let
equation = Dleq.setup_equation G.g1 x_i public_keys y_i in
Dleq.check_proof equation proof
(* reveal a share *)
let reveal_share y ~secret_key ~public_key =
match G.Z_m.inv secret_key with
| None -> failwith "Invalid secret key"
| Some inverse_key ->
let reveal = G.(pow y inverse_key) in
(* y = g₂^(private_key) and public_key = reveal^(private_key) *)
let equation = Dleq.setup_equation G.g2 [public_key] [reveal] [y] in
let proof = Dleq.make_proof equation [secret_key] in
(reveal, proof)
(* check the validity of a revealed share *)
let check_revealed_share share reveal ~public_key proof =
let equation = Dleq.setup_equation G.g2 [public_key] [reveal] [share] in
Dleq.check_proof equation proof
(* reconstruct the secret *)
let reconstruct reveals int_indices =
(* check that there enough reveals *)
let indices = List.map (fun x -> G.Z_m.of_int (1+x)) int_indices in
let lagrange i =
List.fold_left G.Z_m.( * ) G.Z_m.one (
List.map (
fun j ->
if G.Z_m.(j = i) then G.Z_m.one else
match G.Z_m.(inv (j - i)) with
| None -> failwith "Unexpected error inverting scalar."
| Some inverse -> G.Z_m.(j * inverse)
) indices)
in let lagrange = List.map lagrange indices in
List.fold_left G.( * ) G.e (List.map2 G.pow reveals lagrange)
end

111
src/lib_crypto/pvss.mli Normal file
View File

@ -0,0 +1,111 @@
(*****************************************************************************)
(* *)
(* 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. *)
(* *)
(*****************************************************************************)
(** PVSS protocol, following
@see Schoenmakers, B., 1999:
A simple publicly verifiable secret sharing scheme
and its application to electronic voting. Lecture Notes in Computer Science,
pp.148-164.
@see https://www.win.tue.nl/~berry/papers/crypto99.pdf
The protocol is expressed as a functor parametrized by a cyclic group
of prime order. Algebraic properties are enforced at the type level,
whenever reasonably possible.
*)
module type CYCLIC_GROUP = sig
type t
include S.B58_DATA with type t := t
include S.ENCODER with type t := t
val name : string
module Z_m : Znz.ZN
val e : t
val g1 : t
val g2 : t
val ( * ) : t -> t -> t
val (=) : t -> t -> bool
val pow : t -> Z_m.t -> t
(** Binary representation *)
val to_bits : t -> String.t
val of_bits : String.t -> t option
end
(** PVSS construction, based on a cyclic group G of prime order *)
module type PVSS = sig
module type ENCODED = sig
type t
include S.B58_DATA with type t := t
include S.ENCODER with type t := t
end
module Commitment : ENCODED
module Encrypted_share : ENCODED
module Clear_share : ENCODED
module Public_key : ENCODED
module Secret_key : sig
include ENCODED
val to_public_key : t -> Public_key.t
end
type proof
val proof_encoding : proof Data_encoding.t
val dealer_shares_and_proof:
secret:Secret_key.t -> t:int -> public_keys:Public_key.t list ->
(Encrypted_share.t list * Commitment.t list * proof)
(** Lets a dealer share a secret with a set of participant by breaking it into
pieces, encrypting it with the participant's public keys, and publishing
these encrypted shares. Any t participants can reconstruct the secret. A
zero-knowledge proof is produced showing that the dealer correctly
followed the protocol, making the protocol publicly verifiable. *)
val check_dealer_proof:
Encrypted_share.t list -> Commitment.t list -> proof:proof ->
public_keys:Public_key.t list -> bool
(** Checks the proof produced by the dealer, given the encrypted shares,
the commitment list, the proof, and the participant's public keys. *)
val reveal_share : Encrypted_share.t -> secret_key:Secret_key.t
-> public_key:Public_key.t -> Clear_share.t * proof
(** Lets a participant provably decrypt an encrypted share. *)
val check_revealed_share:
Encrypted_share.t -> Clear_share.t -> public_key:Public_key.t -> proof
-> bool
(** Checks that the participant honestly decrypted its share. *)
val reconstruct: Clear_share.t list -> int list -> Public_key.t
end
module MakePvss : functor (G: CYCLIC_GROUP) -> PVSS

View File

@ -0,0 +1,62 @@
(*****************************************************************************)
(* *)
(* 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. *)
(* *)
(*****************************************************************************)
open Secp256k1_group
module G : Pvss.CYCLIC_GROUP = struct
module Z_m = struct
include Group.Scalar
let n = Group.order
let ( + ) = Group.Scalar.add
let ( * ) = Group.Scalar.mul
let ( - ) = Group.Scalar.sub
let ( = ) = Group.Scalar.equal
let inv = Group.Scalar.inverse
end
include Group
let name = "secp256k1"
(* This pvss algorithm assumes the public keys of the participants receiving
shares are based on g2, so we set g2 to Group.g to match regular Secp256k1
public keys.
*)
let g1 = Group.h
let g2 = Group.g
(* We use a multiplicative notation in the pvss module, but
secp256k1 usually uses an additive notation. *)
let ( * ) = Group.(( + ))
let pow x n = Group.mul n x
let of_bits b =
try
Some (Group.of_bits_exn b)
with _ -> None
end
include Pvss.MakePvss (G)

View File

@ -0,0 +1,26 @@
(*****************************************************************************)
(* *)
(* 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. *)
(* *)
(*****************************************************************************)
include Pvss.PVSS

View File

@ -107,6 +107,22 @@ module type ENCODER = sig
end
module type PVSS = sig
type proof
module Clear_share : sig type t end
module Commitment : sig type t end
module Encrypted_share : sig type t end
module Public_key : sig
type t
include B58_DATA with type t := t
include ENCODER with type t := t
end
end
module type INDEXES = sig
type t

View File

@ -0,0 +1,280 @@
(*****************************************************************************)
(* *)
(* 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. *)
(* *)
(*****************************************************************************)
module Sp = Libsecp256k1.Internal
module type SCALAR_SIG = sig
type t
include S.B58_DATA with type t := t
include S.ENCODER with type t := t
val zero : t
val one : t
val of_Z : Z.t -> t
val to_Z : t -> Z.t
val of_int : int -> t
val add: t -> t -> t
val mul: t -> t -> t
val negate: t -> t
val sub : t -> t -> t
val of_bits_exn: string -> t
val to_bits: t -> string
val inverse: t -> t option
val pow: t -> Z.t -> t
val equal : t -> t -> bool
end
module Group : sig
val order: Z.t
module Scalar : SCALAR_SIG
type t
include S.B58_DATA with type t := t
include S.ENCODER with type t := t
val e: t
val g: t
val h: t
val of_coordinates: x:Z.t -> y:Z.t -> t
val of_bits_exn: string -> t
val to_bits: t -> string
val mul: Scalar.t -> t -> t
val (+): t -> t -> t
val (-): t -> t -> t
val (=): t -> t -> bool
end = struct
let order = Z.of_string_base 16 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"
let string_rev s =
let len = String.length s in
String.init len (fun i -> s.[len - 1 - i])
let b32_of_Z z =
let cs = Cstruct.create 32 in
let bits = Z.to_bits z in
let length = (min 32 (String.length bits)) in
let bits = String.sub bits 0 length in
let bits = string_rev bits in
Cstruct.blit_from_string bits 0 cs (32 - length) length;
cs
let z_of_b32 b =
b |> Cstruct.to_string |> string_rev |> Z.of_bits
module Scalar : SCALAR_SIG with type t = Sp.Scalar.t = struct
type t = Sp.Scalar.t
let zero = Sp.Scalar.zero ()
let one = Sp.Scalar.one ()
let equal x y = Sp.Scalar.equal x y
let of_Z z =
let z = Z.erem z order in
let r = Sp.Scalar.const () in
let cs = b32_of_Z z in
let _ = Sp.Scalar.set_b32 r cs in r
let to_Z s =
let cs = Cstruct.create 32 in
Sp.Scalar.get_b32 cs s; cs |> z_of_b32
let of_int i = i |> Z.of_int |> of_Z
let pow t n =
Z.powm (to_Z t) n order |> of_Z
let add x y =
let r = Sp.Scalar.const () in
let _ = Sp.Scalar.add r x y in r
let mul x y =
let r = Sp.Scalar.const () in
Sp.Scalar.mul r x y; r
let negate x =
let r = Sp.Scalar.const () in
Sp.Scalar.negate r x; r
let sub x y =
add x (negate y)
let of_bits_exn bits =
let r = Sp.Scalar.const () in
(* trim to 32 bytes *)
let cs = Cstruct.create 32 in
Cstruct.blit_from_string bits 0 cs 0 (min (String.length bits) 32);
(* ignore overflow condition, it's always 0 based on the c-code *)
let _ = Sp.Scalar.set_b32 r cs in r
(* TODO, check that we are less than the order *)
let to_bits x =
let c = Cstruct.create 32 in
Sp.Scalar.get_b32 c x; Cstruct.to_string c
let inverse x =
if x = zero then
None else
let r = Sp.Scalar.const () in
Sp.Scalar.inverse r x; Some r
type Base58.data +=
| Data of t
let b58check_encoding =
Base58.register_encoding
~prefix: Base58.Prefix.secp256k1_scalar
~length: 32
~to_raw: to_bits
~of_raw: (fun s -> try Some (of_bits_exn s) with _ -> None)
~wrap: (fun x -> Data x)
let title = "Secp256k1_group.Scalar"
let name = "Anscalar for the secp256k1 group"
include Helpers.MakeB58(struct
type nonrec t = t
let title = title
let name = name
let b58check_encoding = b58check_encoding
end)
include Helpers.MakeEncoder(struct
type nonrec t = t
let name = name
let title = title
let raw_encoding = Data_encoding.(conv to_bits of_bits_exn string)
let to_b58check = to_b58check
let to_short_b58check = to_short_b58check
let of_b58check = of_b58check
let of_b58check_opt = of_b58check_opt
let of_b58check_exn = of_b58check_exn
end)
end
type t = Sp.Group.Jacobian.t
(* type ge = Sp.Group.ge *)
let field_of_Z z =
let fe = Sp.Field.const () in
let cs = b32_of_Z z in
let _ = Sp.Field.set_b32 fe cs in fe
let group_of_jacobian j =
let r = Sp.Group.of_fields () in
Sp.Group.Jacobian.get_ge r j; r
let jacobian_of_group g =
let j = Sp.Group.Jacobian.of_fields () in
Sp.Group.Jacobian.set_ge j g; j
let of_coordinates ~x ~y =
Sp.Group.of_fields
~x:(field_of_Z x) ~y:(field_of_Z y) () |> jacobian_of_group
let e =
Sp.Group.Jacobian.of_fields ~infinity:true ()
let g =
let gx = Z.of_string "55066263022277343669578718895168534326250603453777594175500187360389116729240"
and gy = Z.of_string "32670510020758816978083085130507043184471273380659243275938904335757337482424" in
of_coordinates ~x:gx ~y:gy
(* To obtain the second generator, take the sha256 hash of the decimal representation of g1_y
python -c "import hashlib;print int(hashlib.sha256('32670510020758816978083085130507043184471273380659243275938904335757337482424').hexdigest(),16)"
*)
let h =
let hx = Z.of_string "54850469061264194188802857211425616972714231399857248865148107587305936171824"
and hy = Z.of_string "6558914719042992724977242403721980463337660510165027616783569279181206179101" in
of_coordinates ~x:hx ~y:hy
let (+) x y =
let r = Sp.Group.Jacobian.of_fields () in
Sp.Group.Jacobian.add_var r x y; r
let (-) x y =
let neg_y = Sp.Group.Jacobian.of_fields () in
Sp.Group.Jacobian.neg neg_y y; x + neg_y
let (=) x y = Sp.Group.Jacobian.is_infinity (x - y)
let mul s g =
let r = Sp.Group.Jacobian.of_fields () in
Sp.Group.Jacobian.mul r (group_of_jacobian g) s; r
let to_bits j =
let x = group_of_jacobian j
and buf = Cstruct.create 33 in
let cs = (Sp.Group.to_pubkey ~compress:true buf x) in
Cstruct.to_string cs
let of_bits_exn bits =
let buf = Cstruct.of_string bits
and x = Sp.Group.of_fields () in
Sp.Group.from_pubkey x buf;
x |> jacobian_of_group
module Encoding = struct
type Base58.data +=
| Data of t
let title = "Secp256k1_group.Group"
let name = "An element of secp256k1"
let b58check_encoding =
Base58.register_encoding
~prefix: Base58.Prefix.secp256k1_element
~length: 33
~to_raw: to_bits
~of_raw: (fun s -> try Some (of_bits_exn s) with _ -> None)
~wrap: (fun x -> Data x)
include Helpers.MakeB58(
struct
type nonrec t = t
let title = title
let name = name
let b58check_encoding = b58check_encoding
end)
include Helpers.MakeEncoder(
struct
type nonrec t = t
let name = name
let title = title
let raw_encoding = Data_encoding.(conv to_bits of_bits_exn string)
let to_b58check = to_b58check
let to_short_b58check = to_short_b58check
let of_b58check = of_b58check
let of_b58check_opt = of_b58check_opt
let of_b58check_exn = of_b58check_exn
end
)
end
include Encoding
end

View File

@ -0,0 +1,72 @@
(*****************************************************************************)
(* *)
(* 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. *)
(* *)
(*****************************************************************************)
(** Type for the group of integers modulo the order of the curve /p *)
module type SCALAR_SIG = sig
(** Element of the scalar group *)
type t
include S.B58_DATA with type t := t
include S.ENCODER with type t := t
val zero : t
val one : t
val of_Z : Z.t -> t
val to_Z : t -> Z.t
val of_int : int -> t
val add: t -> t -> t
val mul: t -> t -> t
val negate: t -> t
val sub: t -> t -> t
val of_bits_exn: string -> t
val to_bits: t -> string
val inverse: t -> t option
(** Modular exponentiation*)
val pow: t -> Z.t -> t
val equal: t -> t -> bool
end
module Group : sig
type t
include S.B58_DATA with type t := t
include S.ENCODER with type t := t
val order: Z.t
module Scalar : SCALAR_SIG
val e: t
val g : t
val h : t
val of_coordinates: x:Z.t -> y:Z.t -> t
val of_bits_exn: string -> t
val to_bits: t -> string
val mul: Scalar.t -> t -> t
val (+): t -> t -> t
val (-): t -> t -> t
val (=): t -> t -> bool
end

View File

@ -2,21 +2,25 @@
(names test_merkle
test_base58
test_ed25519
test_blake2b)
test_blake2b
test_pvss)
(libraries tezos-stdlib
tezos-crypto
tezos-data-encoding
alcotest)
(flags (:standard -w -9-32
-safe-string
-open Tezos_stdlib
-open Tezos_crypto)))
-open Tezos_crypto
-open Tezos_data_encoding)))
(alias
(name buildtest)
(deps test_merkle.exe
test_base58.exe
test_ed25519.exe
test_blake2b.exe))
test_blake2b.exe
test_pvss.exe))
(alias
(name runtest_merkle)
@ -34,12 +38,17 @@
(name runtest_blake2b)
(action (run %{exe:test_blake2b.exe})))
(alias
(name runtest_pvss)
(action (run %{exe:test_pvss.exe})))
(alias
(name runtest)
(deps (alias runtest_merkle)
(alias runtest_base58)
(alias runtest_ed25519)
(alias runtest_blake2b)))
(alias runtest_blake2b)
(alias runtest_pvss)))
(alias
(name runtest_indent)

View File

@ -0,0 +1,168 @@
(*****************************************************************************)
(* *)
(* 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. *)
(* *)
(*****************************************************************************)
(* pvss tests here *)
module Pvss = Pvss_secp256k1
module Sp = Secp256k1_group
module Setup : sig
val shares : Pvss.Encrypted_share.t list
val commitments: Pvss.Commitment.t list
val proof: Pvss.proof
val secret_scalar : Sp.Group.Scalar.t
val secret: Pvss.Secret_key.t
val public_secret: Pvss.Public_key.t
val other_shares : Pvss.Encrypted_share.t list
val other_commitments: Pvss.Commitment.t list
val other_proof: Pvss.proof
val other_secret: Pvss.Secret_key.t
type keypair = {secret_key: Pvss.Secret_key.t; public_key: Pvss.Public_key.t}
val public_keys : Pvss.Public_key.t list
val keypairs : keypair list
val reveals : (Pvss.Encrypted_share.t * (Pvss.Clear_share.t * Pvss.proof)) list
val convert_encoding : 'a Data_encoding.t -> 'b Data_encoding.t -> 'a -> 'b
val group_encoding : Sp.Group.t Data_encoding.t
end = struct
type keypair = {secret_key: Pvss.Secret_key.t; public_key: Pvss.Public_key.t}
let group_encoding = Data_encoding.(conv Sp.Group.to_bits Sp.Group.of_bits_exn string)
let scalar_encoding = Data_encoding.(conv Sp.Group.Scalar.to_bits Sp.Group.Scalar.of_bits_exn string)
let convert_encoding de1 de2 x =
Data_encoding.Binary.of_bytes_exn de2
(Data_encoding.Binary.to_bytes_exn de1 x)
(** Random value of Z in the range [0,2^256] *)
let rand_Z () =
[Random.int64 Int64.max_int |> Z.of_int64 |> Z.to_bits]
|> Blake2B.hash_string |> Blake2B.to_string |> Z.of_bits
(** Generates n random keypairs *)
let random_keypairs n =
List.init n
(fun _ -> let s = Sp.Group.Scalar.of_Z (rand_Z ()) in
let secret_key = convert_encoding scalar_encoding Pvss.Secret_key.encoding s in
{ secret_key ; public_key = Pvss.Secret_key.to_public_key secret_key })
(** Convert a secret_key to a public key *)
let public secret_key =
convert_encoding group_encoding Pvss.Public_key.encoding
(Sp.Group.mul secret_key Sp.Group.g)
let t = 5
let n = 8
let random_scalar () =
Sp.Group.Scalar.of_Z (rand_Z ())
let secret_of_scalar s =
convert_encoding scalar_encoding Pvss.Secret_key.encoding s
let secret_scalar = random_scalar ()
let secret = secret_of_scalar secret_scalar
let public_secret = Pvss.Secret_key.to_public_key secret
let other_secret= secret_of_scalar (random_scalar ())
let keypairs = random_keypairs n
let public_keys = List.map (fun {public_key} -> public_key) keypairs
let ((shares, commitments, proof),
(other_shares, other_commitments, other_proof)) =
(
Pvss.dealer_shares_and_proof ~secret ~t ~public_keys,
Pvss.dealer_shares_and_proof ~secret:other_secret ~t ~public_keys
)
let reveals = List.map2 (
fun share keypair ->
(share, Pvss.reveal_share share
~secret_key:keypair.secret_key ~public_key:keypair.public_key))
shares keypairs
end
let test_dealer_proof () =
let shr = (Setup.shares, Setup.other_shares)
and cmt = (Setup.commitments, Setup.other_commitments)
and prf = (Setup.proof, Setup.other_proof) in
begin
for i = 0 to 1 do
for j = 0 to 1 do
for k = 0 to 1 do
let pick = function 0 -> fst | _ -> snd in
assert ((Pvss.check_dealer_proof
(pick i shr)
(pick j cmt)
~proof:(pick k prf) ~public_keys:Setup.public_keys) = (i = j && j = k))
done
done
done
end
let test_share_reveal () =
(* check reveal shares *)
let shares_valid = List.map2 (fun (share, (reveal, proof)) public_key ->
Pvss.check_revealed_share share reveal ~public_key:public_key proof)
Setup.reveals Setup.public_keys in
List.iteri (fun i b -> print_endline (string_of_int i); assert b)
shares_valid
let test_reconstruct () =
let indices = [0;1;2;3;4] in
let reconstructed = Pvss.reconstruct
(List.map
(fun n -> let (_, (r, _)) = List.nth Setup.reveals n in r) indices
)
indices
in
assert (Sp.Group.((=))
(Setup.convert_encoding
Pvss.Public_key.encoding Setup.group_encoding reconstructed)
(Setup.convert_encoding
Pvss.Public_key.encoding Setup.group_encoding Setup.public_secret))
let tests = [
"dealer_proof", `Quick, test_dealer_proof ;
"reveal", `Quick, test_share_reveal ;
"recontruct", `Quick, test_reconstruct
]
let () =
Alcotest.run "test-pvss" [
"pvss", tests
]

116
src/lib_crypto/znz.ml Normal file
View File

@ -0,0 +1,116 @@
(*****************************************************************************)
(* *)
(* 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. *)
(* *)
(*****************************************************************************)
module type ZN = sig
type t
include S.B58_DATA with type t := t
include S.ENCODER with type t := t
val zero : t
val one : t
val n : Z.t
val (+) : t -> t -> t
val ( * ) : t -> t -> t
val (-) : t -> t -> t
val (=) : t -> t -> bool
val of_int : int -> t
val of_Z : Z.t -> t
val to_Z : t -> Z.t
val of_bits_exn : String.t -> t
val to_bits : t -> String.t
val pow : t -> Z.t -> t
val inv : t -> t option
end
module type INT = sig
val n : Z.t
end
module MakeZn (N : INT) (B : sig val b58_prefix : string end) : ZN = struct
type t = Z.t
let n = N.n
let max_char_length = 2 * (Z.numbits n)
let zero = Z.zero
let one = Z.one
let of_Z r = Z.(erem r n)
let to_Z a = a
let of_int u = u |> Z.of_int |> of_Z
let to_bits h = h |> Zplus.serialize |> (fun s -> String.sub s 0 (String.length s - 1))
let of_bits_exn bits =
(* Do not process oversized inputs. *)
if Compare.Int.((String.length bits) > max_char_length) then
failwith "input too long"
else
(* Make sure the input is in the range [0, N.n-1]. Do not reduce modulo
N.n for free! *)
let x = Zplus.deserialize (bits) in
if Zplus.(x < zero || x >= N.n) then
failwith "out of range"
else
of_Z x
let pow a x = Z.powm a Z.(erem x (sub n one)) n
let (+) x y = Z.(erem (add x y) n)
let ( * ) x y = Z.(erem (mul x y) n)
let (-) x y = Z.(erem (sub x y) n)
let (=) x y = Z.equal x y
let inv a = Zplus.invert a n
let title = Format.sprintf "Znz.Make(%s)" (Z.to_string N.n)
let name = Format.sprintf "An element of Z/nZ for n = %s" (Z.to_string N.n)
type Base58.data +=
| Data of t
let b58check_encoding =
Base58.register_encoding
~prefix: B.b58_prefix
~length: 32
~to_raw: to_bits
~of_raw: (fun s -> try Some (of_bits_exn s) with _ -> None)
~wrap: (fun x -> Data x)
include Helpers.MakeB58(struct
type nonrec t = t
let title = title
let name = name
let b58check_encoding = b58check_encoding
end)
include Helpers.MakeEncoder(struct
type nonrec t = t
let name = name
let title = title
let raw_encoding = Data_encoding.(conv to_bits of_bits_exn string)
let to_b58check = to_b58check
let to_short_b58check = to_short_b58check
let of_b58check = of_b58check
let of_b58check_opt = of_b58check_opt
let of_b58check_exn = of_b58check_exn
end)
end

73
src/lib_crypto/znz.mli Normal file
View File

@ -0,0 +1,73 @@
(*****************************************************************************)
(* *)
(* 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. *)
(* *)
(*****************************************************************************)
(** Type for a module representing the /n ring*)
module type ZN = sig
type t
include S.B58_DATA with type t := t
include S.ENCODER with type t := t
val zero : t
val one : t
val n : Z.t
val (+) : t -> t -> t
val ( * ) : t -> t -> t
val (-) : t -> t -> t
val (=) : t -> t -> bool
(** Converts an integer to a ring element *)
val of_int : int -> t
(** Converts a Zarith integer to a ring element *)
val of_Z : Z.t -> t
(** Provides an integer representation between 0 and n-1 of an element *)
val to_Z : t -> Z.t
(** Converts a string of bytes to an integer modulo n, requires the string of
byte to represent an integer between 0 and n-1 and checks the length of
the string for sanity*)
val of_bits_exn : String.t -> t
(** Converts a ring element to a byte representation *)
val to_bits : t -> String.t
(** Modular exponentiation *)
val pow : t -> Z.t -> t
(** Returns the inverse of a in /n, maybe *)
val inv : t -> t option
end
(** Type of a module wrapping an integer. *)
module type INT = sig
val n : Z.t
end
(** Functor to build the /n ring given n*)
module MakeZn : functor (N : INT) (B : sig val b58_prefix : string end) -> ZN

73
src/lib_crypto/zplus.ml Normal file
View File

@ -0,0 +1,73 @@
(*****************************************************************************)
(* *)
(* 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. *)
(* *)
(*****************************************************************************)
(* let re_trailing_null =
Re_pcre.regexp "^(.*?)\000*$"
let remove_trailing_null s =
Re.get (Re.exec re_trailing_null s) 1 *)
let remove_trailing_null s =
let n = String.length s in
let i = ref (n-1) in
while (!i >= 0) && (String.get s !i = '\000') do
i := !i - 1
done; String.sub s 0 (!i+1)
let serialize z =
let n =
if Z.(lt z zero) then
Z.(neg (add (add z z) one))
else
Z.(add z z)
in
n |> Z.to_bits |> remove_trailing_null
let deserialize z =
let n = Z.of_bits z in
let z = Z.shift_right_trunc n 1 in
if Z.(n land one = zero) then z else Z.neg z
let leq a b = (Z.compare a b) <= 0
let geq a b = (Z.compare a b) >= 0
let lt a b = (Z.compare a b) < 0
let gt a b = (Z.compare a b) > 0
let (<) = lt
let (>) = gt
let (<=) = leq
let (>=) = geq
let zero = Z.zero
let one = Z.one
let invert a n =
try
Some (Z.invert a n)
with
Division_by_zero -> None

59
src/lib_crypto/zplus.mli Normal file
View File

@ -0,0 +1,59 @@
(*****************************************************************************)
(* *)
(* 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. *)
(* *)
(*****************************************************************************)
val serialize: Z.t -> string
val deserialize: string -> Z.t
val leq: Z.t -> Z.t -> bool
(** Less than or equal. *)
val geq: Z.t -> Z.t -> bool
(** Greater than or equal. *)
val lt: Z.t -> Z.t -> bool
(** Less than (and not equal). *)
val gt: Z.t -> Z.t -> bool
(** Greater than (and not equal). *)
val (<=): Z.t -> Z.t -> bool
(** Less than or equal. *)
val (>=): Z.t -> Z.t -> bool
(** Greater than or equal. *)
val (<): Z.t -> Z.t -> bool
(** Less than (and not equal). *)
val (>): Z.t -> Z.t -> bool
(** Greater than (and not equal). *)
val zero: Z.t
val one: Z.t
val invert: Z.t -> Z.t -> Z.t option
(** Invert the first argument modulo the second. Returns
none if there is no inverse *)