Browse Source

implement Paillier encryption, the additive homomorphic encryption algorithm, and renew MultiSum

tags/1.0.0
zhanglin33 5 years ago
parent
commit
c9398ccfcd
8 changed files with 743 additions and 124 deletions
  1. +0
    -6
      source/crypto/crypto-adv/pom.xml
  2. +57
    -48
      source/crypto/crypto-adv/src/main/java/com/jd/blockchain/crypto/mpc/MultiSum.java
  3. +51
    -0
      source/crypto/crypto-adv/src/main/java/com/jd/blockchain/crypto/paillier/PaillierKeyPairGenerator.java
  4. +101
    -0
      source/crypto/crypto-adv/src/main/java/com/jd/blockchain/crypto/paillier/PaillierPrivateKeyParameters.java
  5. +59
    -0
      source/crypto/crypto-adv/src/main/java/com/jd/blockchain/crypto/paillier/PaillierPublicKeyParameters.java
  6. +218
    -0
      source/crypto/crypto-adv/src/main/java/com/jd/blockchain/crypto/paillier/PaillierUtils.java
  7. +55
    -70
      source/crypto/crypto-adv/src/test/java/test/com/jd/blockchain/crypto/mpc/MultiSumTest.java
  8. +202
    -0
      source/crypto/crypto-adv/src/test/java/test/com/jd/blockchain/crypto/paillier/PaillierUtilsTest.java

+ 0
- 6
source/crypto/crypto-adv/pom.xml View File

@@ -45,11 +45,5 @@
<scope>compile</scope>
</dependency>

<dependency>
<groupId>com.n1analytics</groupId>
<artifactId>javallier_2.10</artifactId>
<version>0.6.0</version>
</dependency>

</dependencies>
</project>

+ 57
- 48
source/crypto/crypto-adv/src/main/java/com/jd/blockchain/crypto/mpc/MultiSum.java View File

@@ -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);
}

}

+ 51
- 0
source/crypto/crypto-adv/src/main/java/com/jd/blockchain/crypto/paillier/PaillierKeyPairGenerator.java View File

@@ -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);
}
}

+ 101
- 0
source/crypto/crypto-adv/src/main/java/com/jd/blockchain/crypto/paillier/PaillierPrivateKeyParameters.java View File

@@ -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;
}
}

+ 59
- 0
source/crypto/crypto-adv/src/main/java/com/jd/blockchain/crypto/paillier/PaillierPublicKeyParameters.java View File

@@ -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;
}
}

+ 218
- 0
source/crypto/crypto-adv/src/main/java/com/jd/blockchain/crypto/paillier/PaillierUtils.java View File

@@ -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;
}
}
}
}

+ 55
- 70
source/crypto/crypto-adv/src/test/java/test/com/jd/blockchain/crypto/mpc/MultiSumTest.java View File

@@ -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;
}
}

+ 202
- 0
source/crypto/crypto-adv/src/test/java/test/com/jd/blockchain/crypto/paillier/PaillierUtilsTest.java View File

@@ -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;
}
}

Loading…
Cancel
Save