1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
//!
//! Community Tally Verification Tool
//!

use chain_vote::tally::batch_decrypt;
use lib::tally::{
    decrypt_tally_with_secret_keys, encode_decrypt_shares, encode_public_keys,
    extract_decrypt_shares, load_decrypt_shares, load_encrypted_tally,
    parse_private_committee_keys, parse_public_committee_keys,
};

use clap::Parser;

use color_eyre::Result;
use tracing::{info, Level};

use std::error::Error;

///
/// Args defines and declares CLI behaviour within the context of clap
///
#[derive(Parser, Debug, Clone)]
#[clap(about, version, author)]
pub struct Args {
    /// Encrypted tally
    #[clap(short, long)]
    pub encrypted_tally: Option<String>,
    /// Produce decrypt shares: not for public use
    #[clap(
        short,
        long,
        requires = "encrypted_tally",
        value_delimiter = ' ',
        num_args = 1..
    )]
    pub produce_decrypt_shares: Option<Vec<String>>,
    /// Decrypt Tally from shares: public use
    #[clap(
        short,
        long,
        requires = "encrypted_tally",
        requires = "public_keys",
        value_delimiter = ' ',
        num_args = 1..
    )]
    pub decrypt_tally_from_shares: Option<Vec<String>>,
    /// Decrypt Tally from secret keys: internal use
    #[clap(short, long, requires = "encrypted_tally", value_delimiter = ' ', num_args = 1..)]
    pub decrypt_tally_from_keys: Option<Vec<String>>,
    /// List of whitespace seperated Secret keys
    #[clap(short, long, value_delimiter = ' ', num_args = 1..)]
    pub private_keys: Option<Vec<String>>,
    /// List of whitespace seperated Public keys
    #[clap(short, long, value_delimiter = ' ', num_args = 1..)]
    pub public_keys: Option<Vec<String>>,
    /// Show Public keys
    #[clap(short, long, value_delimiter = ' ', num_args = 1..)]
    pub show_public_keys: Option<Vec<String>>,
}

fn main() -> Result<(), Box<dyn Error>> {
    color_eyre::install()?;

    let args = Args::parse();

    // Configure a custom event formatter
    let format = tracing_subscriber::fmt::format()
        .with_level(true) // don't include levels in formatted output
        .with_target(true) // don't include targets
        .with_thread_ids(true) // include the thread ID of the current thread
        .with_thread_names(true) // include the name of the current thread
        .compact(); // use the `Compact` formatting style.

    // Create a `fmt` subscriber that uses our custom event format, and set it
    // as the default.
    tracing_subscriber::fmt()
        .event_format(format)
        .with_max_level(Level::INFO /*DEBUG*/)
        .init();

    info!("Audit Tool.");
    info!("Tally Verification Tool.");

    //
    // Load decrypt shares for cross referencing Tally result
    // Intended for public use
    //
    if let Some(shares) = args.decrypt_tally_from_shares {
        let shares = load_decrypt_shares(shares)?;
        let pub_keys = args.public_keys.clone().ok_or("handled by clap")?;

        let encrypted_tally =
            load_encrypted_tally(args.encrypted_tally.clone().ok_or("handled by clap")?)?;

        let pks = parse_public_committee_keys(pub_keys)?;

        let validated_tally = encrypted_tally.validate_partial_decryptions(&pks, &shares)?;

        println!(
            "Decryption results {:?}",
            &batch_decrypt([validated_tally])?
        );
    }

    //
    // Produce decrypt shares for publication
    // Internal use only
    //
    if let Some(committee_private_keys) = args.produce_decrypt_shares {
        let (_pub_keys, priv_keys) = parse_private_committee_keys(committee_private_keys)?;

        let encrypted_tally =
            load_encrypted_tally(args.encrypted_tally.clone().ok_or("handled by clap")?)?;

        let shares = extract_decrypt_shares(encrypted_tally, priv_keys);

        println!("Decryption shares: {:?}", encode_decrypt_shares(shares));
    }

    //
    // Decrypt tally from secret keys
    // Intended for internal use
    //
    if let Some(committee_private_keys) = args.decrypt_tally_from_keys {
        let (_pub_keys, priv_keys) = parse_private_committee_keys(committee_private_keys)?;

        let encrypted_tally =
            load_encrypted_tally(args.encrypted_tally.clone().ok_or("handled by clap")?)?;

        println!(
            "tally decryption {:?}",
            decrypt_tally_with_secret_keys(encrypted_tally, priv_keys)
        );
    }

    //
    // Show public keys of private keys
    //
    if let Some(committee_private_keys) = args.show_public_keys {
        let (pub_keys, _priv_keys) = parse_private_committee_keys(committee_private_keys.clone())?;

        let encoded = encode_public_keys(pub_keys)?;
        let it = encoded.iter().zip(committee_private_keys.iter());

        for (i, (x, y)) in it.enumerate() {
            println!("{}: ({}, {})", i, x, y);
        }
    }

    Ok(())
}