Created
October 29, 2025 11:24
-
-
Save ruescasd/4996a7de9e624c855740e400fc4b642d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| use crypto::context::Context; | |
| use crypto::context::RistrettoCtx as RCtx; | |
| use crypto::cryptosystem::elgamal::{Ciphertext, KeyPair}; | |
| use crypto::traits::groups::GroupElement; | |
| fn main() { | |
| let keypair: KeyPair<RCtx> = KeyPair::generate(); | |
| // voter submission | |
| // encrypt vote | |
| let message = [RCtx::random_element(); 1]; | |
| let r = [RCtx::random_scalar(); 1]; | |
| let ciphertext = keypair.encrypt_with_r(&message, &r); | |
| // compute cv1 | |
| let cv1 = [RCtx::random_element(); 1]; | |
| // note that we are encrypting cv1 with the same randomness r as the vote, which means | |
| // their first values must be equal | |
| let ecv1 = keypair.encrypt_with_r(&cv1, &r); | |
| // check that the first element of the original ciphertext matches the first element of ecv1 | |
| assert_eq!(ciphertext.u()[0], ecv1.u()[0]); | |
| // ea tagging | |
| // computes cv2 | |
| let cv2 = [RCtx::random_element(); 1]; | |
| let ecv2 = keypair.encrypt_with_r(&cv2, &r); | |
| // election ends, tally filtering | |
| // ea multiplies ecv1 and ecv2: | |
| // e(cv) = e(cv1) * e(cv2) = e(cv1 * cv2) | |
| let ecv = ecv1.0.mul(&ecv2.0); | |
| // ea combines ciphertext and cv | |
| let combined_u = [ciphertext.u()[0], ecv[0][0]]; | |
| let combined_v = [ciphertext.v()[0], ecv[1][0]]; | |
| // resulting in a single ciphertext | |
| // (e(message), e(cv1 * cv2)) | |
| // ==> | |
| // // e(message, cv1 * cv2) | |
| let combined: Ciphertext<RCtx, 2> = Ciphertext::new(combined_u, combined_v); | |
| // shuffle | |
| // (ballot, cv) pairs are shuffled as a single ciphertext | |
| let r_n = [RCtx::random_scalar(); 2]; | |
| let shuffled = combined.re_encrypt(&r_n, &keypair.pkey.y); | |
| // in a real election _only the cv values are decrypted_ at the filtering stage, | |
| // by splitting the shuffled outputs | |
| // e(message, cv1 * cv2) | |
| // into | |
| // (e(message), e(cv1 * cv2)) | |
| // and decrypting only the second element of each pair | |
| let decrypted = keypair.decrypt(&shuffled); | |
| // to deniably cancel | |
| // * voter reveals cv1 (this can be checked with randomness used to encrypt cv1, showing the ea that | |
| // it is attached to _a_ ballot) | |
| // * ea reveals cv2 (this can be checked with randomness used to encrypt cv2, showing the voter that it is | |
| // attached to _their_ ballot) | |
| // then, voter submits cv = cv1 * cv2, eg in a box | |
| let cv = cv1[0].mul(&cv2[0]); | |
| // the cv = cv1 * cv2 values extracted from the box are used to | |
| // select ballots for cancelling | |
| // ballots with attached cancel value = cv1 * cv2 are filtered out, by matching with the decrypted | |
| // second element of a (enc(ballot), enc(cv)) pair, since | |
| // cv1 * cv2 = dec(enc(cv1 * cv2)) = dec(e(cv1) * e(cv2)) = dec(enc(cv)) | |
| // note that | |
| // * the ea cannot cancel a ballot without the voter's value cv1 | |
| // * the voter can verify that cv1 * cv2 is used to cancel a ballot, and | |
| // the ea cannot silently refuse to cancel a ballot, as they must publish cv1 * cv2. | |
| // * the coercer cannot detect whether the voter's ballot was cancelled, even if they know cv1, since they do not know cv2, | |
| // moreover, if the coercer demands the value cv2 from the voter, they cannot distinguish a voter that did | |
| // not cancel, from one that did and lied | |
| assert_eq!(decrypted[1], cv); | |
| // first element must match original message | |
| assert_eq!(decrypted[0], message[0]); | |
| /* | |
| Note regarding a denied cancel value attack | |
| * If your coercer denies your cancel value from you, | |
| it is still possible for the trustees to decrypt your | |
| cancel value, and follow the normal deniable cancelling procedure. | |
| This trades a small amount of correctness, as in theory, | |
| the trustees could collude to cancel votes without the | |
| voter's consent. | |
| * The most frequent coercer scenarios occurs | |
| with a spouse or some other close relation, who will usually | |
| not be qualified to set up a voting system that denies the cancel | |
| value from the target. | |
| */ | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment