Commit fce75cfd authored by Stephane Glondu's avatar Stephane Glondu

Implement factor computation / verification

parent f079fd90
......@@ -74,7 +74,7 @@ module MakeHomomorphicElection (P : Crypto_sigs.ELECTION_PARAMS) = struct
beta = c1.beta *~ c2.beta;
}
let combine_ciphertexts = Array.map2ij eg_combine
let combine_ciphertexts = Array.mmap2 eg_combine
type plaintext = int array array
type ballot = public_key Serializable_t.ballot
......@@ -177,6 +177,11 @@ module MakeHomomorphicElection (P : Crypto_sigs.ELECTION_PARAMS) = struct
let overall_proof = eg_disj_prove d (summ - q.q_min) sumr sumc in
{choices; individual_proofs; overall_proof}
let create_randomness () =
Array.map (fun q ->
Array.init (Array.length q.q_answers) (fun _ -> random G.q)
) params.e_questions
let create_ballot r m =
{
answers = Array.map3 create_answer params.e_questions r m;
......@@ -201,9 +206,24 @@ module MakeHomomorphicElection (P : Crypto_sigs.ELECTION_PARAMS) = struct
type factor = public_key Serializable_t.partial_decryption
let compute_factor c x = assert false
let check_factor c y f = assert false
let eg_factor x {alpha; beta} =
alpha **~ x,
fs_prove [| g; alpha |] x hash
let compute_factor c x =
let res = Array.mmap (eg_factor x) c in
let decryption_factors, decryption_proofs = Array.ssplit res in
{decryption_factors; decryption_proofs}
let check_factor c y f =
Array.fforall3 (fun {alpha; _} f {challenge; response} ->
let commitments =
[|
g **~ response / (y **~ challenge);
alpha **~ response / (f **~ challenge);
|]
in hash commitments =% challenge
) c f.decryption_factors f.decryption_proofs
type result = public_key Serializable_t.result
......
......@@ -88,8 +88,12 @@ module type HOMOMORPHIC = sig
type randomness = Z.t array array
(** Randomness needed to create a ballot. *)
val create_randomness : unit -> randomness
(** Creates randomness for [create_ballot] below. The result can be
kept for Benaloh-style auditing. *)
val create_ballot : randomness -> plaintext -> ballot
(** [create_ballot answers] creates a ballot, or raises
(** [create_ballot r answers] creates a ballot, or raises
[Invalid_argument] if [answers] doesn't satisfy the election
constraints. *)
......@@ -107,7 +111,7 @@ module type HOMOMORPHIC = sig
private key share and the encrypted tally, and contains a
cryptographic proof that he or she didn't cheat. *)
val compute_factor : randomness -> ciphertext -> private_key -> factor
val compute_factor : ciphertext -> private_key -> factor
val check_factor : ciphertext -> public_key -> factor -> bool
(** [check_factor c pk f] checks that [f], supposedly submitted by a
......
......@@ -44,9 +44,17 @@ let of_ballot b =
let open Serializable_t in
{answers; election_hash; election_uuid}
let of_partial_decryption p =
let {decryption_factors; decryption_proofs} = p in
let decryption_proofs = Array.mmap of_proof decryption_proofs in
let open Serializable_t in
{decryption_factors; decryption_proofs}
module type COMPAT = sig
type t
val to_ballot : t Serializable_t.ballot -> t ballot
val to_partial_decryption : t Serializable_t.ciphertext array array ->
t Serializable_t.partial_decryption -> t partial_decryption
end
module MakeCompat (P : Crypto_sigs.ELECTION_PARAMS) = struct
......@@ -114,9 +122,13 @@ module MakeCompat (P : Crypto_sigs.ELECTION_PARAMS) = struct
let to_answer a q =
let {choices; individual_proofs; overall_proof} = a in
let individual_proofs = Array.map2 (recommit d01) individual_proofs choices in
let individual_proofs =
Array.map2 (recommit d01) individual_proofs choices
in
let sumc = Array.fold_left eg_combine dummy_ciphertext choices in
let overall_proof = recommit (make_d q.q_min q.q_max) overall_proof sumc in
let overall_proof =
recommit (make_d q.q_min q.q_max) overall_proof sumc
in
let open Serializable_compat_t in
{choices; individual_proofs; overall_proof}
......@@ -125,4 +137,22 @@ module MakeCompat (P : Crypto_sigs.ELECTION_PARAMS) = struct
let answers = Array.map2 to_answer answers params.e_questions in
let open Serializable_compat_t in
{answers; election_hash; election_uuid}
let to_partial_decryption c p =
let {decryption_factors; decryption_proofs} = p in
let decryption_proofs =
Array.mmap3 (fun {alpha; _} f {challenge; response} ->
let open Serializable_compat_t in
let dp_commitment = {
a = g **~ response / (y **~ challenge);
b = alpha **~ response / (f **~ challenge);
} in {
dp_commitment;
dp_challenge = challenge;
dp_response = response;
}
) c decryption_factors decryption_proofs
in
let open Serializable_compat_t in
{decryption_factors; decryption_proofs}
end
......@@ -4,10 +4,14 @@ open Serializable_compat_t
val of_election : 'a election -> 'a Serializable_t.election
val of_ballot : 'a ballot -> 'a Serializable_t.ballot
val of_partial_decryption :
'a partial_decryption -> 'a Serializable_t.partial_decryption
module type COMPAT = sig
type t
val to_ballot : t Serializable_t.ballot -> t ballot
val to_partial_decryption : t Serializable_t.ciphertext array array ->
t Serializable_t.partial_decryption -> t partial_decryption
end
module MakeCompat (P : Crypto_sigs.ELECTION_PARAMS) :
......
......@@ -25,13 +25,39 @@ module Array = struct
else true
in loop (pred (Array.length x))
let fforall3 f xs ys zs =
let rec loop_outer i =
if i >= 0 then
let x = xs.(i) and y = ys.(i) and z = zs.(i) in
let n = Array.length x in
n = Array.length y &&
n = Array.length z &&
let rec loop_inner j =
if j >= 0 then f x.(j) y.(j) z.(j) && loop_inner (pred j)
else true
in loop_inner (pred n)
else true
in
let n = Array.length xs in
n = Array.length ys &&
n = Array.length zs &&
loop_outer (pred n)
let map2 f a b =
Array.mapi (fun i ai -> f ai b.(i)) a
let map2i f a b =
Array.mapi (fun i ai -> f i ai b.(i)) a
let map2ij f a b =
let map3 f a b c =
Array.mapi (fun i ai -> f ai b.(i) c.(i)) a
let mmap f a =
Array.map (fun ai ->
Array.map f ai
) a
let mmap2 f a b =
Array.mapi (fun i ai ->
let bi = b.(i) in
Array.mapi (fun j aj ->
......@@ -39,8 +65,16 @@ module Array = struct
) ai
) a
let map3 f a b c =
Array.mapi (fun i ai -> f ai b.(i) c.(i)) a
let mmap3 f a b c =
Array.mapi (fun i ai ->
let bi = b.(i) and ci = c.(i) in
Array.mapi (fun j aj ->
f aj bi.(j) ci.(j)
) ai
) a
let ssplit a =
mmap fst a, mmap snd a
end
module List = struct
......@@ -85,7 +119,9 @@ let non_empty_lines_of_file fname =
Lwt_stream.filter (fun s -> s <> "") |>
Lwt_stream.to_list
let prng = Cryptokit.Random.(pseudo_rng (string secure_rng 32))
let seed = lazy (Cryptokit.Random.(string secure_rng 32))
let prng = Cryptokit.Random.(pseudo_rng (Lazy.force seed))
let random q =
let size = Z.size q * Sys.word_size / 8 in
......
......@@ -11,10 +11,18 @@ module Array : sig
val forall : ('a -> bool) -> 'a array -> bool
val forall2 : ('a -> 'b -> bool) -> 'a array -> 'b array -> bool
val foralli : (int -> 'a -> bool) -> 'a array -> bool
val fforall3 : ('a -> 'b -> 'c -> bool) ->
'a array array -> 'b array array -> 'c array array -> bool
val map2 : ('a -> 'b -> 'c) -> 'a array -> 'b array -> 'c array
val map2i : (int -> 'a -> 'b -> 'c) -> 'a array -> 'b array -> 'c array
val map2ij : ('a -> 'b -> 'c) -> 'a array array -> 'b array array -> 'c array array
val map3 : ('a -> 'b -> 'c -> 'd) -> 'a array -> 'b array -> 'c array -> 'd array
val map3 : ('a -> 'b -> 'c -> 'd) ->
'a array -> 'b array -> 'c array -> 'd array
val mmap : ('a -> 'b) -> 'a array array -> 'b array array
val mmap2 : ('a -> 'b -> 'c) ->
'a array array -> 'b array array -> 'c array array
val mmap3 : ('a -> 'b -> 'c -> 'd) ->
'a array array -> 'b array array -> 'c array array -> 'd array array
val ssplit : ('a * 'b) array array -> 'a array array * 'b array array
end
module String : sig
......@@ -25,7 +33,8 @@ end
val hashB : string -> string
val load_from_file : (Yojson.lexer_state -> Lexing.lexbuf -> 'a) -> string -> 'a
val load_from_file : (Yojson.lexer_state -> Lexing.lexbuf -> 'a) ->
string -> 'a
val non_empty_lines_of_file : string -> string list Lwt.t
val random : Z.t -> Z.t
......@@ -254,3 +254,21 @@ let create_ballot b =
let test_ballot = create_ballot [| [| 1; 0; 0; 0 |] |];;
assert (Election.check_ballot test_ballot);;
let result =
match e.public_data.election_result with
| Some r -> r
| None -> assert false
let tally = result.encrypted_tally.tally;;
let fs = Array.map Serializable_compat.of_partial_decryption result.partial_decryptions;;
assert (Array.forall2 (fun f f' -> f = Compat.to_partial_decryption tally f') result.partial_decryptions fs);;
let ys = Array.map (fun x -> x.trustee_public_key.y) e.public_data.public_keys;;
assert (Array.forall2 (Election.check_factor tally) ys fs);;
let y = ys.(0);;
let x = Z.of_string "45298523167338358817538343074024028933886309805828157085973885299032584889325";;
assert (g **~ x =% y);;
let test_factor = Election.compute_factor tally x;;
assert (Election.check_factor tally y test_factor);;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment