demo.ml 4.48 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
open Util
open Serializable_t

let hashB x = Cryptokit.(x |>
  hash_string (Hash.sha256 ()) |>
  transform_string (Base64.encode_compact ())
);;

(* Setup group *)

Stephane Glondu's avatar
Stephane Glondu committed
11 12
module G = Election.DefaultGroup;;
assert G.(Election.check_finite_field ~p ~q ~g);;
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27

module M = Election.MakeSimpleMonad(G);;

(* Setup trustees *)

module KG = Election.MakeSimpleDistKeyGen(G)(M);;

let private_keys, public_keys =
  let rec loop i accu =
    if i >= 0
    then loop (pred i) (KG.generate_and_prove () () :: accu)
    else (
      let a, b = List.split accu in
      Array.of_list a, Array.of_list b
    )
Stephane Glondu's avatar
Stephane Glondu committed
28
  in loop 1 []
29 30 31 32 33 34
;;
assert (Array.forall KG.check public_keys);;
let y = KG.combine public_keys;;

(* Setup election *)

35
let params = {
Stephane Glondu's avatar
Stephane Glondu committed
36
  e_description = "This is a test election.";
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
  e_name = "Test election";
  e_public_key = y;
  e_questions =
    [|
      {
        q_answers = [| "a"; "b"; "c"; "d"; "e" |];
        q_min = 0;
        q_max = 1;
        q_question = "Question 1?";
      };
      {
        q_answers = [| "a"; "b"; "c"; "d"; "e"; "f" |];
        q_min = 2;
        q_max = 3;
        q_question = "Question 2?";
      };
      {
        q_answers = [| "a"; "b"; "c" |];
        q_min = 1;
        q_max = 1;
        q_question = "Question 3?";
      };
    |];
  e_uuid = Uuidm.create `V4;
  e_short_name = "test";
};;

64 65 66 67 68 69
let metadata =
  let open CalendarLib.Fcalendar.Precise in
  let now = now () in
  {
    e_voting_starts_at = add now Period.(day 1), None;
    e_voting_ends_at = add now Period.(day 8), None;
Stephane Glondu's avatar
Stephane Glondu committed
70
    e_voters_list = None;
71 72 73
  }
;;

74 75
module P = struct
  module G = G
76
  let params = params
77
  let metadata = Some metadata
78 79 80
  let public_keys = Lazy.lazy_from_val (
    public_keys |> Array.map (fun x -> x.trustee_public_key)
  )
81
  let fingerprint =
82 83
    params |>
    Serializable_j.string_of_params Serializable_builtin_j.write_number |>
84 85 86 87 88 89 90 91 92 93 94
    hashB
end;;

module E = Election.MakeElection(P)(M);;

(* Vote *)

let vote b =
  try
    let b = E.create_ballot (E.make_randomness () ()) b () in
    let ok = E.check_ballot b in
95
    if ok then M.cast b "anonymous" ();
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
    ok
  with _ -> false
;;

assert (vote [|[| 0; 0; 0; 0; 0 |]; [| 0; 1; 0; 1; 1; 0 |]; [| 0; 0; 1 |]|]);;
assert (vote [|[| 0; 0; 1; 0; 0 |]; [| 0; 1; 0; 1; 1; 0 |]; [| 0; 0; 1 |]|]);;
assert (vote [|[| 0; 0; 0; 0; 0 |]; [| 0; 1; 0; 1; 1; 0 |]; [| 1; 0; 0 |]|]);;
assert (vote [|[| 1; 0; 0; 0; 0 |]; [| 0; 1; 0; 1; 0; 0 |]; [| 0; 1; 0 |]|]);;
assert (not (vote [|[| 0; 0; 0; 0; 0 |]; [| 0; 1; 0; 1; 1; 0 |]; [| 0; 0; 0 |]|]));;
assert (not (vote [|[| 0; 0; 1; 1; 0 |]; [| 0; 1; 0; 1; 1; 0 |]; [| 0; 0; 1 |]|]));;
assert (not (vote [|[| 0; 0; 0; 0; 0 |]; [| 0; 1; 0; 1; 1; 1 |]; [| 1; 0; 0 |]|]));;
assert (not (vote [|[| 1; 0; 0; 0; 0 |]; [| 0; 1; 0; 1; 0; 0 |]; [| 0; 1; 1 |]|]));;

(* Tally *)

111
let encrypted_tally = M.fold_ballots (fun b t ->
112 113 114 115 116 117
  M.return (E.combine_ciphertexts (E.extract_ciphertext b) t)
) E.neutral_ciphertext ();;

let factors = Array.map (fun x ->
  E.compute_factor encrypted_tally x ()
) private_keys;;
118
assert (Array.forall2 (E.check_factor encrypted_tally) (Lazy.force P.public_keys) factors);;
119

120
let result = E.combine_factors (M.turnout ()) encrypted_tally factors;;
121 122 123 124
assert (E.check_result result);;

let tally = E.extract_tally result;;
assert (tally = [|[| 1; 0; 1; 0; 0 |]; [|0; 4; 0; 4; 3; 0|]; [| 1; 1; 2 |]|]);;
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147

(* Save to disk *)

let ( / ) = Filename.concat

let save_to filename writer x =
  let oc = open_out filename in
  let ob = Bi_outbuf.create_channel_writer oc in
  writer ob x;
  Bi_outbuf.flush_channel_writer ob;
  close_out oc;;

let list_save_to filename writer xs =
  let oc = open_out filename in
  let ob = Bi_outbuf.create_channel_writer oc in
  Array.iter (fun x ->
    writer ob x;
    Bi_outbuf.add_char ob '\n';
  ) xs;
  Bi_outbuf.flush_channel_writer ob;
  close_out oc;;

let save_to_disk () =
148
  let params = { params with
Stephane Glondu's avatar
Stephane Glondu committed
149
    e_public_key = G.({ g; p; q; y })
150
  } in
151
  let ballots = Array.of_list (M.fold_ballots (fun x xs () -> x::xs) [] ()) in
152
  let dir = Printf.sprintf "demo/data/%s" (Uuidm.to_string params.e_uuid) in
153 154 155
  Unix.mkdir dir 0o755;
  let open Serializable_j in
  let number = Serializable_builtin_j.write_number in
156
  save_to (dir/"election.json") (write_params write_ff_pubkey) params;
157
  save_to (dir/"metadata.json") write_metadata metadata;
158 159 160 161 162
  list_save_to (dir/"private_keys.jsons") number private_keys;
  list_save_to (dir/"public_keys.jsons") (write_trustee_public_key number) public_keys;
  list_save_to (dir/"ballots.jsons") (write_ballot number) ballots;
  save_to (dir/"result.json") (write_result number) result;
  ();;