package threshold.mr04.benchmarking;
import static threshold.mr04.Util.getBytes;
import static threshold.mr04.Util.randomFromZn;
import static threshold.mr04.Util.randomFromZnStar;
import static threshold.mr04.Util.sha256Hash;
import java.io.Serializable;
import java.math.BigInteger;
import java.security.SecureRandom;
import org.bouncycastle.asn1.sec.SECNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.math.ec.ECPoint;
import threshold.mr04.Paillier;
import threshold.mr04.PaillierPublicKey;
import threshold.mr04.SignatureTest;
import threshold.mr04.data.PublicParameters;
public class Proofs implements Serializable {
transient private ECDomainParameters CURVE;
private final BigInteger q;
private final byte[] gRaw;
private final byte[] qRaw;
private final int kPrime;
private BigInteger h1;
private BigInteger h2;
private BigInteger g;
private BigInteger N;
private BigInteger nHat;
private BigInteger Nsquared;
Paillier paillier;
private BigInteger keyShare;
private final SecureRandom rand;
private final PaillierPublicKey alicesPaillierPubKey;
private BigInteger kP1;
private BigInteger ciphertext1;
private BigInteger ciphertext2;
// the random values used for the Paillier ciphertexts
private BigInteger zP1;
private BigInteger r1;
private BigInteger r2;
ECPoint yP1;
private byte[] rRaw;
BigInteger rPrime;
BigInteger mPrime;
ECPoint G;
ECPoint Ri;
ECPoint ROfIPlus1;
BigInteger r5;
BigInteger r6;
BigInteger m1;
BigInteger m2;
BigInteger m3;
BigInteger m4;
BigInteger m5;
BigInteger m6;
public Proofs( byte[] publicKey, SecureRandom rand, PublicParameters params) {
this.rand = rand;
this.q = params.q;
do {
keyShare = new BigInteger(256, rand);
} while (keyShare.compareTo(q) != -1);
X9ECParameters CURVEparams = SECNamedCurves.getByName("secp256k1");
this.CURVE = new ECDomainParameters(CURVEparams.getCurve(), CURVEparams.getG(), CURVEparams.getN(),
CURVEparams.getH());
this.gRaw = params.G(this.CURVE.getCurve()).getEncoded();
this.kPrime = params.kPrime;
this.h1 = params.h1;
this.h2 = params.h2;
g = params.alicesPaillierPubKey.g;
N = params.alicesPaillierPubKey.N;
this.nHat = params.nHat;
Nsquared = N.pow(2);
qRaw = CURVE.getCurve().decodePoint(publicKey).getEncoded();
alicesPaillierPubKey = params.alicesPaillierPubKey;
do {
kP1 = new BigInteger(256, rand);
} while (kP1.compareTo(q) != -1);
zP1 = kP1.modInverse(q);
BigInteger kP1minus1;
do {
kP1minus1 = new BigInteger(256, rand);
} while (kP1minus1.compareTo(q) != -1);
zP1 = zP1.modInverse(q);
G = getG();
yP1 = G.multiply(keyShare);
ROfIPlus1 = G.multiply(kP1minus1);
Ri = ROfIPlus1.multiply(kP1);
r5 = randomFromZnStar(N, rand);
r6 = randomFromZnStar(N, rand);
}
// NOTE NOT ACTUALLY IMPLENTING THE PROOF WITH THE CORRECT VALUES AS THOSE DEPEND ON PREVIOUS PARTS OF THE PROTOCOL
// JUST DOING THE EXPONENTIATION WITH
// THE CORRECT SIZED NUMBERS SO THAT WE CAN BENCHMARK THE PROOF
public void zkpI(int number){
//grows by a factor of q for each proof
BigInteger alphaIminus1 = randomFromZn(q.pow(number), rand);
BigInteger betaIminus1 = randomFromZn(q.pow(number), rand);
BigInteger r1 = randomFromZn(N, rand);
BigInteger r2 = randomFromZn(N, rand);
BigInteger r3 = randomFromZn(N, rand);
BigInteger r4 = randomFromZn(N, rand);
m1 = Paillier.encrypt(zP1.multiply(alphaIminus1), alicesPaillierPubKey,r1);
long startTime = System.nanoTime();
m2 = Paillier.encrypt(zP1.multiply(keyShare).mod(q).multiply(betaIminus1), alicesPaillierPubKey,r2);
System.out.println("Paillier: " + (System.nanoTime() - startTime));
m3 = Paillier.encrypt(alphaIminus1, alicesPaillierPubKey,r3);
m4 = Paillier.encrypt(betaIminus1, alicesPaillierPubKey,r4);
m5 = Paillier.encrypt(zP1, alicesPaillierPubKey, r5);
m6 = Paillier.encrypt(zP1.multiply(keyShare).mod(q), alicesPaillierPubKey, r6);
ECPoint d = G;
BigInteger x1 = zP1;
BigInteger x2 = zP1.multiply(keyShare).mod(q);
ECPoint w1 = ROfIPlus1;
ECPoint w2 = yP1;
ECPoint c = Ri;
//zkpi
BigInteger alpha = randomFromZn(q.pow(3), rand);
BigInteger delta = randomFromZn(q.pow(3), rand);
BigInteger beta1 = randomFromZnStar(N, rand);
BigInteger beta2 = randomFromZnStar(N, rand);
BigInteger rho1 = randomFromZn(q.multiply(nHat), rand);
BigInteger rho2 = randomFromZn(q.multiply(nHat), rand);
BigInteger gamma = randomFromZn(q.multiply(nHat), rand);
BigInteger nu = randomFromZn(q.pow(3).multiply(nHat), rand);
BigInteger rho3 = randomFromZn(q, rand);
BigInteger epsilon = randomFromZn(q, rand);
BigInteger z1 = h1.modPow(x1, nHat).multiply(h2.modPow(rho1, nHat)).mod(nHat);
ECPoint u1 = c.multiply(alpha);
BigInteger u2= g.modPow(alpha, Nsquared).multiply(beta1.modPow(N, Nsquared)).mod(Nsquared);
BigInteger u3 = h1.modPow(alpha, nHat).multiply(h2.modPow(gamma, nHat)).mod(nHat);
BigInteger z2 = h1.modPow(x2, nHat).multiply(h2.modPow(rho2, nHat)).mod(nHat);
ECPoint y = d.multiply(x2.add(rho3));
ECPoint v1 = d.multiply(delta.add(epsilon));
startTime = System.nanoTime();
ECPoint v2 = w2.multiply(alpha).add(d.multiply(epsilon));
System.out.println("ECPoint: " + (System.nanoTime() - startTime));
startTime = System.nanoTime();
BigInteger v3 = m3.modPow(alpha, Nsquared);
System.out.println("modPow: " + (System.nanoTime() - startTime));
BigInteger v4 = m4.modPow(delta, Nsquared);
BigInteger v5 = g.modPow(delta, Nsquared).multiply(beta2.modPow(N, Nsquared)).mod(Nsquared);
BigInteger v6 = h1.modPow(delta, nHat).multiply(h2.modPow(nu, nHat)).mod(nHat);
byte[] eBytes = sha256Hash(getBytes(c),getBytes(d),getBytes(w1),getBytes(w2),getBytes(m1),getBytes(m2),getBytes(m3),getBytes(m4),getBytes(m5),getBytes(m6),getBytes(z1),getBytes(u1),getBytes(u2),getBytes(u3),getBytes(z2),getBytes(y),getBytes(v1),getBytes(v3),getBytes(v4),getBytes(v5),getBytes(v6));
BigInteger e = new BigInteger(1, eBytes);
BigInteger s1 = e.multiply(x1).add(alpha);
BigInteger s2 = r5.modPow(e, N).multiply(beta1).mod(N);
BigInteger s3 = e.multiply(rho1).add(gamma);
BigInteger t1 = e.multiply(x2).add(delta);
BigInteger t2 = e.multiply(rho3).add(epsilon);
BigInteger t3 = r6.modPow(e, N).multiply(beta2).mod(N);
BigInteger t4 = alpha= e.multiply(rho2).add(nu);
//verification--we're not actually doing the proof--just exponentitating to check the time
c.multiply(s1).add(w1.multiply(e.negate()));
startTime = System.nanoTime();
g.modPow(s1, Nsquared).multiply(s2.modPow(N, Nsquared)).multiply(m5.modPow(e.negate(), Nsquared)).mod(Nsquared);
System.out.println("big ugly: " + (System.nanoTime() - startTime));
h1.modPow(s1, nHat).multiply(h2.modPow(s3, nHat)).multiply(z1.modPow(e.negate(), nHat)).mod(nHat);
d.multiply(t1.add(t2)).add(y.multiply(e.negate()));
w2.multiply(s1).add(d.multiply(t2)).add(y.multiply(e.negate()));
m3.modPow(s1, Nsquared).multiply(m1.modPow(e.negate(), Nsquared)).mod(Nsquared);
m4.modPow(t1, Nsquared).multiply(m2.modPow(e.negate(), Nsquared)).mod(Nsquared);
g.modPow(t1, Nsquared).multiply(t3.modPow(N, Nsquared)).multiply(m6.modPow(e.negate(), Nsquared)).mod(Nsquared);
h1.modPow(t1, nHat).multiply(h2.modPow(t4, nHat)).multiply(z2.modPow(e.negate(), nHat)).mod(nHat);
}
private void setR(ECPoint r) {
rRaw = r.getEncoded();
}
private ECPoint getR() {
return CURVE.getCurve().decodePoint(rRaw);
}
private ECPoint getG() {
return CURVE.getCurve().decodePoint(gRaw);
}
public ECPoint getQ() {
return CURVE.getCurve().decodePoint(qRaw);
}
}