Created
October 5, 2013 15:38
-
-
Save ruescasd/6842394 to your computer and use it in GitHub Desktop.
This file contains 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
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