232 lines
4.9 KiB
JavaScript
Executable file
232 lines
4.9 KiB
JavaScript
Executable file
/*
|
|
|
|
Cryptography functions written by Bingsheng Zhang
|
|
|
|
Uses the milagro-crypto-js library at:
|
|
https://github.com/milagro-crypto/milagro-crypto-js
|
|
|
|
*/
|
|
|
|
|
|
//Group parameter generator: returns rng object and generators g1,g2 for G1,G2 as well as order
|
|
gpGen = function(){
|
|
//init, and base generators
|
|
var ctx = new CTX("BN254CX");
|
|
|
|
var n=new ctx.BIG(0); n.rcopy(ctx.ROM_CURVE.CURVE_Order);
|
|
|
|
//get generator P for G1
|
|
P = new ctx.ECP(0);
|
|
gx = new ctx.BIG(0);
|
|
gx.rcopy(ctx.ROM_CURVE.CURVE_Gx);
|
|
if (ctx.ECP.CURVETYPE != ctx.ECP.MONTGOMERY) {
|
|
gy = new ctx.BIG(0);
|
|
gy.rcopy(ctx.ROM_CURVE.CURVE_Gy);
|
|
P.setxy(gx, gy);
|
|
} else P.setx(gx);
|
|
|
|
//get generator Q for G2
|
|
var A=new ctx.BIG(0);
|
|
var B=new ctx.BIG(0);
|
|
A.rcopy(ctx.ROM_CURVE.CURVE_Pxa);
|
|
B.rcopy(ctx.ROM_CURVE.CURVE_Pxb);
|
|
var Qx=new ctx.FP2(0); Qx.bset(A,B);
|
|
A.rcopy(ctx.ROM_CURVE.CURVE_Pya);
|
|
B.rcopy(ctx.ROM_CURVE.CURVE_Pyb);
|
|
var Qy=new ctx.FP2(0); Qy.bset(A,B);
|
|
var Q=new ctx.ECP2();
|
|
Q.setxy(Qy,Qy);
|
|
|
|
return{
|
|
n:n,
|
|
g1:P,
|
|
g2:Q
|
|
}
|
|
}
|
|
|
|
|
|
//creates ElGamal public and secret key
|
|
keyGen=function(params){
|
|
var ctx = new CTX("BN254CX");
|
|
//set rng
|
|
var RAW = [];
|
|
var d = new Date();//time for seed, not secure
|
|
var rng = new ctx.RAND();
|
|
rng.clean();
|
|
RAW[0] = d.getSeconds();
|
|
RAW[1] = d.getMinutes();
|
|
RAW[2] = d.getMilliseconds();
|
|
rng.seed(3, RAW);
|
|
|
|
//ElGamal
|
|
var sk = new ctx.BIG(0);
|
|
sk = ctx.BIG.randomnum(params.n,rng);
|
|
var pk = new ctx.ECP(0);
|
|
pk = ctx.PAIR.G1mul(params.g1,sk);
|
|
|
|
|
|
return{
|
|
PK:pk,
|
|
SK:sk
|
|
}
|
|
}
|
|
|
|
|
|
//combine multiple public key together
|
|
//the input is an array of PKs
|
|
combine=function(PKs){
|
|
var ctx = new CTX("BN254CX");
|
|
var pk=new ctx.ECP();
|
|
//copy the first pk
|
|
pk.copy(PKs[0]);
|
|
//multiple the rest PKs
|
|
for(i=1;i<PKs.length;i++){
|
|
pk.add(PKs[i]);
|
|
}
|
|
|
|
return{
|
|
PK:pk
|
|
}
|
|
}
|
|
|
|
|
|
//ElGamal encryption
|
|
encrypt=function(params,PK, m){
|
|
var ctx = new CTX("BN254CX");
|
|
//set rand
|
|
var RAW = [];
|
|
var d = new Date();//time for seed, not secure
|
|
var rng = new ctx.RAND();
|
|
rng.clean();
|
|
RAW[0] = d.getSeconds();
|
|
RAW[1] = d.getMinutes();
|
|
RAW[2] = d.getMilliseconds();
|
|
rng.seed(3, RAW);
|
|
|
|
var r=new ctx.BIG.randomnum(params.n,rng);
|
|
var M=new ctx.BIG(m);
|
|
|
|
var C1=new ctx.ECP();
|
|
C1 = ctx.PAIR.G1mul(params.g1,r);
|
|
|
|
var gM=new ctx.ECP();
|
|
gM = ctx.PAIR.G1mul(params.g1,M);
|
|
|
|
var C2=new ctx.ECP();
|
|
C2 = ctx.PAIR.G1mul(PK,r);
|
|
C2.mul(r);
|
|
C2.add(gM);
|
|
|
|
return{
|
|
C1:C1,
|
|
C2:C2
|
|
}
|
|
}
|
|
|
|
|
|
//add ciphertexts
|
|
add=function(Ciphers){
|
|
var ctx = new CTX("BN254CX");
|
|
var s1=new ctx.ECP();
|
|
var s2=new ctx.ECP();
|
|
//copy the first cipher
|
|
s1.copy(Ciphers[0].C1);
|
|
s2.copy(Ciphers[0].C2);
|
|
//multiple the rest ciphertexts
|
|
for(i=1;i<Ciphers.length;i++){
|
|
s1.add(Ciphers[i].C1);
|
|
}
|
|
//no idea why I need two loops
|
|
for(j=1;j<Ciphers.length;j++){
|
|
s2.add(Ciphers[j].C2);
|
|
}
|
|
|
|
return{
|
|
C1:s1,
|
|
C2:s2
|
|
}
|
|
}
|
|
|
|
|
|
//ElGamal decryption
|
|
decrypt=function(params,SK, C){
|
|
var ctx = new CTX("BN254CX");
|
|
var D=new ctx.ECP();
|
|
D = ctx.PAIR.G1mul(C.C1,SK);
|
|
|
|
var gM=new ctx.ECP();
|
|
gM.copy(C.C2);
|
|
gM.sub(D);
|
|
|
|
//search for message by brute force
|
|
var B;
|
|
for (j = 0; j < 1000; j++) {
|
|
//use D as temp var
|
|
B = new ctx.BIG(j);
|
|
D = ctx.PAIR.G1mul(params.g1,B);
|
|
if (D.equals(gM))
|
|
return{
|
|
M:j
|
|
}
|
|
|
|
};
|
|
|
|
|
|
return{
|
|
M: "Error"
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//ElGamal partial decryption
|
|
partDec=function(SK, C){
|
|
var ctx = new CTX("BN254CX");
|
|
var D=new ctx.ECP();
|
|
D = ctx.PAIR.G1mul(C.C1,SK);
|
|
|
|
return{
|
|
D: D
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//Tally, combine partial decryption
|
|
//Ds is the array of partial decryptions; C is the ciphertext.
|
|
tally=function(params,Ds, C){
|
|
var ctx = new CTX("BN254CX");
|
|
var D=new ctx.ECP();
|
|
D.copy(Ds[0].D);
|
|
|
|
//combine D
|
|
for(i=1;i<Ds.length;i++){
|
|
D.add(Ds[i].D);
|
|
}
|
|
|
|
|
|
var gM=new ctx.ECP();
|
|
gM.copy(C.C2);
|
|
gM.sub(D);
|
|
|
|
//search for message by brute force
|
|
var B;
|
|
for (j = 0; j < 1000; j++) {
|
|
//use D as temp var
|
|
B = new ctx.BIG(j);
|
|
D = ctx.PAIR.G1mul(params.g1,B);
|
|
if (D.equals(gM))
|
|
return{
|
|
M:j
|
|
}
|
|
|
|
};
|
|
|
|
|
|
return{
|
|
M: "Error"
|
|
}
|
|
}
|
|
|