fourq
Version:
298 lines • 10.4 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.FourQ = exports.CryptoScheme = void 0;
let FourQImported = false;
let FourQlib;
try {
FourQlib = require('../build/Release/addon');
FourQImported = true;
}
catch (e) {
console.error(e);
FourQlib = new Proxy({}, {
get: (t, p, r) => {
if (t[p] !== undefined) {
return FourQlib;
}
return t[p];
}
});
}
const crypto = require('crypto');
const isApple = (process.platform === 'darwin');
var CryptoScheme;
(function (CryptoScheme) {
CryptoScheme["ED25519"] = "ED";
CryptoScheme["FourQ"] = "4Q";
})(CryptoScheme = exports.CryptoScheme || (exports.CryptoScheme = {}));
class FourQ {
static generateKeyPair() {
return FourQ.generateFromSeed();
}
static generateFromSeed(seed) {
if (!seed) {
seed = crypto.randomBytes(32);
}
const a = toBuffer(seed);
if (a.length !== 32) {
throw new Error('Seed must be 32-byte');
}
const publicKey = FourQlib.generateFromSeed(a.buffer);
return {
isSchnorr: true,
type: CryptoScheme.FourQ,
publicKey: Buffer.from(publicKey),
secretKey: a,
};
}
static sign(message, secretKey) {
const a = toBuffer(message);
const b = toBuffer(secretKey);
if (b.length !== 32) {
throw new Error('Secret key must be 32-byte');
}
const sigData = FourQlib.sign(a.buffer, b.buffer);
return {
type: CryptoScheme.FourQ,
data: Buffer.from(sigData),
};
}
static verify(signature, message, publicKey, serversideUnknowabilityOverride = -1) {
const a = toBuffer(signature);
if (a.length !== 64) {
throw new Error('Signature key must be 64-byte');
}
const b = toBuffer(message);
let c = toBuffer(publicKey);
const ssu = (serversideUnknowabilityOverride !== -1) ?
serversideUnknowabilityOverride
: FourQ.features.serversideUnknowabilityLevel;
if (ssu >= 1) {
if (!c || c.length !== 32) {
c = Buffer.allocUnsafeSlow(1);
c[0] = 0;
}
}
return FourQlib.verify(a.buffer, b.buffer, c.buffer);
}
static ecdhGenerateKeyPair() {
return FourQ.ecdhGenerateFromSeed();
}
static ecdhGenerateFromSeed(seed) {
if (!seed) {
seed = crypto.randomBytes(32);
}
const a = toBuffer(seed);
if (a.length !== 32) {
throw new Error('Seed must be 32-byte');
}
const publicKey = FourQlib.generateFromSeedECDH(a.buffer);
return {
isDH: true,
type: CryptoScheme.FourQ,
publicKey: Buffer.from(publicKey),
secretKey: a,
};
}
static getSharedSecret(mySecret, theirPublicKey) {
const a = toBuffer(mySecret);
if (a.length !== 32) {
throw new Error('Your secret key must be 32-byte');
}
const b = toBuffer(theirPublicKey);
if (b.length !== 32) {
throw new Error('Their public key must be 32-byte');
}
const sharedSecret = FourQlib.getSharedSecretECDH(a.buffer, b.buffer);
return Buffer.from(sharedSecret);
}
static randomBytes(length = 32) {
return toBuffer(crypto.randomBytes(length));
}
static generateIdentity(seed) {
if (!seed) {
seed = crypto.randomBytes(32);
}
const secretKeyBuffer = toBuffer(seed);
const schnorrKeypair = FourQ.generateFromSeed(seed);
const ecdhKeypair = FourQ.ecdhGenerateFromSeed(seed);
return {
isIdentity: true,
type: CryptoScheme.FourQ,
publicKeySchnorr: schnorrKeypair.publicKey,
publicKeyECDH: ecdhKeypair.publicKey,
secretKey: secretKeyBuffer,
};
}
static xorCryptSHA512(cypherBuffer64Byte, content) {
const a = toBuffer(cypherBuffer64Byte);
if (a.length !== 64) {
throw new Error('Your cypherBuffer must be 64-byte');
}
const b = toBuffer(content);
const xorEncrypted = FourQlib.xorCryptSHA512(a.buffer, b.buffer);
return Buffer.from(xorEncrypted);
}
static test(verbose = true) {
const iterationsK = 10;
const iterations = iterationsK * 1000;
const iterationName = `${iterationsK}k`;
const rand = Array.from({ length: 32 }, () => Math.floor(Math.random() * 256));
const message = Buffer.from(rand);
if (isApple) {
if (verbose) {
console.log('FourQ (Generic, Slow)');
}
}
else {
if (verbose) {
console.log('FourQ (Optimized)');
}
}
const wrongKey = FourQ.generateFromSeed();
const wrongPubKey = crypto.randomBytes(32);
const keys = [];
const k1 = Date.now();
for (let i = 0; i < 25000; ++i) {
keys.push(FourQ.generateFromSeed());
}
const k2 = Date.now();
if (verbose) {
console.log(`${iterationName} Key generation, took ${k2 - k1} ms ` +
`(${(iterationsK / ((k2 - k1) / 1000)).toFixed(2)}k/s)`);
}
const sigs = [];
const s1 = Date.now();
for (let i = 0; i < iterations; ++i) {
sigs.push(FourQ.sign(message, keys[i].secretKey));
}
const s2 = Date.now();
if (verbose) {
console.log(`${iterationName} Signing, took ${s2 - s1} ms ` +
`(${(iterationsK / ((s2 - s1) / 1000)).toFixed(2)}k/s)`);
}
const v1 = Date.now();
for (let i = 0; i < iterations; ++i) {
const res = FourQ.verify(sigs[i].data, message, keys[i].publicKey);
if (!res) {
console.log('Verification Failed.', sigs[i].data, message, keys[i].publicKey);
break;
}
}
const v2 = Date.now();
if (verbose) {
console.log(`${iterationName} Valid verifications, took ${v2 - v1} ms ` +
`(${(iterationsK / ((v2 - v1) / 1000)).toFixed(2)}k/s)`);
}
const wrongSigningKeys = [];
for (let i = 0; i < iterations; ++i) {
wrongSigningKeys.push(crypto.randomBytes(32));
}
const sb1 = Date.now();
for (let i = 0; i < iterations; ++i) {
FourQ.sign(message, wrongSigningKeys[i]);
}
const sb2 = Date.now();
if (verbose) {
console.log(`${iterationName} Signing with bogus secret key, took ${sb2 - sb1} ms ` +
`(${(iterationsK / ((sb2 - sb1) / 1000)).toFixed(2)}k/s)`);
}
const iv1 = Date.now();
for (let i = 0; i < iterations; ++i) {
FourQ.verify(sigs[i].data, message, wrongKey.publicKey);
}
const iv2 = Date.now();
if (verbose) {
console.log(`${iterationName} Valid sig verification with wrong public key, took ${iv2 - iv1} ms ` +
`(${(iterationsK / ((iv2 - iv1) / 1000)).toFixed(2)}k/s)`);
}
const wrongSigs = [];
for (let i = 0; i < iterations; ++i) {
wrongSigs.push({
type: CryptoScheme.FourQ,
data: crypto.randomBytes(64),
});
}
const isv1 = Date.now();
for (let i = 0; i < iterations; ++i) {
FourQ.verify(wrongSigs[i].data, message, keys[i].publicKey);
}
const isv2 = Date.now();
if (verbose) {
console.log(`${iterationName} Bogus sig verifications with wrong public key, took ${isv2 - isv1} ms ` +
`(${(iterationsK / ((isv2 - isv1) / 1000)).toFixed(2)}k/s)`);
}
const isvp1 = Date.now();
for (let i = 0; i < iterations; ++i) {
FourQ.verify(wrongSigs[i].data, message, wrongPubKey);
}
const isvp2 = Date.now();
if (verbose) {
console.log(`${iterationName} Bogus sig Verifications with bogus public key, took ${isvp2 - isvp1} ms ` +
`(${(iterationsK / ((isvp2 - isvp1) / 1000)).toFixed(2)}k/s)`);
}
}
static memoryLeakTest(callback) {
FourQ.test(false);
const baseUsage = process.memoryUsage();
for (let i = 0; i < 10000000; ++i) {
FourQ.test(false);
memoryCompare(baseUsage, callback);
}
}
}
FourQ.imported = FourQImported;
FourQ.STRING_MODE_TEXT = 0;
FourQ.STRING_MODE_BASE64 = 1;
FourQ.STRING_MODE_HEX = 2;
FourQ.unsafeBuffers = false;
FourQ.stringMode = FourQ.STRING_MODE_BASE64;
FourQ.features = {
serversideUnknowabilityLevel: 1,
};
exports.FourQ = FourQ;
function toBuffer(a) {
if (!a) {
return null;
}
if (Buffer.isBuffer(a)) {
if (FourQ.unsafeBuffers) {
return a;
}
const b = Buffer.allocUnsafeSlow(a.length);
a.copy(b);
return b;
}
if (typeof a === 'string') {
if (FourQ.stringMode === FourQ.STRING_MODE_BASE64) {
a = Buffer.from(a, 'base64');
}
else if (FourQ.stringMode === FourQ.STRING_MODE_HEX) {
a = Buffer.from(a, 'hex');
}
else {
a = Buffer.from(a);
}
if (FourQ.unsafeBuffers) {
return a;
}
const b = Buffer.allocUnsafeSlow(a.length);
a.copy(b);
return b;
}
throw new Error('Unknown type supplied.');
}
function memoryCompare(baseUsage, callback) {
const usageNow = process.memoryUsage();
const rss = Math.floor((usageNow.rss - baseUsage.rss) / 1024 / 1024);
const heapTotal = Math.floor((usageNow.heapTotal - baseUsage.heapTotal) / 1024 / 1024);
const heapUsed = Math.floor((usageNow.heapUsed - baseUsage.heapUsed) / 1024 / 1024);
const external = Math.floor((usageNow.external - baseUsage.external) / 1024 / 1024);
console.log(`dTotal: ${heapTotal}, dUsed: ${heapUsed}, external: ${external}`);
const data = { delta: { rss, heapTotal, heapUsed, external } };
if (callback) {
callback(data);
}
return data;
}
//# sourceMappingURL=FourQ.js.map
;