crypto_vote/identity.rs
1//! Operation A — generation of a cryptographic identity.
2//!
3//! A voter's identity is a single [`Scalar`] sampled uniformly at
4//! random, plus its derived Ristretto point. The scalar is the secret
5//! key, the point is the public key.
6//!
7//! Randomness comes from [`SysRng`], i.e. the operating-system CSPRNG:
8//!
9//! - on Linux / macOS / Windows that's `getrandom(2)` /
10//! `getentropy(2)` / `BCryptGenRandom`;
11//! - in a browser, with the `wasm` feature on, `getrandom` is
12//! configured (in `Cargo.toml`) to use `Crypto.getRandomValues` via
13//! its `wasm_js` feature.
14//!
15//! In every case the application code is the same — that is the whole
16//! point of routing through `SysRng`.
17
18use crate::types::{PublicKey, SecretKey};
19use curve25519_dalek::scalar::Scalar;
20use rand::rngs::SysRng;
21use rand_core::UnwrapErr;
22
23/// A freshly generated voter identity.
24pub struct Identity {
25 /// Public part — publish this so the registrar can add it to the
26 /// authorised list.
27 pub public_key: PublicKey,
28 /// Secret part — must stay on the voter's device.
29 pub secret_key: SecretKey,
30}
31
32/// Generate a new [`Identity`] from the platform CSPRNG.
33///
34/// This is Operation A from the requirements spec: no inputs, two
35/// outputs. There is nothing else to it — every voter holds exactly one
36/// independently sampled identity.
37pub fn generate_identity() -> Identity {
38 let mut rng = UnwrapErr(SysRng);
39 let scalar = Scalar::random(&mut rng);
40 let secret_key = SecretKey { scalar };
41 let public_key = secret_key.public_key();
42 Identity {
43 public_key,
44 secret_key,
45 }
46}
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51
52 #[test]
53 fn two_identities_are_different() {
54 // SysRng is supposed to be uniform; getting the same key twice
55 // would mean either a catastrophic bug or the heat-death of the
56 // universe.
57 let a = generate_identity();
58 let b = generate_identity();
59 assert_ne!(a.public_key, b.public_key);
60 assert_ne!(a.secret_key.to_bytes(), b.secret_key.to_bytes());
61 }
62
63 #[test]
64 fn public_key_is_derived_from_secret_key() {
65 let id = generate_identity();
66 // Re-deriving from the encoded secret key should give the same
67 // public key — that's the "secret key uniquely determines the
68 // public key" property the protocol relies on.
69 let restored = SecretKey::from_bytes(&id.secret_key.to_bytes()).unwrap();
70 assert_eq!(restored.public_key(), id.public_key);
71 }
72}