meerkat-java/mixer/src/main/java/prover/Prover.java

216 lines
10 KiB
Java
Raw Normal View History

2015-12-11 07:41:26 -05:00
package prover;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import meerkat.crypto.concrete.ECElGamalEncryption;
2015-12-11 07:41:26 -05:00
import meerkat.crypto.mixnet.Mix2ZeroKnowledgeProver;
import meerkat.protobuf.Crypto;
import meerkat.protobuf.Mixing;
import org.bouncycastle.math.ec.ECPoint;
2016-04-05 04:49:34 -04:00
import org.factcenter.qilin.primitives.RandomOracle;
import org.factcenter.qilin.primitives.concrete.ECGroup;
2015-12-14 10:54:44 -05:00
import java.math.BigInteger;
2015-12-11 07:41:26 -05:00
import java.util.Random;
2016-01-25 09:48:36 -05:00
/**
* implements of Mix2ZeroKnowledgeProver interface
* this implantation assumes that each RerandomizableEncryptedMessage is ElGamalCiphertext
*/
public class Prover implements Mix2ZeroKnowledgeProver {
2016-01-25 09:48:36 -05:00
private final ECGroup group;
private final RandomOracle randomOracle;
private final Random rand;
private final ECElGamalEncryption encryptor;
private final ECPoint g,h;
private final BigInteger groupOrderUpperBound;
private final ElGamalProofOrganizer organizer;
/**
* @param rand
* @param encryptor
* @param randomOracle - use for FiatShamir heuristic
*/
public Prover(Random rand,ECElGamalEncryption encryptor,RandomOracle randomOracle) {
2015-12-11 07:41:26 -05:00
this.rand = rand;
2016-01-25 09:48:36 -05:00
this.encryptor = encryptor;
this.randomOracle = randomOracle;
2016-01-25 09:48:36 -05:00
this.group = this.encryptor.getGroup();
this.g = group.getGenerator();
2016-01-25 09:48:36 -05:00
this.h = this.encryptor.getElGamalPK().getPK();
2016-01-20 05:14:15 -05:00
this.organizer = new ElGamalProofOrganizer(group,g,h);
2016-01-25 09:48:36 -05:00
this.groupOrderUpperBound = group.orderUpperBound();
}
2016-01-25 09:48:36 -05:00
/**
* @param in1
* @param in2
* @param out1 - if sw then out1 = rerandomize(in2,r2) else out1 = rerandomize(in1,r1)
* @param out2 - if sw then out2 = rerandomize(in1,r1) else out1 = rerandomize(in2,r2)
* @param sw - flag
* @param i - column of in1 and out1 in encryption table
* @param j - column of in2 and out2 in encryption table
* @param layer - row of in1,in2 in encryption table
* @param r1
* @param r2
* @return - a valid ZKP that indeed out1,out2 calculated as required
* @throws InvalidProtocolBufferException
*/
2015-12-11 07:41:26 -05:00
public Mixing.ZeroKnowledgeProof prove(Crypto.RerandomizableEncryptedMessage in1,
Crypto.RerandomizableEncryptedMessage in2,
Crypto.RerandomizableEncryptedMessage out1,
Crypto.RerandomizableEncryptedMessage out2,
2015-12-17 12:15:48 -05:00
boolean sw,int i,int j, int layer,
2015-12-11 07:41:26 -05:00
Crypto.EncryptionRandomness r1,
Crypto.EncryptionRandomness r2) throws InvalidProtocolBufferException {
2015-12-11 07:41:26 -05:00
Mixing.ZeroKnowledgeProof.OrProof first,second,third,fourth;
2016-01-20 05:14:15 -05:00
ElGamalProofOrganizer.ElGamalProofInput input = organizer.createProofInput(in1,in2,out1,out2,r1,r2,sw);
first = createOrProofElGamal(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.first));
second = createOrProofElGamal(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.second));
third = createOrProofElGamal(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.third));
fourth = createOrProofElGamal(input.getOrProofInput(ElGamalProofOrganizer.OrProofOrder.fourth));
2015-12-17 12:15:48 -05:00
Mixing.ZeroKnowledgeProof.Location location = Mixing.ZeroKnowledgeProof.Location.newBuilder()
.setI(i)
.setJ(j)
.setLayer(layer)
.build();
Mixing.ZeroKnowledgeProof result = Mixing.ZeroKnowledgeProof.newBuilder()
2015-12-11 07:41:26 -05:00
.setFirst(first)
.setSecond(second)
.setThird(third)
.setFourth(fourth)
2015-12-17 12:15:48 -05:00
.setLocation(location)
2015-12-11 07:41:26 -05:00
.build();
return result;
2015-12-11 07:41:26 -05:00
}
2016-01-25 09:48:36 -05:00
/**
* FiatShamir heuristic
* @param input - protobuf contains all parameters from the first step of the current prove
* @return randomOracle.hash(input)
*/
private BigInteger hash(Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle input) {
byte[] arr = input.toByteArray();
2016-03-20 13:18:23 -04:00
return new BigInteger(1,this.randomOracle.hash(arr,arr.length));
}
2016-01-25 09:48:36 -05:00
/**
* @param orProofInput
* @return ZKP OrProof: there exists x s.t (g1 ^ x == h1 and g2 ^ x == h2) or (g1' ^ x == h1 and g2' ^ x == h2)
* assuming DLog is hard in this.group then that proves x is known for the prover
*/
2016-01-20 05:14:15 -05:00
private Mixing.ZeroKnowledgeProof.OrProof createOrProofElGamal(ElGamalProofOrganizer.OrProofInput orProofInput) {
2015-12-11 07:41:26 -05:00
2016-01-20 05:14:15 -05:00
ECPoint g1 = orProofInput.g1;
ECPoint h1 = orProofInput.h1;
ECPoint g2 = orProofInput.g2;
ECPoint h2 = orProofInput.h2;
2016-01-20 05:14:15 -05:00
ECPoint g1Tag = orProofInput.g1Tag;
ECPoint h1Tag = orProofInput.h1Tag;
ECPoint g2Tag = orProofInput.g2Tag;
ECPoint h2Tag = orProofInput.h2Tag;
2015-12-11 07:41:26 -05:00
2016-03-20 13:18:23 -04:00
BigInteger r = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound);
2015-12-14 10:54:44 -05:00
BigInteger c1,c2,z,zTag;
ECPoint u,v,uTag,vTag;
Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle forRandomOracle;
2016-01-20 05:14:15 -05:00
switch (orProofInput.flag) {
case left:
2016-03-20 13:18:23 -04:00
c2 = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound);
zTag = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound);
//step 1
u = group.multiply(g1, r);
v = group.multiply(g2, r);
uTag = group.add(group.multiply(g1Tag, zTag), group.negate(group.multiply(h1Tag, c2)));
vTag = group.add(group.multiply(g2Tag, zTag), group.negate(group.multiply(h2Tag, c2)));
//step 2
// c1 = (hash(input + step1) + group size - c2)% group size
forRandomOracle =
Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle.newBuilder()
2016-01-20 05:14:15 -05:00
.setG1(ByteString.copyFrom(orProofInput.g1Encoded))
.setH1(ByteString.copyFrom(orProofInput.h1Encoded))
.setG2(ByteString.copyFrom(orProofInput.g2Encoded))
.setH2(ByteString.copyFrom(orProofInput.h2Encoded))
.setG1Tag(ByteString.copyFrom(orProofInput.g1TagEncoded))
2016-01-25 09:48:36 -05:00
.setH1Tag(ByteString.copyFrom(orProofInput.h1TagEncoded))
.setG2Tag(ByteString.copyFrom(orProofInput.g2TagEncoded))
.setH2Tag(ByteString.copyFrom(orProofInput.h2TagEncoded))
.setU(ByteString.copyFrom(group.encode(u)))
.setV(ByteString.copyFrom(group.encode(v)))
.setUTag(ByteString.copyFrom(group.encode(uTag)))
.setVTag(ByteString.copyFrom(group.encode(vTag)))
.build();
2016-01-25 09:48:36 -05:00
c1 = hash(forRandomOracle).add(group.orderUpperBound().subtract(c2)).mod(groupOrderUpperBound);
//step 3
//z = (r + c1 * x) % group size;
2016-03-20 13:18:23 -04:00
z = r.add(c1.multiply(encryptor.extractRandomness(orProofInput.x))).mod(groupOrderUpperBound);
break;
case right:
2016-03-20 13:18:23 -04:00
c1 = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound);
z = encryptor.extractRandomness(encryptor.generateRandomness(rand)).mod(groupOrderUpperBound);
//step 1
uTag = group.multiply(g1Tag, r);
vTag = group.multiply(g2Tag, r);
u = group.add(group.multiply(g1, z), group.negate(group.multiply(h1, c1)));
v = group.add(group.multiply(g2, z), group.negate(group.multiply(h2, c1)));
//step 2
// c1 = (hash(input + step1) + group size - c1)% group size
forRandomOracle =
Mixing.ZeroKnowledgeProof.OrProof.ForRandomOracle.newBuilder()
2016-01-20 05:14:15 -05:00
.setG1(ByteString.copyFrom(orProofInput.g1Encoded))
.setH1(ByteString.copyFrom(orProofInput.h1Encoded))
.setG2(ByteString.copyFrom(orProofInput.g2Encoded))
.setH2(ByteString.copyFrom(orProofInput.h2Encoded))
.setG1Tag(ByteString.copyFrom(orProofInput.g1TagEncoded))
2016-01-25 09:48:36 -05:00
.setH1Tag(ByteString.copyFrom(orProofInput.h1TagEncoded))
.setG2Tag(ByteString.copyFrom(orProofInput.g2TagEncoded))
.setH2Tag(ByteString.copyFrom(orProofInput.h2TagEncoded))
.setU(ByteString.copyFrom(group.encode(u)))
.setV(ByteString.copyFrom(group.encode(v)))
.setUTag(ByteString.copyFrom(group.encode(uTag)))
.setVTag(ByteString.copyFrom(group.encode(vTag)))
.build();
2016-01-25 09:48:36 -05:00
c2 = hash(forRandomOracle).add(group.orderUpperBound().subtract(c1)).mod(groupOrderUpperBound);
//step 3
//zTag = (r + c2 * x) % group size;
2016-03-20 13:18:23 -04:00
zTag = r.add(c2.multiply(encryptor.extractRandomness(orProofInput.x))).mod(groupOrderUpperBound);
break;
default:
return null;
2015-12-11 07:41:26 -05:00
}
2015-12-11 07:41:26 -05:00
return Mixing.ZeroKnowledgeProof.OrProof.newBuilder()
2016-01-20 05:14:15 -05:00
.setG1(forRandomOracle.getG1())
.setH1(forRandomOracle.getH1())
.setG2(forRandomOracle.getG2())
.setH2(forRandomOracle.getH2())
.setG1Tag(forRandomOracle.getG1())
.setH1Tag(forRandomOracle.getH1Tag())
.setG2Tag(forRandomOracle.getG2Tag())
.setH2Tag(forRandomOracle.getH2Tag())
.setU(forRandomOracle.getU())
.setV(forRandomOracle.getV())
.setUTag(forRandomOracle.getUTag())
.setVTag(forRandomOracle.getVTag())
2015-12-14 10:54:44 -05:00
.setC1(ByteString.copyFrom(c1.toByteArray()))
.setC2(ByteString.copyFrom(c2.toByteArray()))
.setZ(ByteString.copyFrom(z.toByteArray()))
.setZTag(ByteString.copyFrom(zTag.toByteArray()))
2015-12-11 07:41:26 -05:00
.build();
}
}