@beraji/wallet-sdk
Version:
Beraji: Distributed Secret Sharing.
119 lines • 5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExtendedElGamal = exports.ElGamal = exports.parity = exports.xor = void 0;
const utils_1 = require("@noble/hashes/utils");
const edtss_1 = require("./edtss");
const xor = (a, b) => {
if (a.length !== b.length)
throw new Error('Invalid buffer length');
const c = new Uint8Array(a.length);
for (let i = 0; i < a.length; i++)
c[i] = a[i] ^ b[i];
return c;
};
exports.xor = xor;
const parity = (a) => {
let b = a.reduce((x, y) => x ^ y, 0);
b = b ^ (b >> 1);
b = b ^ (b >> 2);
b = b ^ (b >> 4);
return b & 1;
};
exports.parity = parity;
class ElGamal {
constructor() {
this.encrypt = (msg, pubkey) => {
if (msg.length != ElGamal.plainTextLength)
throw new Error(`Invalid block length. It must be 32 bytes instead of ${msg.length} bytes.`);
const r = edtss_1.EdCurve.ff.rand();
const R = edtss_1.EdCurve.baseMul(r);
const m = (0, exports.xor)(msg, R);
if ((0, utils_1.bytesToHex)(m) !== (0, utils_1.bytesToHex)(edtss_1.EdCurve.ff.norm(m)))
return this.encrypt(msg, pubkey);
const s = edtss_1.EdCurve.mulScalar(pubkey, r);
const c = edtss_1.EdCurve.ff.add(m, s);
return new Uint8Array([...R, ...c]);
};
this.decrypt = (cipher, privkey) => {
if (privkey.length !== ElGamal.privateKeyLength)
throw new Error('Invalid private key length');
if (cipher.length !== ElGamal.cipherTextLength)
throw new Error('Invalid cipher text length');
const priv = edtss_1.EdCurve.getDerivedKey(privkey);
const R = cipher.subarray(0, 32);
const c = cipher.subarray(32, ElGamal.cipherTextLength);
const s = edtss_1.EdCurve.mulScalar(R, priv);
const m = edtss_1.EdCurve.ff.sub(c, s);
const msg = (0, exports.xor)(m, R);
return msg;
};
}
}
exports.ElGamal = ElGamal;
ElGamal.publicKeyLength = 32;
ElGamal.privateKeyLength = 32;
ElGamal.plainTextLength = 32;
ElGamal.cipherTextLength = 64;
class ExtendedElGamal {
constructor() {
this._enc = (msg, pubkey) => {
const length = msg.length;
if (length > ExtendedElGamal.plainTextLength)
throw new Error(`Invalid block length. It must be 30 bytes instead of ${length} bytes.`);
const par = (0, exports.parity)(msg);
const padding = (0, utils_1.randomBytes)(ExtendedElGamal.plainTextLength - length);
const m = new Uint8Array([par, length, ...padding, ...msg]);
const r = edtss_1.EdCurve.ff.rand();
const R = edtss_1.EdCurve.baseMul(r);
const s = edtss_1.EdCurve.mulScalar(pubkey, r);
const c = (0, exports.xor)(m, s);
return new Uint8Array([...R, ...c]);
};
this._dec = (cipher, privkey) => {
if (privkey.length !== ExtendedElGamal.privateKeyLength)
throw new Error('Invalid private key length');
if (cipher.length % ExtendedElGamal.cipherTextLength !== 0)
throw new Error('Invalid cipher text length');
const R = cipher.subarray(0, 32);
const c = cipher.subarray(32, ExtendedElGamal.cipherTextLength);
const s = edtss_1.EdCurve.mulScalar(R, privkey);
const p = (0, exports.xor)(c, s);
const par = p[0];
const length = p[1];
const msg = p.subarray(ExtendedElGamal.blockLength - length, ExtendedElGamal.blockLength);
if (par !== (0, exports.parity)(msg))
throw new Error('Incorrect cipher text');
return msg;
};
this.encrypt = (m, pubkey) => {
let c = [];
let offset = 0;
while (offset < m.length) {
c.push([
...this._enc(m.subarray(offset, offset + ExtendedElGamal.plainTextLength), pubkey),
]);
offset = offset + ExtendedElGamal.plainTextLength;
}
return new Uint8Array(c.flat());
};
this.decrypt = (c, privkey) => {
const priv = edtss_1.EdCurve.getDerivedKey(privkey);
let m = [];
let offset = 0;
while (offset < c.length) {
m.push([
...this._dec(c.subarray(offset, offset + ExtendedElGamal.cipherTextLength), priv),
]);
offset = offset + ExtendedElGamal.cipherTextLength;
}
return new Uint8Array(m.flat());
};
}
}
exports.ExtendedElGamal = ExtendedElGamal;
ExtendedElGamal.publicKeyLength = 32;
ExtendedElGamal.privateKeyLength = 32;
ExtendedElGamal.blockLength = 32;
ExtendedElGamal.plainTextLength = 30;
ExtendedElGamal.cipherTextLength = 64;
//# sourceMappingURL=elgamal.js.map