Crypto: add PVSS support
This commit is contained in:
parent
7206ccd560
commit
7a8fadb2f6
@ -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) *)
|
||||
|
@ -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
321
src/lib_crypto/pvss.ml
Normal 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ⱼ^(iʲ) *)
|
||||
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
111
src/lib_crypto/pvss.mli
Normal 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
|
62
src/lib_crypto/pvss_secp256k1.ml
Normal file
62
src/lib_crypto/pvss_secp256k1.ml
Normal 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)
|
26
src/lib_crypto/pvss_secp256k1.mli
Normal file
26
src/lib_crypto/pvss_secp256k1.mli
Normal 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
|
@ -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
|
||||
|
280
src/lib_crypto/secp256k1_group.ml
Normal file
280
src/lib_crypto/secp256k1_group.ml
Normal 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
|
72
src/lib_crypto/secp256k1_group.mli
Normal file
72
src/lib_crypto/secp256k1_group.mli
Normal 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
|
@ -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)
|
||||
|
168
src/lib_crypto/test/test_pvss.ml
Normal file
168
src/lib_crypto/test/test_pvss.ml
Normal 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
116
src/lib_crypto/znz.ml
Normal 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
73
src/lib_crypto/znz.mli
Normal 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
73
src/lib_crypto/zplus.ml
Normal 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
59
src/lib_crypto/zplus.mli
Normal 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 *)
|
Loading…
Reference in New Issue
Block a user