-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.js
153 lines (123 loc) · 4.55 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
const crypto = require('crypto')
const paillier = require('paillier-js')
const bigInt = require('big-integer')
const rEncrypt = function ({ n, g }, message) {
const _n2 = n.pow(2)
let r
do {
r = bigInt.randBetween(2, n)
} while (r.leq(1))
return {r, cipher: g.modPow(bigInt(message), _n2).multiply(r.modPow(n, _n2)).mod(_n2)}
}
const getCoprime = (target) => {
const bits = Math.floor(Math.log2(target))
while (true) {
const lowerBound = bigInt(2).pow(bits-1).plus(1)
let possible = lowerBound.plus(bigInt.rand(bits)).or(1)
const result = bigInt(possible)
if (possible.gt(bigInt(2).pow(1024))) return result
while(target > 0) {
[possible, target] = [target, possible.mod(target)]
}
if (possible.eq(bigInt(1))) return result
}
}
const encryptWithProof = (publicKey, message, bits=512) => {
const {r: random, cipher} = rEncrypt(publicKey, message)
const om = getCoprime(publicKey.n)
const ap = om.modPow(publicKey.n, publicKey._n2)
let proof = {}
const gmk = publicKey.g.modPow(bigInt(message), publicKey._n2)
const uk = cipher.times(gmk.modInv(publicKey._n2)).mod(publicKey._n2)
if (message.toString() === message.toString()) {
proof[`a`] = ap.toString()
} else {
const zk = getCoprime(publicKey.n)
const ek = bigInt.randBetween(2, bigInt(2).pow(bits).subtract(1))
const zn = zk.modPow(publicKey.n, publicKey._n2)
const ue = uk.modPow(ek, publicKey._n2)
const ak = zn.times(ue.modInv(publicKey._n2)).mod(publicKey._n2)
proof[`a`] = ak.toString()
proof[`z`] = zk.toString()
proof[`e`] = ek.toString()
}
const hash = crypto.createHash('sha256').update(Object.values(proof).filter((_, i) => i % 3 === 0).join('')).digest('hex')
const esum = Object.values(proof).filter((_, i) => i % 3 === 2).reduce((acc, ek) => acc.plus(bigInt(ek)), bigInt(0))
const ep = bigInt(hash, 16).subtract(esum).mod(bigInt(2).pow(256))
const rep = random.modPow(ep, publicKey.n)
const zp = om.times(rep).mod(publicKey.n)
proof[`e`] = ep.toString()
proof[`z`] = zp.toString()
return {cipher: cipher.toString(), proof}
}
const verifyMessage = (publicKey, cipher, proof, validMessage) => {
const cipherBigInt = bigInt(cipher)
const hash = crypto.createHash('sha256').update(proof.a).digest('hex')
let gmk
if (publicKey.g instanceof bigInt) {
// you can safely call modPow
gmk = publicKey.g.modPow(validMessage, publicKey._n2)
} else {
// convert to bigInt first
publicKey.g = bigInt(publicKey.g);
}
gmk = publicKey.g.modPow(validMessage, publicKey._n2)
const uk = cipherBigInt.times(gmk.modInv(publicKey._n2)).mod(publicKey._n2)
const ek = bigInt(proof.e)
if (!bigInt(hash, 16).eq(ek)) {
return false
}
const zk = bigInt(proof.z)
const ak = bigInt(proof.a)
const zkn = zk.modPow(publicKey.n, publicKey._n2)
const uke = uk.modPow(ek, publicKey._n2)
const akue = ak.times(uke).mod(publicKey._n2)
return zkn.eq(akue)
}
const verifySecret = (publicKey, cipher, proof) => {
const cipherBigInt = bigInt(cipher);
const hash = crypto.createHash('sha256').update(proof.a).digest('hex');
const ek = bigInt(proof.e);
if (!bigInt(hash, 16).eq(ek)) {
return false;
}
const zk = bigInt(proof.z);
const ak = bigInt(proof.a);
const zkn = zk.modPow(publicKey.n, publicKey._n2);
const uke = cipherBigInt.modPow(ek, publicKey._n2);
const akue = ak.times(uke).mod(publicKey._n2);
return zkn.eq(akue);
}
function stringToBigInt(str) {
const buf = Buffer.from(str)
let hexString = buf.toString('hex')
if (hexString.length % 2 != 0) {
hexString = '0' + hexString // pad with a leading zero if necessary
}
return bigInt(hexString, 16)
}
module.exports = function(bits) {
const zerok = this
if(!bits) bits = 512
let {publicKey, privateKey} = paillier.generateRandomKeys(bits)
this.keypair = {publicKey, privateKey}
this.newKey = (bits) => {
if(!bits) bits = 512
let keypair = paillier.generateRandomKeys(bits)
publicKey = keypair.publicKey
privateKey = keypair.privateKey
this.keypair = {publicKey, privateKey}
}
this.proof = (message) => {
message = stringToBigInt(message.toString())
return encryptWithProof(publicKey, message, bits)
}
this.verify = (message, certificate, pubkey) => {
if(!pubkey) pubkey = publicKey
message = stringToBigInt(message.toString())
return verifyMessage(pubkey, certificate.cipher, certificate.proof, message)
}
this.verifySecret = (certificate, pubkey = publicKey) => {
return verifySecret(pubkey, certificate.cipher, certificate.proof);
}
}