1. 背景
工作中需要用到密文计算,涉及密文求和sum、平均avg以及加权平均wavg 。特此分享,供参考。
2. 代码
2.1 分数类MyFraction
涉及小数运算,但是密文目前只能存整数,所以考虑用分数来处理。用分数对象来存储分子和分母,分子是密文,分母是明文,通分时正好可以利用密文的标量乘。
public class MyFraction {
// cipher son
private BigInteger fson = new BigInteger("0");
// mon
private BigInteger fmon = new BigInteger("1");
// 密文计算器
private CipherCompute cc = null;
//
public MyFraction(BigInteger fson, BigInteger fmon, CipherCompute cc) {
this.fson = fson;
this.fmon = fmon;
this.cc = cc;
}
public MyFraction(BigInteger fson, CipherCompute cc) {
this.fson = fson;
this.cc = cc;
}
public MyFraction(BigInteger fson) {
this.fson = fson;
}
public MyFraction() {
}
// 通分后加
public MyFraction add(MyFraction mf) {
if (null == mf) return new MyFraction();
// 求分母最小公倍数
BigInteger lcm = fmon.multiply(mf.getFmon()).divide(fmon.gcd(mf.getFmon()));
// 分别要乘的系数
BigInteger son_m = lcm.divide(fmon);
BigInteger son_n = lcm.divide(mf.getFmon());
// 计算分子,分母
BigInteger mid1 = cc.cipher_multiply(fson, son_m);
BigInteger mid2 = cc.cipher_multiply(mf.getFson(), son_n);
BigInteger res_son = cc.cipher_add(mid1, mid2);
BigInteger res_mon = lcm;
MyFraction res = new MyFraction(res_son, res_mon, cc);
return res;
}
// 对数组中每一个MyFraction累加
public MyFraction sum(MyFraction[] mfarr) {
if (null == mfarr) return new MyFraction(BigInteger.ZERO, BigInteger.ONE, cc);
int len = mfarr.length;
if (0 == len) return new MyFraction(BigInteger.ZERO, BigInteger.ONE, cc);
if (1 == len) return mfarr[0];
MyFraction res = mfarr[0];
for (int i=1; i < len; i++) {
res = res.add(mfarr[i]);
}
return res;
}
// 只能标量乘,注意先后顺序,否则解密有问题、
// 也就是只能乘明文
public MyFraction multiply(MyFraction mf) {
BigInteger res_son = cc.cipher_multiply(fson, mf.getFson());
BigInteger res_mon = fmon.multiply(mf.getFmon());
MyFraction res = new MyFraction(res_son, res_mon, cc);
return res;
}
// 取平均
public MyFraction avg(MyFraction[] mfarr) {
int len = mfarr.length;
if (0 == len) return new MyFraction();
BigInteger blen = new BigInteger(String.valueOf(len));
MyFraction[] brr = new MyFraction[len];
for (int i =0; i < len; i++) {
brr[i] = new MyFraction(mfarr[i].getFson(), mfarr[i].getFmon().multiply(blen), cc);
}
return sum(brr);
}
// 加权计算,注意这里mfa2数组,权重分数都是明文,不支持密文。
public MyFraction wavg(MyFraction[] mfa1, MyFraction[] mfa2) {
if (mfa1.length != mfa2.length) {
System.out.println("param error, the length of two arrays not equal.");
return new MyFraction();
}
MyFraction[] mfa3 = new MyFraction[mfa1.length];
for (int i=0; i < mfa1.length; i++) {
mfa3[i] = mfa1[i].multiply(mfa2[i]);
}
return sum(mfa3);
}
// String数组转 MyFraction数组
public MyFraction[] parseStringArray(String[] srr) {
int len = srr.length;
if (0 == len) return new MyFraction[0];
MyFraction[] mfarr = new MyFraction[len];
for (int i=0; i < len; i++ ) {
mfarr[i] = new MyFraction(new BigInteger(srr[i]), BigInteger.ONE, cc);
}
return mfarr;
}
@Override
public String toString() {
return "MyFraction{" +
"fson=" + fson +
", fmon=" + fmon +
", cc=" + cc +
'}';
}
public BigInteger getFson() {
return fson;
}
public void setFson(BigInteger fson) {
this.fson = fson;
}
public BigInteger getFmon() {
return fmon;
}
public void setFmon(BigInteger fmon) {
this.fmon = fmon;
}
public CipherCompute getCc() {
return cc;
}
public void setCc(CipherCompute cc) {
this.cc = cc;
}
}
2.2 密文计算类CipherCompute
public class CipherCompute {
private BigInteger nsquare;
public CipherCompute(BigInteger nsquare) {
this.nsquare = nsquare;
}
public BigInteger cipher_add(BigInteger em1, BigInteger em2) {
return em1.multiply(em2).mod(nsquare);
}
public BigInteger cipher_multiply(BigInteger em1, BigInteger m2) {
return em1.modPow(m2, nsquare);
}
}