fixed bug in prime bitlength. Fixed dts

This commit is contained in:
juanelas 2020-04-07 19:26:26 +02:00
parent 094df8068f
commit 818c3b09f3
8 changed files with 131 additions and 23 deletions

View File

@ -4,7 +4,7 @@ const path = require('path')
const pkgJson = require('../package.json') const pkgJson = require('../package.json')
const rootDir = path.join(__dirname, '..') const rootDir = path.join(__dirname, '..')
const jsFile = path.join(rootDir, pkgJson.browser) const jsFile = path.join(rootDir, pkgJson.directories.lib, 'index.browser.bundle.mod.js')
const dtsFile = path.join(rootDir, pkgJson.types) const dtsFile = path.join(rootDir, pkgJson.types)
const compilerOptions = { const compilerOptions = {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -321,7 +321,7 @@ function primeSync (bitLength, iterations = 16) {
if (bitLength < 1) { throw new RangeError(`bitLength MUST be > 0 and it is ${bitLength}`) } if (bitLength < 1) { throw new RangeError(`bitLength MUST be > 0 and it is ${bitLength}`) }
let rnd = 0n let rnd = 0n
do { do {
rnd = fromBuffer(randBytesSync(bitLength / 8, true)) rnd = fromBuffer(randBits(bitLength, true))
} while (!_isProbablyPrime(rnd, iterations)) } while (!_isProbablyPrime(rnd, iterations))
return rnd return rnd
} }
@ -383,18 +383,17 @@ function randBits (bitLength, forceLength = false) {
function randBytes (byteLength, forceLength = false) { function randBytes (byteLength, forceLength = false) {
if (byteLength < 1) { throw new RangeError(`byteLength MUST be > 0 and it is ${byteLength}`) } if (byteLength < 1) { throw new RangeError(`byteLength MUST be > 0 and it is ${byteLength}`) }
let buf
/* eslint-disable no-lone-blocks */ /* eslint-disable no-lone-blocks */
{ // browser { // browser
return new Promise(function (resolve) { return new Promise(function (resolve) {
buf = new Uint8Array(byteLength) const buf = new Uint8Array(byteLength)
self.crypto.getRandomValues(buf) self.crypto.getRandomValues(buf)
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength // If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
if (forceLength) { buf[0] = buf[0] | 128 } if (forceLength) { buf[0] = buf[0] | 128 }
resolve(buf) resolve(buf)
}) })
} }
/* eslint-disable no-lone-blocks */ /* eslint-enable no-lone-blocks */
} }
/** /**
@ -409,10 +408,12 @@ function randBytesSync (byteLength, forceLength = false) {
if (byteLength < 1) { throw new RangeError(`byteLength MUST be > 0 and it is ${byteLength}`) } if (byteLength < 1) { throw new RangeError(`byteLength MUST be > 0 and it is ${byteLength}`) }
let buf let buf
/* eslint-disable no-lone-blocks */
{ // browser { // browser
buf = new Uint8Array(byteLength) buf = new Uint8Array(byteLength)
self.crypto.getRandomValues(buf) self.crypto.getRandomValues(buf)
} }
/* eslint-enable no-lone-blocks */
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength // If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
if (forceLength) { buf[0] = buf[0] | 128 } if (forceLength) { buf[0] = buf[0] | 128 }
return buf return buf

View File

@ -113,7 +113,7 @@ function primeSync (bitLength, iterations = 16) {
if (bitLength < 1) { throw new RangeError(`bitLength MUST be > 0 and it is ${bitLength}`) } if (bitLength < 1) { throw new RangeError(`bitLength MUST be > 0 and it is ${bitLength}`) }
let rnd = 0n let rnd = 0n
do { do {
rnd = fromBuffer(randBytesSync(bitLength / 8, true)) rnd = fromBuffer(randBits(bitLength, true))
} while (!_isProbablyPrime(rnd, iterations)) } while (!_isProbablyPrime(rnd, iterations))
return rnd return rnd
} }
@ -175,18 +175,17 @@ function randBits (bitLength, forceLength = false) {
function randBytes (byteLength, forceLength = false) { function randBytes (byteLength, forceLength = false) {
if (byteLength < 1) { throw new RangeError(`byteLength MUST be > 0 and it is ${byteLength}`) } if (byteLength < 1) { throw new RangeError(`byteLength MUST be > 0 and it is ${byteLength}`) }
let buf
/* eslint-disable no-lone-blocks */ /* eslint-disable no-lone-blocks */
{ // browser { // browser
return new Promise(function (resolve) { return new Promise(function (resolve) {
buf = new Uint8Array(byteLength) const buf = new Uint8Array(byteLength)
self.crypto.getRandomValues(buf) self.crypto.getRandomValues(buf)
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength // If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
if (forceLength) { buf[0] = buf[0] | 128 } if (forceLength) { buf[0] = buf[0] | 128 }
resolve(buf) resolve(buf)
}) })
} }
/* eslint-disable no-lone-blocks */ /* eslint-enable no-lone-blocks */
} }
/** /**
@ -201,10 +200,12 @@ function randBytesSync (byteLength, forceLength = false) {
if (byteLength < 1) { throw new RangeError(`byteLength MUST be > 0 and it is ${byteLength}`) } if (byteLength < 1) { throw new RangeError(`byteLength MUST be > 0 and it is ${byteLength}`) }
let buf let buf
/* eslint-disable no-lone-blocks */
{ // browser { // browser
buf = new Uint8Array(byteLength) buf = new Uint8Array(byteLength)
self.crypto.getRandomValues(buf) self.crypto.getRandomValues(buf)
} }
/* eslint-enable no-lone-blocks */
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength // If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
if (forceLength) { buf[0] = buf[0] | 128 } if (forceLength) { buf[0] = buf[0] | 128 }
return buf return buf

View File

@ -65,7 +65,7 @@ function prime (bitLength, iterations = 16) {
if (!_useWorkers) { if (!_useWorkers) {
let rnd = 0n let rnd = 0n
do { do {
rnd = fromBuffer(randBytesSync(bitLength / 8, true)) rnd = fromBuffer(randBits(bitLength, true))
} while (!_isProbablyPrime(rnd, iterations)) } while (!_isProbablyPrime(rnd, iterations))
return new Promise((resolve) => { resolve(rnd) }) return new Promise((resolve) => { resolve(rnd) })
} }
@ -131,7 +131,7 @@ function primeSync (bitLength, iterations = 16) {
if (bitLength < 1) { throw new RangeError(`bitLength MUST be > 0 and it is ${bitLength}`) } if (bitLength < 1) { throw new RangeError(`bitLength MUST be > 0 and it is ${bitLength}`) }
let rnd = 0n let rnd = 0n
do { do {
rnd = fromBuffer(randBytesSync(bitLength / 8, true)) rnd = fromBuffer(randBits(bitLength, true))
} while (!_isProbablyPrime(rnd, iterations)) } while (!_isProbablyPrime(rnd, iterations))
return rnd return rnd
} }
@ -193,18 +193,17 @@ function randBits (bitLength, forceLength = false) {
function randBytes (byteLength, forceLength = false) { function randBytes (byteLength, forceLength = false) {
if (byteLength < 1) { throw new RangeError(`byteLength MUST be > 0 and it is ${byteLength}`) } if (byteLength < 1) { throw new RangeError(`byteLength MUST be > 0 and it is ${byteLength}`) }
let buf
/* eslint-disable no-lone-blocks */ /* eslint-disable no-lone-blocks */
{ // node { // node
const crypto = require('crypto') const crypto = require('crypto')
buf = Buffer.alloc(byteLength) const buf = Buffer.alloc(byteLength)
return crypto.randomFill(buf, function (resolve) { return crypto.randomFill(buf, function (resolve) {
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength // If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
if (forceLength) { buf[0] = buf[0] | 128 } if (forceLength) { buf[0] = buf[0] | 128 }
resolve(buf) resolve(buf)
}) })
} }
/* eslint-disable no-lone-blocks */ /* eslint-enable no-lone-blocks */
} }
/** /**
@ -219,11 +218,13 @@ function randBytesSync (byteLength, forceLength = false) {
if (byteLength < 1) { throw new RangeError(`byteLength MUST be > 0 and it is ${byteLength}`) } if (byteLength < 1) { throw new RangeError(`byteLength MUST be > 0 and it is ${byteLength}`) }
let buf let buf
/* eslint-disable no-lone-blocks */
{ // node { // node
const crypto = require('crypto') const crypto = require('crypto')
buf = Buffer.alloc(byteLength) buf = Buffer.alloc(byteLength)
crypto.randomFillSync(buf) crypto.randomFillSync(buf)
} }
/* eslint-enable no-lone-blocks */
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength // If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
if (forceLength) { buf[0] = buf[0] | 128 } if (forceLength) { buf[0] = buf[0] | 128 }
return buf return buf
@ -576,6 +577,7 @@ function _isProbablyPrime (w, iterations = 16) {
} }
let _useWorkers = true // The following is just to check whether Node.js can use workers let _useWorkers = true // The following is just to check whether Node.js can use workers
/* eslint-disable no-lone-blocks */
{ // Node.js { // Node.js
_useWorkers = (function _workers () { _useWorkers = (function _workers () {
try { try {
@ -590,6 +592,7 @@ This node version doesn't support worker_threads. You should enable them in orde
} }
})() })()
} }
/* eslint-enable no-lone-blocks */
if (_useWorkers) { // node.js with support for workers if (_useWorkers) { // node.js with support for workers
const { parentPort, isMainThread } = require('worker_threads') const { parentPort, isMainThread } = require('worker_threads')

View File

@ -81,7 +81,7 @@ export function prime (bitLength, iterations = 16) {
if (!process.browser && !_useWorkers) { if (!process.browser && !_useWorkers) {
let rnd = 0n let rnd = 0n
do { do {
rnd = fromBuffer(randBytesSync(bitLength / 8, true)) rnd = fromBuffer(randBits(bitLength, true))
} while (!_isProbablyPrime(rnd, iterations)) } while (!_isProbablyPrime(rnd, iterations))
return new Promise((resolve) => { resolve(rnd) }) return new Promise((resolve) => { resolve(rnd) })
} }
@ -154,7 +154,7 @@ export function primeSync (bitLength, iterations = 16) {
if (bitLength < 1) { throw new RangeError(`bitLength MUST be > 0 and it is ${bitLength}`) } if (bitLength < 1) { throw new RangeError(`bitLength MUST be > 0 and it is ${bitLength}`) }
let rnd = 0n let rnd = 0n
do { do {
rnd = fromBuffer(randBytesSync(bitLength / 8, true)) rnd = fromBuffer(randBits(bitLength, true))
} while (!_isProbablyPrime(rnd, iterations)) } while (!_isProbablyPrime(rnd, iterations))
return rnd return rnd
} }
@ -216,11 +216,10 @@ export function randBits (bitLength, forceLength = false) {
export function randBytes (byteLength, forceLength = false) { export function randBytes (byteLength, forceLength = false) {
if (byteLength < 1) { throw new RangeError(`byteLength MUST be > 0 and it is ${byteLength}`) } if (byteLength < 1) { throw new RangeError(`byteLength MUST be > 0 and it is ${byteLength}`) }
let buf
/* eslint-disable no-lone-blocks */ /* eslint-disable no-lone-blocks */
if (!process.browser) { // node if (!process.browser) { // node
const crypto = require('crypto') const crypto = require('crypto')
buf = Buffer.alloc(byteLength) const buf = Buffer.alloc(byteLength)
return crypto.randomFill(buf, function (resolve) { return crypto.randomFill(buf, function (resolve) {
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength // If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
if (forceLength) { buf[0] = buf[0] | 128 } if (forceLength) { buf[0] = buf[0] | 128 }
@ -228,14 +227,14 @@ export function randBytes (byteLength, forceLength = false) {
}) })
} else { // browser } else { // browser
return new Promise(function (resolve) { return new Promise(function (resolve) {
buf = new Uint8Array(byteLength) const buf = new Uint8Array(byteLength)
self.crypto.getRandomValues(buf) self.crypto.getRandomValues(buf)
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength // If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
if (forceLength) { buf[0] = buf[0] | 128 } if (forceLength) { buf[0] = buf[0] | 128 }
resolve(buf) resolve(buf)
}) })
} }
/* eslint-disable no-lone-blocks */ /* eslint-enable no-lone-blocks */
} }
/** /**
@ -250,6 +249,7 @@ export function randBytesSync (byteLength, forceLength = false) {
if (byteLength < 1) { throw new RangeError(`byteLength MUST be > 0 and it is ${byteLength}`) } if (byteLength < 1) { throw new RangeError(`byteLength MUST be > 0 and it is ${byteLength}`) }
let buf let buf
/* eslint-disable no-lone-blocks */
if (!process.browser) { // node if (!process.browser) { // node
const crypto = require('crypto') const crypto = require('crypto')
buf = Buffer.alloc(byteLength) buf = Buffer.alloc(byteLength)
@ -258,6 +258,7 @@ export function randBytesSync (byteLength, forceLength = false) {
buf = new Uint8Array(byteLength) buf = new Uint8Array(byteLength)
self.crypto.getRandomValues(buf) self.crypto.getRandomValues(buf)
} }
/* eslint-enable no-lone-blocks */
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength // If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
if (forceLength) { buf[0] = buf[0] | 128 } if (forceLength) { buf[0] = buf[0] | 128 }
return buf return buf
@ -635,6 +636,7 @@ function _isProbablyPrime (w, iterations = 16) {
} }
let _useWorkers = true // The following is just to check whether Node.js can use workers let _useWorkers = true // The following is just to check whether Node.js can use workers
/* eslint-disable no-lone-blocks */
if (!process.browser) { // Node.js if (!process.browser) { // Node.js
_useWorkers = (function _workers () { _useWorkers = (function _workers () {
try { try {
@ -649,6 +651,7 @@ This node version doesn't support worker_threads. You should enable them in orde
} }
})() })()
} }
/* eslint-enable no-lone-blocks */
if (!process.browser && _useWorkers) { // node.js with support for workers if (!process.browser && _useWorkers) { // node.js with support for workers
const { parentPort, isMainThread } = require('worker_threads') const { parentPort, isMainThread } = require('worker_threads')

102
types/index.d.ts vendored
View File

@ -1,3 +1,51 @@
/**
* A triple (g, x, y), such that ax + by = g = gcd(a, b).
*/
export type egcdReturn = {
g: bigint;
x: bigint;
y: bigint;
};
/**
* Absolute value. abs(a)==a if a>=0. abs(a)==-a if a<0
*
* @param {number|bigint} a
*
* @returns {bigint} the absolute value of a
*/
export function abs(a: number | bigint): bigint;
/**
* Returns the bitlength of a number
*
* @param {number|bigint} a
* @returns {number} - the bit length
*/
export function bitLength(a: number | bigint): number;
/**
* @typedef {Object} egcdReturn A triple (g, x, y), such that ax + by = g = gcd(a, b).
* @property {bigint} g
* @property {bigint} x
* @property {bigint} y
*/
/**
* An iterative implementation of the extended euclidean algorithm or extended greatest common divisor algorithm.
* Take positive integers a, b as input, and return a triple (g, x, y), such that ax + by = g = gcd(a, b).
*
* @param {number|bigint} a
* @param {number|bigint} b
*
* @returns {egcdReturn} A triple (g, x, y), such that ax + by = g = gcd(a, b).
*/
export function eGcd(a: number | bigint, b: number | bigint): egcdReturn;
/**
* Greatest-common divisor of two integers based on the iterative binary algorithm.
*
* @param {number|bigint} a
* @param {number|bigint} b
*
* @returns {bigint} The greatest common divisor of a and b
*/
export function gcd(a: number | bigint, b: number | bigint): bigint;
/** /**
* The test first tries if any of the first 250 small primes are a factor of the input number and then passes several * The test first tries if any of the first 250 small primes are a factor of the input number and then passes several
* iterations of Miller-Rabin Probabilistic Primality Test (FIPS 186-4 C.3.1) * iterations of Miller-Rabin Probabilistic Primality Test (FIPS 186-4 C.3.1)
@ -8,6 +56,51 @@
* @return {Promise<boolean>} A promise that resolves to a boolean that is either true (a probably prime number) or false (definitely composite) * @return {Promise<boolean>} A promise that resolves to a boolean that is either true (a probably prime number) or false (definitely composite)
*/ */
export function isProbablyPrime(w: number | bigint, iterations?: number): Promise<boolean>; export function isProbablyPrime(w: number | bigint, iterations?: number): Promise<boolean>;
/**
* The least common multiple computed as abs(a*b)/gcd(a,b)
* @param {number|bigint} a
* @param {number|bigint} b
*
* @returns {bigint} The least common multiple of a and b
*/
export function lcm(a: number | bigint, b: number | bigint): bigint;
/**
* Maximum. max(a,b)==a if a>=b. max(a,b)==b if a<=b
*
* @param {number|bigint} a
* @param {number|bigint} b
*
* @returns {bigint} maximum of numbers a and b
*/
export function max(a: number | bigint, b: number | bigint): bigint;
/**
* Minimum. min(a,b)==b if a>=b. min(a,b)==a if a<=b
*
* @param {number|bigint} a
* @param {number|bigint} b
*
* @returns {bigint} minimum of numbers a and b
*/
export function min(a: number | bigint, b: number | bigint): bigint;
/**
* Modular inverse.
*
* @param {number|bigint} a The number to find an inverse for
* @param {number|bigint} n The modulo
*
* @returns {bigint} the inverse modulo n or NaN if it does not exist
*/
export function modInv(a: number | bigint, n: number | bigint): bigint;
/**
* Modular exponentiation b**e mod n. Currently using the right-to-left binary method
*
* @param {number|bigint} b base
* @param {number|bigint} e exponent
* @param {number|bigint} n modulo
*
* @returns {bigint} b**e mod n
*/
export function modPow(b: number | bigint, e: number | bigint, n: number | bigint): bigint;
/** /**
* A probably-prime (Miller-Rabin), cryptographically-secure, random-number generator. * A probably-prime (Miller-Rabin), cryptographically-secure, random-number generator.
* The browser version uses web workers to parallelise prime look up. Therefore, it does not lock the UI * The browser version uses web workers to parallelise prime look up. Therefore, it does not lock the UI
@ -66,4 +159,11 @@ export function randBytes(byteLength: number, forceLength?: boolean): Promise<Ui
* @returns {Buffer | Uint8Array} A Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bytes * @returns {Buffer | Uint8Array} A Buffer/UInt8Array (Node.js/Browser) filled with cryptographically secure random bytes
*/ */
export function randBytesSync(byteLength: number, forceLength?: boolean): Uint8Array | Buffer; export function randBytesSync(byteLength: number, forceLength?: boolean): Uint8Array | Buffer;
export { abs, bitLength, eGcd, gcd, lcm, max, min, modInv, modPow, toZn } from "bigint-mod-arith"; /**
* Finds the smallest positive element that is congruent to a in modulo n
* @param {number|bigint} a An integer
* @param {number|bigint} n The modulo
*
* @returns {bigint} The smallest positive representation of a in modulo n
*/
export function toZn(a: number | bigint, n: number | bigint): bigint;