Skip to content

Instantly share code, notes, and snippets.

@ruescasd
Created October 5, 2013 15:38
Show Gist options
  • Save ruescasd/6842394 to your computer and use it in GitHub Desktop.
Save ruescasd/6842394 to your computer and use it in GitHub Desktop.
import verificatum.eio.ByteTree;
import verificatum.eio.ByteTreeBasic;
import verificatum.eio.ByteTreeReader;
import verificatum.arithm.ModPGroup;
import verificatum.arithm.PGroup;
import verificatum.arithm.PGroupElement;
import verificatum.arithm.PGroupElementArray;
import verificatum.arithm.PPGroup;
import verificatum.arithm.PPGroupElement;
import verificatum.arithm.PRing;
import verificatum.arithm.PFieldElement;
import verificatum.arithm.PRingElement;
import verificatum.arithm.PRingElementArray;
import verificatum.crypto.RandomOracle;
import verificatum.crypto.CryptoKeyGen;
import verificatum.crypto.CryptoKeyGenCramerShoup;
import verificatum.crypto.CryptoKeyPair;
import verificatum.crypto.Hashfunction;
import verificatum.crypto.HashfunctionHeuristic;
import verificatum.crypto.PRG;
import verificatum.crypto.PRGHeuristic;
import verificatum.crypto.RandomSource;
import verificatum.protocol.mixnet.MixNetElGamalInterface;
import verificatum.protocol.mixnet.MixNetElGamalInterfaceNative;
import verificatum.eio.Marshalizer;
import verificatum.eio.Hex;
import org.apache.commons.codec.binary.Base64;
// https://github.com/benadida/js-voting-crypto/blob/master/lib/elgamal.js
// https://github.com/agoraciudadana/applet-verificatum/blob/master/src/org/agora/VotingApplet.java
public class Vote {
protected static final String interfaceName = "native";
protected static final int certainty = 100;
protected RandomSource mRandomSource = null;
protected int mVote = -1;
protected int mProposal = -1;
protected PGroupElement mFullPublicKey = null;
protected String mFullPublicKeyString = null;
protected String mEncryptedVote = null;
protected String mHash = null;
protected String mAFactor = null;
protected String mDFactor = null;
protected String mUFactor = null;
public Vote(int vote, int proposal, String publicKeyString) throws Exception {
mVote = vote;
mProposal = proposal;
mFullPublicKeyString = publicKeyString;
obtainPublicKey();
encrypt();
}
// Obtain the public key for this proposal/voting
protected void obtainPublicKey() throws Exception {
// mFullPublicKey = MixNetElGamalInterface.stringToPublicKey(interfaceName, mFullPublicKeyString, mRandomSource, certainty);
this.readPublicKey(mFullPublicKeyString, mRandomSource, certainty);
}
protected void encrypt() throws Exception {
String plaintext = Integer.toString(mVote);
// Recover key from input
PGroupElement basicPublicKey =
((PPGroupElement)mFullPublicKey).project(0);
PGroupElement publicKey =
((PPGroupElement)mFullPublicKey).project(1);
PGroup basicPublicKeyPGroup = basicPublicKey.getPGroup();
PGroup publicKeyPGroup = publicKey.getPGroup();
// Get interface (added cast)
MixNetElGamalInterfaceNative mixnetInterface =
(MixNetElGamalInterfaceNative) MixNetElGamalInterface.getInterface(interfaceName);
// Generate plaintext
byte[] iBytes = plaintext.getBytes();
PGroupElement a_plaintext = publicKeyPGroup.encode(iBytes, 0, iBytes.length);
// Encrypt the result.
PRG prg = new PRGHeuristic(); // this uses SecureRandom internally
PRing randomizerPRing = basicPublicKeyPGroup.getPRing();
PRingElement r = randomizerPRing.randomElement(prg, 20);
PGroupElement u = basicPublicKey.exp(r);
PGroupElement v = publicKey.exp(r).mul(a_plaintext);
PGroupElement ciph =
((PPGroup)mFullPublicKey.getPGroup()).product(u, v);
// set ciphertext using the format of the interface.
mEncryptedVote = mixnetInterface.ciphertextToString(ciph);
// Calculate hash and convert it to readable hex String
RandomOracle ro = new RandomOracle(new HashfunctionHeuristic("SHA-256"), 2048);
String HEXES = "0123456789abcdef";
byte[] raw = ro.hash(mEncryptedVote.getBytes());
StringBuilder hex = new StringBuilder(2 * raw.length);
for (byte b : raw) {
hex.append(HEXES.charAt((b & 0xF0) >> 4))
.append(HEXES.charAt((b & 0x0F)));
}
mHash = hex.toString();
// Create a verifiable proof of knowledge of the cleartext
PRingElement s = randomizerPRing.randomElement(prg, 20);
PGroupElement a = basicPublicKey.exp(s);
// c = hash(prefix, g, u*v, a)
ByteTree cTree = new ByteTree(
new ByteTree(basicPublicKeyPGroup.toByteTree().toByteArray()),
new ByteTree(ciph.toByteTree().toByteArray()),
new ByteTree(a.toByteTree().toByteArray())
);
// ro = new RandomOracle(new HashfunctionHeuristic("SHA-256"), 2048, ByteTree.intToByteTree(mProposal));
Hashfunction roHashfunction = Marshalizer.unmarshalAux_Hashfunction(ByteTree.intToByteTree(mProposal).getByteTreeReader(), mRandomSource, certainty);
byte[] cHash = ro.hash(cTree.toByteArray());
// d = cr+s
prg.setSeed(cHash);
PRingElement c = randomizerPRing.randomElement(prg, 20);
PRingElement d = c.mul(r).add(s);
mAFactor = encode(a.toByteTree().toByteArray());
mDFactor = encode(d.toByteTree().toByteArray());
mUFactor = encode(u.toByteTree().toByteArray());
}
public String getAFactor() {
return mAFactor;
}
public String getDFactor() {
return mDFactor;
}
public String getUFactor() {
return mUFactor;
}
public int getVote() {
return mVote;
}
public int getProposal() {
return mProposal;
}
public String getEncryptedVote() {
return mEncryptedVote;
}
public String getHash() {
return mHash;
}
public String toString() {
return "vote id = " + mVote + ", proposal id = " + mProposal;
}
// from mixnetinterfacenative
private PGroupElement readPublicKey(String publicKeyString, RandomSource randomSource, int certainty) throws Exception {
byte[] keyBytes = Hex.toByteArray(publicKeyString);
ByteTreeReader btr =
(new ByteTree(keyBytes, null)).getByteTreeReader();
PGroup pGroup = Marshalizer.unmarshalAux_PGroup(btr.getNextChild(),
randomSource,
certainty);
return (new PPGroup(pGroup, 2)).toElement(btr.getNextChild());
}
public static String encode(byte[] bytes) throws Exception {
byte[] encoded = Base64.encodeBase64(bytes);
return new String(encoded, "ASCII");
}
public static void main(String[] args) throws Exception {
String publicKeyString = "00000000020000000002010000001a766572696669636174756d2e61726974686d2e505047726f7570000000000200000000010000000002010000001c766572696669636174756d2e61726974686d2e4d6f645047726f7570000000000401000001010188cb0fcd7f00ffd629ee7c0426036c09cd1ae4576e3cde79680733bd13b0b1ef6ace0082d1cc0839d8d8f89d302570dcd4b7178fd8edfd54166d891b5f5b435c0cba214c471dda545897a12a9b53956fb76a6d647295011bec650e0609b50f97ffa16201ffd5b6368083965abf0a2f73ae0c2a9dc315ca63253df511176551961440aebbee1495c5bf318b9228c77938c4508063048161e9e4d83cbec3a3c16d856d1cf4d5f5c10d979476b39cd3541786fbc22d12326d8c66119a847c360e36294d4e1d14b1f80757f9fbfec49146e86b60130ecda55ac889aa733198a849946656c37cb5cbe3fd60d92900476ee6a9dac4825d89296fb5601a357de2121537010000010100c46587e6bf807feb14f73e021301b604e68d722bb71e6f3cb40399de89d858f7b567004168e6041cec6c7c4e9812b86e6a5b8bc7ec76feaa0b36c48dafada1ae065d10a6238eed2a2c4bd0954da9cab7dbb536b2394a808df632870304da87cbffd0b100ffeadb1b4041cb2d5f8517b9d706154ee18ae531929efa888bb2a8cb0a20575df70a4ae2df98c5c91463bc9c622840318240b0f4f26c1e5f61d1e0b6c2b68e7a6afae086cbca3b59ce69aa0bc37de116891936c63308cd423e1b071b14a6a70e8a58fc03abfcfdff6248a37435b0098766d2ad6444d53998cc5424ca332b61be5ae5f1feb06c948023b77354ed62412ec494b7dab00d1abef1090a9b010000010100e25212162cb0c7247fe38c94ee63c2f28af46f64aee6b967e6f77d3bee673db34346132755152d283644b7c9a7a97764862fa53466d1da6b24ccc105240829c8dfbf923e34bc01e49c1642cea67c183e13fccbe213eb2668cca873a44f2b43a76708b158ab785400750a132a754bf50eb290b84118b895837d1016e6bf957287cdb5bfbb360d2a9e4235be011f116be0bdd40423f60e22a65f3e323f5bb0eebc9e6f30fd3883ea9e9e8f7709df6aa6ad1cc3a834438e835c3f348c6a9f2b4c92dfc058f3bf375ec9bc5d9a4cf447f5a15e44632284d44b74901001e6b9fc30ea5e49ee15ac823205318a5af618d471fc7c8918d061043b58d2513bd3f13038be01000000040000000100000000020100000004000000000100000004000000000000000002010000010100e25212162cb0c7247fe38c94ee63c2f28af46f64aee6b967e6f77d3bee673db34346132755152d283644b7c9a7a97764862fa53466d1da6b24ccc105240829c8dfbf923e34bc01e49c1642cea67c183e13fccbe213eb2668cca873a44f2b43a76708b158ab785400750a132a754bf50eb290b84118b895837d1016e6bf957287cdb5bfbb360d2a9e4235be011f116be0bdd40423f60e22a65f3e323f5bb0eebc9e6f30fd3883ea9e9e8f7709df6aa6ad1cc3a834438e835c3f348c6a9f2b4c92dfc058f3bf375ec9bc5d9a4cf447f5a15e44632284d44b74901001e6b9fc30ea5e49ee15ac823205318a5af618d471fc7c8918d061043b58d2513bd3f13038be010000010100a5fa8159068f2fcba2b6e773091ed4c255b5510a217211905356ff96f3404279c4bd2dcdf5ccc0edf3ba6e32277d2807876d6118d49685d97e6fd535550919157146322e6d79cfa5df6800fe80cccf91d18ff336adbf41593cedc8eb3ae55f89b150433bfacc475e42fe2bd547c5fb1350304153ebea56d947afb81899a9ee78ab57602eb22f1391f5714f4f1d134056e9b0f6963c14f93bfc76523cf4021637ec423af2e6c8370533acf2cbafc31c00c71b1fe66ed5b8d623983b0ab49ac8193d9a4d59dda9438bca339a8245a9e12fd5ce669aa1494c2755efffb3a319a97fa0deb2ae35e2643e663843725ec0885e1783a8dfc5a2a3497e6cdf1cc538f638";
Vote vote = new Vote(-1, 23, publicKeyString);
// String ballotStr = "0,1," + publicKeyString;
// applet.vote(ballotStr, args[0]);
return;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment