diff --git a/source/crypto/crypto-adv/pom.xml b/source/crypto/crypto-adv/pom.xml
index ac72b043..bf759175 100644
--- a/source/crypto/crypto-adv/pom.xml
+++ b/source/crypto/crypto-adv/pom.xml
@@ -45,11 +45,5 @@
compile
-
- com.n1analytics
- javallier_2.10
- 0.6.0
-
-
\ No newline at end of file
diff --git a/source/crypto/crypto-adv/src/main/java/com/jd/blockchain/crypto/mpc/MultiSum.java b/source/crypto/crypto-adv/src/main/java/com/jd/blockchain/crypto/mpc/MultiSum.java
index 7fe64ef9..45392f29 100644
--- a/source/crypto/crypto-adv/src/main/java/com/jd/blockchain/crypto/mpc/MultiSum.java
+++ b/source/crypto/crypto-adv/src/main/java/com/jd/blockchain/crypto/mpc/MultiSum.java
@@ -2,17 +2,15 @@ package com.jd.blockchain.crypto.mpc;
import java.math.BigInteger;
-import com.n1analytics.paillier.PaillierPrivateKey;
-import com.n1analytics.paillier.PaillierPublicKey;
+import com.jd.blockchain.crypto.paillier.PaillierPublicKeyParameters;
+import com.jd.blockchain.crypto.paillier.PaillierUtils;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
-import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.agreement.ECDHBasicAgreement;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;
-import org.bouncycastle.util.encoders.Hex;
import com.jd.blockchain.crypto.utils.sm.SM2Utils;
import com.jd.blockchain.crypto.utils.sm.SM3Utils;
@@ -20,68 +18,73 @@ import com.jd.blockchain.utils.io.BytesUtils;
public class MultiSum {
- private ECPrivateKeyParameters ePrivKey;
- private ECPublicKeyParameters ePubKey;
- private ECCurve curve;
- private ECDomainParameters domainParams;
+ private static byte[] ePrivKey;
+ private static byte[] ePubKey;
+ private static ECCurve curve;
+ private static ECDomainParameters domainParams;
- public void generateEphemeralKeyPair(){
+ public static void generateEphemeralKeyPair(){
AsymmetricCipherKeyPair eKeyPair = SM2Utils.generateKeyPair();
- this.ePrivKey = (ECPrivateKeyParameters) eKeyPair.getPrivate();
- this.ePubKey = (ECPublicKeyParameters) eKeyPair.getPublic();
- this.curve = SM2Utils.getCurve();
- this.domainParams = SM2Utils.getDomainParams();
+ ECPrivateKeyParameters ecPrivKey = (ECPrivateKeyParameters) eKeyPair.getPrivate();
+ ECPublicKeyParameters ecPubKey= (ECPublicKeyParameters) eKeyPair.getPublic();
+ ePrivKey = bigIntegerToBytes(ecPrivKey.getD());
+ ePubKey = ecPubKey.getQ().getEncoded(false);
+ curve = SM2Utils.getCurve();
+ domainParams = SM2Utils.getDomainParams();
}
- public BigInteger calculateAgreement(CipherParameters otherEPubKey){
+ public static byte[] calculateAgreement(byte[] otherEPubKey, byte[] ePrivKey){
ECDHBasicAgreement basicAgreement = new ECDHBasicAgreement();
- basicAgreement.init(ePrivKey);
- return basicAgreement.calculateAgreement(otherEPubKey);
+ ECPoint ePubKeyPoint = resolvePubKeyBytes(otherEPubKey);
+ ECPublicKeyParameters pubKey = new ECPublicKeyParameters(ePubKeyPoint, domainParams);
+ ECPrivateKeyParameters privateKey = new ECPrivateKeyParameters(new BigInteger(1,ePrivKey), domainParams);
+
+ basicAgreement.init(privateKey);
+ BigInteger agreement = basicAgreement.calculateAgreement(pubKey);
+ return bigIntegerToBytes(agreement);
}
- public static BigInteger deriveShares(byte[] frontID, byte[] rearID, BigInteger agreement){
- byte[] agreementBytes = agreement.toByteArray();
+ public static byte[] deriveShares(byte[] frontID, byte[] rearID, byte[] agreementBytes){
byte[] inputBytes = BytesUtils.concat(frontID,rearID,agreementBytes);
- return new BigInteger(1,SM3Utils.hash(inputBytes));
+ return SM3Utils.hash(inputBytes);
}
- public static BigInteger encryptBlindedMsg(PaillierPublicKey encKey, BigInteger msg, BigInteger frontShare, BigInteger rearShare){
+ public static byte[] encryptBlindedMsg(byte[] paillierPubKey, int input, byte[] frontShare, byte[] rearShare){
+ BigInteger integer = BigInteger.valueOf(input);
+ BigInteger frontInteger = new BigInteger(1,frontShare);
+ BigInteger rearInteger = new BigInteger(1,rearShare);
+ PaillierPublicKeyParameters encKey = PaillierUtils.bytes2PubKey(paillierPubKey);
BigInteger modulus = encKey.getModulus();
- BigInteger plaintext = msg.add(frontShare).subtract(rearShare).mod(modulus);
- return encKey.raw_encrypt(plaintext);
+ BigInteger plaintext = integer.add(frontInteger).subtract(rearInteger).mod(modulus);
+ return PaillierUtils.encrypt(plaintext.toByteArray(),encKey);
}
- public static BigInteger aggregateCiphertexts(PaillierPublicKey encKey, BigInteger... bigIntegers){
- BigInteger aggregatedCiphertext = BigInteger.ONE;
- BigInteger modulusSquared = encKey.getModulusSquared();
- for (BigInteger entry : bigIntegers) {
- aggregatedCiphertext = aggregatedCiphertext.multiply(entry).mod(modulusSquared);
- }
- return aggregatedCiphertext;
+ public static byte[] aggregateCiphertexts(byte[] paillierPubKey, byte[]... ciphertexts){
+ return PaillierUtils.add(paillierPubKey,ciphertexts);
}
- public static BigInteger decrypt(PaillierPrivateKey decKey, BigInteger ciphertext){
- return decKey.raw_decrypt(ciphertext);
+ public static byte[] decrypt(byte[] paillierPrivKey, byte[] ciphertext){
+ return PaillierUtils.decrypt(ciphertext,paillierPrivKey);
}
- public ECPublicKeyParameters getEPubKey(){return ePubKey;}
+ public static byte[] getEPubKey(){return ePubKey;}
- public ECPrivateKeyParameters getEPrivKey(){return ePrivKey;}
+ public static byte[] getEPrivKey(){return ePrivKey;}
- public byte[] getEPubKeyBytes(){
- byte[] ePubKeyBytes = new byte[65];
- byte[] ePubKeyBytesX = ePubKey.getQ().getAffineXCoord().getEncoded();
- byte[] ePubKeyBytesY = ePubKey.getQ().getAffineYCoord().getEncoded();
- System.arraycopy(Hex.decode("04"),0,ePubKeyBytes,0,1);
- System.arraycopy(ePubKeyBytesX,0,ePubKeyBytes,1,32);
- System.arraycopy(ePubKeyBytesY,0,ePubKeyBytes,1+32,32);
- return ePubKeyBytes;
- }
-
- public byte[] getEPrivKeyBytes(){
- return BigIntegerToLBytes(ePrivKey.getD(),32);
- }
+// public byte[] getEPubKeyBytes(){
+// byte[] ePubKeyBytes = new byte[65];
+// byte[] ePubKeyBytesX = ePubKey.getQ().getAffineXCoord().getEncoded();
+// byte[] ePubKeyBytesY = ePubKey.getQ().getAffineYCoord().getEncoded();
+// System.arraycopy(Hex.decode("04"),0,ePubKeyBytes,0,1);
+// System.arraycopy(ePubKeyBytesX,0,ePubKeyBytes,1,32);
+// System.arraycopy(ePubKeyBytesY,0,ePubKeyBytes,1+32,32);
+// return ePubKeyBytes;
+// }
+//
+// public byte[] getEPrivKeyBytes(){
+// return bigIntegerToBytes(ePrivKey.getD());
+// }
public ECPublicKeyParameters resolveEPubKey(byte[] ePubKeyBytes){
byte[] ePubKeyX = new byte[32];
@@ -97,9 +100,9 @@ public class MultiSum {
}
// To convert BigInteger to byte[] whose length is l
- private static byte[] BigIntegerToLBytes(BigInteger b, int l){
+ private static byte[] bigIntegerToBytes(BigInteger b){
byte[] tmp = b.toByteArray();
- byte[] result = new byte[l];
+ byte[] result = new byte[32];
if (tmp.length > result.length) {
System.arraycopy(tmp, tmp.length - result.length, result, 0, result.length);
}
@@ -108,4 +111,10 @@ public class MultiSum {
}
return result;
}
+
+ // To retrieve the public key point from publicKey in byte array mode
+ private static ECPoint resolvePubKeyBytes(byte[] publicKey){
+ return curve.decodePoint(publicKey);
+ }
+
}
diff --git a/source/crypto/crypto-adv/src/main/java/com/jd/blockchain/crypto/paillier/PaillierKeyPairGenerator.java b/source/crypto/crypto-adv/src/main/java/com/jd/blockchain/crypto/paillier/PaillierKeyPairGenerator.java
new file mode 100644
index 00000000..abb72987
--- /dev/null
+++ b/source/crypto/crypto-adv/src/main/java/com/jd/blockchain/crypto/paillier/PaillierKeyPairGenerator.java
@@ -0,0 +1,51 @@
+package com.jd.blockchain.crypto.paillier;
+
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.math.Primes;
+import org.bouncycastle.util.BigIntegers;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+/**
+ * @author zhanglin33
+ * @title: PaillierKeyPairGenerator
+ * @description: generator of paillier key pair
+ * @date 2019-04-30, 14:48
+ */
+public class PaillierKeyPairGenerator {
+
+ private static final int STRENGTH = 2048;
+
+ public AsymmetricCipherKeyPair generateKeyPair() {
+
+ int pLength = (STRENGTH + 1) / 2;
+ int qLength = STRENGTH - pLength;
+
+ BigInteger p;
+ BigInteger q;
+ BigInteger n;
+
+ do {
+ do {
+ SecureRandom pRandom = new SecureRandom();
+ p = BigIntegers.createRandomPrime(pLength, 1, pRandom);
+ } while (!isProbablePrime(p));
+ do {
+ SecureRandom qRandom = new SecureRandom();
+ q = BigIntegers.createRandomPrime(qLength, 1, qRandom);
+ } while (q.equals(p) || !isProbablePrime(p));
+ n = q.multiply(p);
+ } while (n.bitLength() != STRENGTH);
+
+ return new AsymmetricCipherKeyPair(new PaillierPublicKeyParameters(n), new PaillierPrivateKeyParameters(p,q));
+ }
+
+ // Primes class for FIPS 186-4 C.3 primality checking
+ private boolean isProbablePrime(BigInteger x)
+ {
+ int iterations = 3;
+ SecureRandom random = new SecureRandom();
+ return !Primes.hasAnySmallFactors(x) && Primes.isMRProbablePrime(x, random, iterations);
+ }
+}
diff --git a/source/crypto/crypto-adv/src/main/java/com/jd/blockchain/crypto/paillier/PaillierPrivateKeyParameters.java b/source/crypto/crypto-adv/src/main/java/com/jd/blockchain/crypto/paillier/PaillierPrivateKeyParameters.java
new file mode 100644
index 00000000..5dcb2f0f
--- /dev/null
+++ b/source/crypto/crypto-adv/src/main/java/com/jd/blockchain/crypto/paillier/PaillierPrivateKeyParameters.java
@@ -0,0 +1,101 @@
+package com.jd.blockchain.crypto.paillier;
+
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+
+import java.math.BigInteger;
+
+import static org.bouncycastle.util.BigIntegers.ONE;
+
+/**
+ * @author zhanglin33
+ * @title: PaillierPrivateKeyParameters
+ * @description: parameters about Paillier private key
+ * @date 2019-04-30, 14:39
+ */
+public class PaillierPrivateKeyParameters extends AsymmetricKeyParameter {
+
+ private BigInteger p;
+
+ private BigInteger q;
+
+ private BigInteger pSquared;
+
+ private BigInteger qSquared;
+
+ private BigInteger pInverse;
+
+ private BigInteger muP;
+
+ private BigInteger muQ;
+
+ public PaillierPrivateKeyParameters(BigInteger p, BigInteger q) {
+ super(true);
+ BigInteger generator = p.multiply(q).add(ONE);
+ this.p = p;
+ this.pSquared = p.multiply(p);
+ this.q = q;
+ this.qSquared = q.multiply(q);
+ this.pInverse = p.modInverse(q);
+ this.muP = hFunction(generator, p, pSquared);
+ this.muQ = hFunction(generator, q, qSquared);
+ }
+
+ public PaillierPrivateKeyParameters(BigInteger p, BigInteger pSquared, BigInteger q, BigInteger qSquared,
+ BigInteger pInverse, BigInteger muP, BigInteger muQ){
+ super(true);
+ this.p = p;
+ this.pSquared = pSquared;
+ this.q = q;
+ this.qSquared = qSquared;
+ this.pInverse = pInverse;
+ this.muP = muP;
+ this.muQ = muQ;
+ }
+
+
+ // mu = h(x) = (L(g^(x-1) mod x^2))^(-1) mod n
+ private BigInteger hFunction(BigInteger generator, BigInteger x, BigInteger xSquared) {
+ BigInteger phiX = lFunction(generator.modPow(x.subtract(ONE),xSquared),x);
+ return phiX.modInverse(x);
+ }
+
+ // L(x) = (x-1) / n
+ public BigInteger lFunction(BigInteger x, BigInteger n) {
+ return x.subtract(ONE).divide(n);
+ }
+
+ public BigInteger getP()
+ {
+ return p;
+ }
+
+ public BigInteger getPSquared()
+ {
+ return pSquared;
+ }
+
+ public BigInteger getQ()
+ {
+ return q;
+ }
+
+ public BigInteger getQSquared()
+ {
+ return qSquared;
+ }
+
+ public BigInteger getPInverse()
+ {
+ return pInverse;
+ }
+
+ public BigInteger getMuP()
+ {
+ return muP;
+ }
+
+ public BigInteger getMuQ()
+ {
+ return muQ;
+ }
+}
diff --git a/source/crypto/crypto-adv/src/main/java/com/jd/blockchain/crypto/paillier/PaillierPublicKeyParameters.java b/source/crypto/crypto-adv/src/main/java/com/jd/blockchain/crypto/paillier/PaillierPublicKeyParameters.java
new file mode 100644
index 00000000..3706b6b2
--- /dev/null
+++ b/source/crypto/crypto-adv/src/main/java/com/jd/blockchain/crypto/paillier/PaillierPublicKeyParameters.java
@@ -0,0 +1,59 @@
+package com.jd.blockchain.crypto.paillier;
+
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+
+import java.math.BigInteger;
+
+import static org.bouncycastle.util.BigIntegers.ONE;
+
+/**
+ * @author zhanglin33
+ * @title: PaillierPublicKeyParameters
+ * @description: parameters about Paillier public key
+ * @date 2019-04-30, 14:41
+ */
+public class PaillierPublicKeyParameters extends AsymmetricKeyParameter {
+
+ private BigInteger modulus;
+ private BigInteger modulusSquared;
+ private BigInteger generator;
+
+ public PaillierPublicKeyParameters(BigInteger modulus) {
+ super(false);
+ this.modulus = validate(modulus);
+ this.modulusSquared = modulus.multiply(modulus);
+ this.generator = modulus.add(ONE);
+ }
+
+ public BigInteger getModulus() {
+ return modulus;
+ }
+
+ public BigInteger getModulusSquared() {
+ return modulusSquared;
+ }
+
+ public BigInteger getGenerator() {
+ return generator;
+ }
+
+ private BigInteger validate(BigInteger modulus)
+ {
+ if ((modulus.intValue() & 1) == 0)
+ {
+ throw new IllegalArgumentException("The modulus is even!");
+ }
+
+ // the value is the product of the 132 smallest primes from 3 to 751
+ if (!modulus.gcd(new BigInteger("145188775577763990151158743208307020242261438098488931355057091965" +
+ "931517706595657435907891265414916764399268423699130577757433083166" +
+ "651158914570105971074227669275788291575622090199821297575654322355" +
+ "049043101306108213104080801056529374892690144291505781966373045481" +
+ "8359472391642885328171302299245556663073719855")).equals(ONE))
+ {
+ throw new IllegalArgumentException("The modulus has a small prime factor!");
+ }
+
+ return modulus;
+ }
+}
diff --git a/source/crypto/crypto-adv/src/main/java/com/jd/blockchain/crypto/paillier/PaillierUtils.java b/source/crypto/crypto-adv/src/main/java/com/jd/blockchain/crypto/paillier/PaillierUtils.java
new file mode 100644
index 00000000..3d765df3
--- /dev/null
+++ b/source/crypto/crypto-adv/src/main/java/com/jd/blockchain/crypto/paillier/PaillierUtils.java
@@ -0,0 +1,218 @@
+package com.jd.blockchain.crypto.paillier;
+
+import com.jd.blockchain.utils.io.BytesUtils;
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import static org.bouncycastle.util.BigIntegers.ONE;
+
+/**
+ * @author zhanglin33
+ * @title: PaillierUtils
+ * @description: encryption, decryption, homomorphic addition and scalar multiplication in Paillier algorithm
+ * @date 2019-04-30, 14:49
+ */
+public class PaillierUtils {
+
+ private static final int MODULUS_LENGTH = 256;
+ private static final int MODULUSSQUARED_LENGTH = 512;
+
+ private static final int P_LENGTH = 128;
+ private static final int PSQUARED_LENGTH = 256;
+ private static final int Q_LENGTH = 128;
+ private static final int QSQUARED_LENGTH = 256;
+ private static final int PINVERSE_LENGTH = 128;
+ private static final int MUP_LENGTH = 128;
+ private static final int MUQ_LENGTH = 128;
+
+ private static final int PRIVKEY_LENGTH = P_LENGTH + PSQUARED_LENGTH + Q_LENGTH + QSQUARED_LENGTH
+ + PINVERSE_LENGTH + MUP_LENGTH + MUQ_LENGTH;
+
+ public static AsymmetricCipherKeyPair generateKeyPair(){
+ PaillierKeyPairGenerator generator = new PaillierKeyPairGenerator();
+ return generator.generateKeyPair();
+ }
+
+ public static byte[] encrypt(byte[] plainBytes, byte[] publicKey) {
+ PaillierPublicKeyParameters pubKeyParams = bytes2PubKey(publicKey);
+ return encrypt(plainBytes, pubKeyParams);
+ }
+
+ public static byte[] encrypt(byte[] plainBytes, PaillierPublicKeyParameters pubKeyParams) {
+ SecureRandom random = new SecureRandom();
+ return encrypt(plainBytes, pubKeyParams, random);
+ }
+
+ // c = g^m * r^n mod n^2 = (1+n)^m * r^n mod n^2 = (1 + n*m mod n^2) * r^n mod n^2
+ public static byte[] encrypt(byte[] plainBytes, PaillierPublicKeyParameters pubKeyParams, SecureRandom random){
+
+ BigInteger n = pubKeyParams.getModulus();
+ BigInteger nSquared = pubKeyParams.getModulusSquared();
+
+ BigInteger m = new BigInteger(1,plainBytes);
+ BigInteger r = new BigInteger(n.bitLength(), random);
+
+ BigInteger rawCiphertext = n.multiply(m).add(ONE).mod(nSquared);
+ BigInteger c = r.modPow(n, nSquared).multiply(rawCiphertext).mod(nSquared);
+
+ return bigIntegerToBytes(c, MODULUSSQUARED_LENGTH);
+ }
+
+
+ public static byte[] decrypt(byte[] cipherBytes, byte[] privateKey) {
+ PaillierPrivateKeyParameters privKeyParams = bytes2PrivKey(privateKey);
+ return decrypt(cipherBytes,privKeyParams);
+ }
+ // m mod p = L(c^(p-1) mod p^2) * muP mod p
+ // m mod q = L(c^(q-1) mod q^2) * muQ mod q
+ // m = (m mod p) * (1/q mod p) * q + (m mod q) * (1/p mod q) * p
+ // = ((m mod q)-(m mod p)) * (1/p mod q) mod q * p + (m mod p)
+ public static byte[] decrypt(byte[] cipherBytes, PaillierPrivateKeyParameters privKeyParams){
+
+ BigInteger cihphertext = new BigInteger(1, cipherBytes);
+
+ BigInteger p = privKeyParams.getP();
+ BigInteger pSquared = privKeyParams.getPSquared();
+ BigInteger q = privKeyParams.getQ();
+ BigInteger qSquared = privKeyParams.getQSquared();
+ BigInteger pInverse = privKeyParams.getPInverse();
+ BigInteger muP = privKeyParams.getMuP();
+ BigInteger muQ = privKeyParams.getMuQ();
+
+ BigInteger mModP =
+ privKeyParams.lFunction(cihphertext.modPow(p.subtract(ONE),pSquared),p).multiply(muP).mod(p);
+ BigInteger mModQ =
+ privKeyParams.lFunction(cihphertext.modPow(q.subtract(ONE),qSquared),q).multiply(muQ).mod(q);
+
+ BigInteger midValue = mModQ.subtract(mModP).multiply(pInverse).mod(q);
+ BigInteger m = midValue.multiply(p).add(mModP);
+
+ return m.toByteArray();
+ }
+
+
+ public static byte[] pubKey2Bytes(PaillierPublicKeyParameters pubKeyParams) {
+ BigInteger n = pubKeyParams.getModulus();
+ return bigIntegerToBytes(n, MODULUS_LENGTH);
+ }
+
+ public static PaillierPublicKeyParameters bytes2PubKey(byte[] publicKey) {
+
+ if (publicKey.length != MODULUS_LENGTH) {
+ throw new IllegalArgumentException("publicKey's length does not meet algorithm's requirement!");
+ }
+
+ BigInteger n = new BigInteger(1, publicKey);
+ return new PaillierPublicKeyParameters(n);
+ }
+
+
+ public static byte[] privKey2Bytes(PaillierPrivateKeyParameters privKeyParams) {
+
+ BigInteger p = privKeyParams.getP();
+ BigInteger pSquared = privKeyParams.getPSquared();
+ BigInteger q = privKeyParams.getQ();
+ BigInteger qSquared = privKeyParams.getQSquared();
+ BigInteger pInverse = privKeyParams.getPInverse();
+ BigInteger muP = privKeyParams.getMuP();
+ BigInteger muQ = privKeyParams.getMuQ();
+
+ byte[] pBytes = bigIntegerToBytes(p, P_LENGTH);
+ byte[] pSquaredBytes = bigIntegerToBytes(pSquared, PSQUARED_LENGTH);
+ byte[] qBytes = bigIntegerToBytes(q, Q_LENGTH);
+ byte[] qSquaredBytes = bigIntegerToBytes(qSquared, QSQUARED_LENGTH);
+ byte[] pInverseBytes = bigIntegerToBytes(pInverse, PINVERSE_LENGTH);
+ byte[] muPBytes = bigIntegerToBytes(muP, MUP_LENGTH);
+ byte[] muQBytes = bigIntegerToBytes(muQ, MUQ_LENGTH);
+
+ return BytesUtils.concat(pBytes,pSquaredBytes,qBytes,qSquaredBytes,pInverseBytes,muPBytes,muQBytes);
+ }
+
+ public static PaillierPrivateKeyParameters bytes2PrivKey(byte[] privateKey) {
+
+ if (privateKey.length != PRIVKEY_LENGTH) {
+ throw new IllegalArgumentException("privateKey's length does not meet algorithm's requirement!");
+ }
+
+ byte[] pBytes = new byte[P_LENGTH];
+ byte[] pSquaredBytes = new byte[PSQUARED_LENGTH];
+ byte[] qBytes = new byte[Q_LENGTH];
+ byte[] qSquaredBytes = new byte[QSQUARED_LENGTH];
+ byte[] pInverseBytes = new byte[PINVERSE_LENGTH];
+ byte[] muPBytes = new byte[MUP_LENGTH];
+ byte[] muQBytes = new byte[MUQ_LENGTH];
+
+ split(privateKey,pBytes,pSquaredBytes,qBytes,qSquaredBytes,pInverseBytes,muPBytes,muQBytes);
+
+ BigInteger p = new BigInteger(1, pBytes);
+ BigInteger pSquared = new BigInteger(1, pSquaredBytes);
+ BigInteger q = new BigInteger(1, qBytes);
+ BigInteger qSquared = new BigInteger(1, qSquaredBytes);
+ BigInteger pInverse = new BigInteger(1, pInverseBytes);
+ BigInteger muP = new BigInteger(1, muPBytes);
+ BigInteger muQ = new BigInteger(1, muQBytes);
+
+ return new PaillierPrivateKeyParameters(p,pSquared,q,qSquared,pInverse,muP,muQ);
+ }
+
+ public static byte[] add(byte[] publicKey, byte[]... ciphertexts) {
+ PaillierPublicKeyParameters pubKeyParams = bytes2PubKey(publicKey);
+ return add(pubKeyParams,ciphertexts);
+ }
+
+ public static byte[] add(PaillierPublicKeyParameters pubKeyParams, byte[]... ciphertexts) {
+
+ BigInteger result = ONE;
+ BigInteger multiplier;
+ BigInteger nSquared = pubKeyParams.getModulusSquared();
+ for (byte[] each: ciphertexts) {
+ multiplier = new BigInteger(1, each);
+ result = result.multiply(multiplier).mod(nSquared);
+ }
+
+ return bigIntegerToBytes(result, MODULUSSQUARED_LENGTH);
+ }
+
+ public static byte[] scalarMultiply(byte[] publicKey, byte[] cipherBytes, long scalar) {
+ PaillierPublicKeyParameters pubKeyParams = bytes2PubKey(publicKey);
+ return scalarMultiply(pubKeyParams,cipherBytes,scalar);
+ }
+
+ public static byte[] scalarMultiply(PaillierPublicKeyParameters pubKeyParams, byte[] cipherBytes, long scalar) {
+
+ BigInteger nSquared = pubKeyParams.getModulusSquared();
+ BigInteger cihertext = new BigInteger(1, cipherBytes);
+ BigInteger exponent = BigInteger.valueOf(scalar);
+
+ BigInteger result = cihertext.modPow(exponent,nSquared);
+
+ return bigIntegerToBytes(result, MODULUSSQUARED_LENGTH);
+ }
+
+ // To convert BigInteger to byte array in specified size
+ private static byte[] bigIntegerToBytes(BigInteger b, int bytesSize){
+ byte[] tmp = b.toByteArray();
+ byte[] result = new byte[bytesSize];
+ if (tmp.length > result.length) {
+ System.arraycopy(tmp, tmp.length - result.length, result, 0, result.length);
+ }
+ else {
+ System.arraycopy(tmp,0,result,result.length-tmp.length,tmp.length);
+ }
+ return result;
+ }
+
+ private static void split(byte[] src, byte[]... bytesList) {
+
+ int srcPos = 0;
+ for (byte[] each: bytesList){
+ System.arraycopy(src,srcPos,each,0,each.length);
+ srcPos += each.length;
+ if (srcPos >= src.length){
+ break;
+ }
+ }
+ }
+}
diff --git a/source/crypto/crypto-adv/src/test/java/test/com/jd/blockchain/crypto/mpc/MultiSumTest.java b/source/crypto/crypto-adv/src/test/java/test/com/jd/blockchain/crypto/mpc/MultiSumTest.java
index 2bb53407..6c04a74a 100644
--- a/source/crypto/crypto-adv/src/test/java/test/com/jd/blockchain/crypto/mpc/MultiSumTest.java
+++ b/source/crypto/crypto-adv/src/test/java/test/com/jd/blockchain/crypto/mpc/MultiSumTest.java
@@ -1,103 +1,88 @@
package test.com.jd.blockchain.crypto.mpc;
import com.jd.blockchain.crypto.mpc.MultiSum;
-import com.n1analytics.paillier.PaillierPrivateKey;
-import com.n1analytics.paillier.PaillierPublicKey;
-import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
-import org.bouncycastle.crypto.params.ECPublicKeyParameters;
-import org.bouncycastle.util.encoders.Hex;
-import org.junit.Before;
+import com.jd.blockchain.crypto.paillier.PaillierPrivateKeyParameters;
+import com.jd.blockchain.crypto.paillier.PaillierPublicKeyParameters;
+import com.jd.blockchain.crypto.paillier.PaillierUtils;
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.junit.Test;
-import java.math.BigInteger;
-
import static org.junit.Assert.*;
public class MultiSumTest {
- private PaillierPrivateKey decKey;
- private PaillierPublicKey encKey;
-
- @Before
- public void init() {
- decKey = PaillierPrivateKey.create(2048);
- encKey = decKey.getPublicKey();
- }
-
@Test
public void testMultiSum() {
- MultiSum instance1 = new MultiSum();
- MultiSum instance2 = new MultiSum();
- MultiSum instance3 = new MultiSum();
+ AsymmetricCipherKeyPair keyPair = PaillierUtils.generateKeyPair();
+ PaillierPublicKeyParameters pubKeyParams = (PaillierPublicKeyParameters) keyPair.getPublic();
+ PaillierPrivateKeyParameters privKeyParams = (PaillierPrivateKeyParameters) keyPair.getPrivate();
- BigInteger value1 = BigInteger.valueOf(6);
- BigInteger value2 = BigInteger.valueOf(60);
- BigInteger value3 = BigInteger.valueOf(600);
- BigInteger expectedSum = BigInteger.valueOf(666);
+ byte[] encKey = PaillierUtils.pubKey2Bytes(pubKeyParams);
+ byte[] decKey = PaillierUtils.privKey2Bytes(privKeyParams);
+
+ int int1 = 6;
+ int int2 = 60;
+ int int3 = 600;
+ int sum = 666;
byte[] id1 = "1".getBytes();
byte[] id2 = "2".getBytes();
byte[] id3 = "3".getBytes();
- instance1.generateEphemeralKeyPair();
- instance2.generateEphemeralKeyPair();
- instance3.generateEphemeralKeyPair();
+ MultiSum.generateEphemeralKeyPair();
+ byte[] ePubKey1 = MultiSum.getEPubKey();
+ byte[] ePrivKey1 = MultiSum.getEPrivKey();
- ECPublicKeyParameters ePubKey1 = instance1.getEPubKey();
- ECPublicKeyParameters ePubKey2 = instance2.getEPubKey();
- ECPublicKeyParameters ePubKey3 = instance3.getEPubKey();
+ MultiSum.generateEphemeralKeyPair();
+ byte[] ePubKey2 = MultiSum.getEPubKey();
+ byte[] ePrivKey2 = MultiSum.getEPrivKey();
- BigInteger sk12 = instance1.calculateAgreement(ePubKey2);
- BigInteger sk23 = instance2.calculateAgreement(ePubKey3);
- BigInteger sk31 = instance1.calculateAgreement(ePubKey3);
+ MultiSum.generateEphemeralKeyPair();
+ byte[] ePubKey3 = MultiSum.getEPubKey();
+ byte[] ePrivKey3 = MultiSum.getEPrivKey();
- assertEquals(sk12,instance2.calculateAgreement(ePubKey1));
- assertEquals(sk23,instance3.calculateAgreement(ePubKey2));
- assertEquals(sk31,instance3.calculateAgreement(ePubKey1));
- BigInteger s12 = MultiSum.deriveShares(id1,id2,sk12);
- BigInteger s23 = MultiSum.deriveShares(id2,id3,sk23);
- BigInteger s31 = MultiSum.deriveShares(id3,id1,sk31);
+ byte[] sk12 = MultiSum.calculateAgreement(ePubKey2,ePrivKey1);
+ byte[] sk23 = MultiSum.calculateAgreement(ePubKey3,ePrivKey2);
+ byte[] sk31 = MultiSum.calculateAgreement(ePubKey1,ePrivKey3);
- assertEquals(s12, MultiSum.deriveShares(id1,id2,sk12));
- assertEquals(s23, MultiSum.deriveShares(id2,id3,sk23));
- assertEquals(s31, MultiSum.deriveShares(id3,id1,sk31));
+ assertArrayEquals(sk12,MultiSum.calculateAgreement(ePubKey1,ePrivKey2));
+ assertArrayEquals(sk23,MultiSum.calculateAgreement(ePubKey2,ePrivKey3));
+ assertArrayEquals(sk31,MultiSum.calculateAgreement(ePubKey3,ePrivKey1));
- BigInteger c1 = MultiSum.encryptBlindedMsg(encKey,value1,s12,s31);
- BigInteger c2 = MultiSum.encryptBlindedMsg(encKey,value2,s23,s12);
- BigInteger c3 = MultiSum.encryptBlindedMsg(encKey,value3,s31,s23);
+ byte[] s12 = MultiSum.deriveShares(id1,id2,sk12);
+ byte[] s23 = MultiSum.deriveShares(id2,id3,sk23);
+ byte[] s31 = MultiSum.deriveShares(id3,id1,sk31);
- BigInteger aggregatedCiphertext = MultiSum.aggregateCiphertexts(encKey,c1,c2,c3);
+ assertArrayEquals(s12, MultiSum.deriveShares(id1,id2,sk12));
+ assertArrayEquals(s23, MultiSum.deriveShares(id2,id3,sk23));
+ assertArrayEquals(s31, MultiSum.deriveShares(id3,id1,sk31));
- BigInteger decryptedValue = MultiSum.decrypt(decKey,aggregatedCiphertext);
+ byte[] c1 = MultiSum.encryptBlindedMsg(encKey,int1,s12,s31);
+ byte[] c2 = MultiSum.encryptBlindedMsg(encKey,int2,s23,s12);
+ byte[] c3 = MultiSum.encryptBlindedMsg(encKey,int3,s31,s23);
- assertEquals(expectedSum,decryptedValue);
- }
+ byte[] aggregatedCiphertext = MultiSum.aggregateCiphertexts(encKey,c1,c2,c3);
- @Test
- public void testResolveEPrivKey(){
+ byte[] decryptedValue = MultiSum.decrypt(decKey,aggregatedCiphertext);
- MultiSum instance = new MultiSum();
- instance.generateEphemeralKeyPair();
-
- ECPrivateKeyParameters expectedEPrivKey = instance.getEPrivKey();
- byte[] ePrivKeyBytes = instance.getEPrivKeyBytes();
- ECPrivateKeyParameters ePrivKey = instance.resolveEPrivKey(ePrivKeyBytes);
- assertEquals(expectedEPrivKey.getD(),ePrivKey.getD());
+ assertEquals(sum,byteArrayToInt(decryptedValue));
}
- @Test
- public void testResolveEPubKey(){
-
- MultiSum instance = new MultiSum();
- instance.generateEphemeralKeyPair();
-
- ECPublicKeyParameters expectedEPubKey = instance.getEPubKey();
- byte[] ePubKeyBytes = instance.getEPubKeyBytes();
- ECPublicKeyParameters ePubKey = instance.resolveEPubKey(ePubKeyBytes);
-
- assertEquals(Hex.toHexString(expectedEPubKey.getQ().getAffineXCoord().getEncoded()),Hex.toHexString(ePubKey.getQ().getAffineXCoord().getEncoded()));
- assertEquals(Hex.toHexString(expectedEPubKey.getQ().getAffineYCoord().getEncoded()),Hex.toHexString(ePubKey.getQ().getAffineYCoord().getEncoded()));
+ private static int byteArrayToInt(byte[] input) {
+ int result;
+ int length = input.length;
+ byte[] buffer = new byte[4];
+ if (length <= buffer.length){
+ System.arraycopy(input,0,buffer,buffer.length - length,length);
+ } else {
+ System.arraycopy(input,length - buffer.length,buffer,0, buffer.length);
+ }
+ result = buffer[3] & 0xFF |
+ (buffer[2] & 0xFF) << 8 |
+ (buffer[1] & 0xFF) << 16 |
+ (buffer[0] & 0xFF) << 24;
+ return result;
}
}
\ No newline at end of file
diff --git a/source/crypto/crypto-adv/src/test/java/test/com/jd/blockchain/crypto/paillier/PaillierUtilsTest.java b/source/crypto/crypto-adv/src/test/java/test/com/jd/blockchain/crypto/paillier/PaillierUtilsTest.java
new file mode 100644
index 00000000..8ace44d1
--- /dev/null
+++ b/source/crypto/crypto-adv/src/test/java/test/com/jd/blockchain/crypto/paillier/PaillierUtilsTest.java
@@ -0,0 +1,202 @@
+package test.com.jd.blockchain.crypto.paillier;
+
+import com.jd.blockchain.crypto.paillier.PaillierPrivateKeyParameters;
+import com.jd.blockchain.crypto.paillier.PaillierPublicKeyParameters;
+import com.jd.blockchain.crypto.paillier.PaillierUtils;
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.junit.Test;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author zhanglin33
+ * @title: PaillierUtilsTest
+ * @description: Tests on PaillierUtils
+ * @date 2019-04-30, 14:54
+ */
+public class PaillierUtilsTest {
+ @Test
+ public void generateKeyPairTest() {
+
+ AsymmetricCipherKeyPair keyPair = PaillierUtils.generateKeyPair();
+ PaillierPublicKeyParameters pubKeyParams = (PaillierPublicKeyParameters) keyPair.getPublic();
+ PaillierPrivateKeyParameters privKeyParams = (PaillierPrivateKeyParameters) keyPair.getPrivate();
+
+ BigInteger n = pubKeyParams.getModulus();
+ BigInteger nSquared = pubKeyParams.getModulusSquared();
+ BigInteger g = pubKeyParams.getGenerator();
+
+ BigInteger nConverted = new BigInteger(1, bigIntegerToBytes(n,256));
+ BigInteger nSquaredConverted = new BigInteger(1, bigIntegerToBytes(nSquared,512));
+ BigInteger gConverted = new BigInteger(1, bigIntegerToBytes(g,256));
+ assertEquals(nConverted, n);
+ assertEquals(nSquaredConverted, nSquared);
+ assertEquals(gConverted, g);
+
+ BigInteger p = privKeyParams.getP();
+ BigInteger pSquared = privKeyParams.getPSquared();
+ BigInteger q = privKeyParams.getQ();
+ BigInteger qSquared = privKeyParams.getQSquared();
+ BigInteger pInverse = privKeyParams.getPInverse();
+ BigInteger muP = privKeyParams.getMuP();
+ BigInteger muQ = privKeyParams.getMuQ();
+
+ BigInteger pConverted = new BigInteger(1, bigIntegerToBytes(p,128));
+ BigInteger pSquaredConverted = new BigInteger(1, bigIntegerToBytes(pSquared,256));
+ BigInteger qConverted = new BigInteger(1, bigIntegerToBytes(q,128));
+ BigInteger qSquaredConverted = new BigInteger(1, bigIntegerToBytes(qSquared,256));
+ BigInteger pInverseConverted = new BigInteger(1, bigIntegerToBytes(pInverse,128));
+ BigInteger muPConverted = new BigInteger(1, bigIntegerToBytes(muP,128));
+ BigInteger muQConverted = new BigInteger(1, bigIntegerToBytes(muQ,128));
+ assertEquals(pConverted, p);
+ assertEquals(pSquaredConverted, pSquared);
+ assertEquals(qConverted, q);
+ assertEquals(qSquaredConverted, qSquared);
+ assertEquals(pInverseConverted, pInverse);
+ assertEquals(muPConverted, muP);
+ assertEquals(muQConverted, muQ);
+ }
+
+ @Test
+ public void encryptTest() {
+
+ AsymmetricCipherKeyPair keyPair = PaillierUtils.generateKeyPair();
+ PaillierPublicKeyParameters pubKeyParams = (PaillierPublicKeyParameters) keyPair.getPublic();
+
+ byte[] pubKeyBytes = PaillierUtils.pubKey2Bytes(pubKeyParams);
+
+ SecureRandom random = new SecureRandom();
+ byte[] data = new byte[256];
+ random.nextBytes(data);
+
+ byte[] ciphertextFromParams = PaillierUtils.encrypt(data,pubKeyParams);
+ byte[] ciphertextFromBytes = PaillierUtils.encrypt(data,pubKeyBytes);
+
+ assertEquals(512,ciphertextFromParams.length);
+ assertEquals(512,ciphertextFromBytes.length);
+ }
+
+ @Test
+ public void decryptTest(){
+
+ AsymmetricCipherKeyPair keyPair = PaillierUtils.generateKeyPair();
+ PaillierPublicKeyParameters pubKeyParams = (PaillierPublicKeyParameters) keyPair.getPublic();
+ PaillierPrivateKeyParameters privKeyParams = (PaillierPrivateKeyParameters) keyPair.getPrivate();
+
+ byte[] pubKeyBytes = PaillierUtils.pubKey2Bytes(pubKeyParams);
+ byte[] privKeyBytes = PaillierUtils.privKey2Bytes(privKeyParams);
+
+ int input = 666;
+ byte[] data = intToByteArray(input);
+
+ byte[] ciphertextFromParams = PaillierUtils.encrypt(data,pubKeyParams);
+ byte[] ciphertextFromBytes = PaillierUtils.encrypt(data,pubKeyBytes);
+
+ byte[] plaintextFromParams = PaillierUtils.decrypt(ciphertextFromBytes,privKeyParams);
+ byte[] plaintextFromBytes = PaillierUtils.decrypt(ciphertextFromParams,privKeyBytes);
+
+ int outputFromParams = byteArrayToInt(plaintextFromParams);
+ int outputFromBytes = byteArrayToInt(plaintextFromBytes);
+
+ assertEquals(input,outputFromParams);
+ assertEquals(input,outputFromBytes);
+ }
+
+ @Test
+ public void addTest() {
+
+ AsymmetricCipherKeyPair keyPair = PaillierUtils.generateKeyPair();
+ PaillierPublicKeyParameters pubKeyParams = (PaillierPublicKeyParameters) keyPair.getPublic();
+ PaillierPrivateKeyParameters privKeyParams = (PaillierPrivateKeyParameters) keyPair.getPrivate();
+
+ byte[] pubKeyBytes = PaillierUtils.pubKey2Bytes(pubKeyParams);
+
+ int input1 = 600;
+ int input2 = 60;
+ int input3 = 6;
+
+ int sum = 666;
+
+ byte[] data1 = intToByteArray(input1);
+ byte[] data2 = intToByteArray(input2);
+ byte[] data3 = intToByteArray(input3);
+
+ byte[] ciphertext1 = PaillierUtils.encrypt(data1,pubKeyParams);
+ byte[] ciphertext2 = PaillierUtils.encrypt(data2,pubKeyParams);
+ byte[] ciphertext3 = PaillierUtils.encrypt(data3,pubKeyParams);
+
+ byte[] aggregatedCiphertext = PaillierUtils.add(pubKeyParams,ciphertext1,ciphertext2,ciphertext3);
+ byte[] plaintext = PaillierUtils.decrypt(aggregatedCiphertext,privKeyParams);
+
+ int output = byteArrayToInt(plaintext);
+ assertEquals(sum,output);
+
+ aggregatedCiphertext = PaillierUtils.add(pubKeyBytes,ciphertext1,ciphertext2,ciphertext3);
+ plaintext = PaillierUtils.decrypt(aggregatedCiphertext,privKeyParams);
+
+ output = byteArrayToInt(plaintext);
+ assertEquals(sum,output);
+ }
+
+ @Test
+ public void scalarMultiplyTest() {
+
+ AsymmetricCipherKeyPair keyPair = PaillierUtils.generateKeyPair();
+ PaillierPublicKeyParameters pubKeyParams = (PaillierPublicKeyParameters) keyPair.getPublic();
+ PaillierPrivateKeyParameters privKeyParams = (PaillierPrivateKeyParameters) keyPair.getPrivate();
+
+ byte[] pubKeyBytes = PaillierUtils.pubKey2Bytes(pubKeyParams);
+
+ int input = 111;
+ int scalar = 6;
+ byte[] data = intToByteArray(input);
+
+ byte[] ciphertext = PaillierUtils.encrypt(data,pubKeyParams);
+ byte[] ciphertextPowered = PaillierUtils.scalarMultiply(pubKeyBytes,ciphertext,scalar);
+ byte[] plaintextMultiplied = PaillierUtils.decrypt(ciphertextPowered,privKeyParams);
+
+ int output = byteArrayToInt(plaintextMultiplied);
+ assertEquals(input * scalar, output);
+ }
+
+ private static byte[] intToByteArray(int input) {
+ byte[] result = new byte[4];
+ result[0] = (byte) ((input >> 24) & 0xFF);
+ result[1] = (byte) ((input >> 16) & 0xFF);
+ result[2] = (byte) ((input >> 8 ) & 0xFF);
+ result[3] = (byte) ((input ) & 0xFF);
+ return result;
+ }
+
+ private static int byteArrayToInt(byte[] input) {
+ int result;
+ int length = input.length;
+ byte[] buffer = new byte[4];
+ if (length <= buffer.length){
+ System.arraycopy(input,0,buffer,buffer.length - length,length);
+ } else {
+ System.arraycopy(input,length - buffer.length,buffer,0, buffer.length);
+ }
+ result = buffer[3] & 0xFF |
+ (buffer[2] & 0xFF) << 8 |
+ (buffer[1] & 0xFF) << 16 |
+ (buffer[0] & 0xFF) << 24;
+ return result;
+ }
+
+ // To convert BigInteger to byte array in specified size
+ private static byte[] bigIntegerToBytes(BigInteger b, int bytesSize){
+ byte[] tmp = b.toByteArray();
+ byte[] result = new byte[bytesSize];
+ if (tmp.length > result.length) {
+ System.arraycopy(tmp, tmp.length - result.length, result, 0, result.length);
+ }
+ else {
+ System.arraycopy(tmp,0,result,result.length-tmp.length,tmp.length);
+ }
+ return result;
+ }
+}