UNPKG

fourq

Version:

298 lines 10.4 kB
"use strict"; 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