Throw RangeError instead of returning NaN (which is not a bigint)
This commit is contained in:
parent
9c4eaf2830
commit
a2da4b0c4b
14
README.md
14
README.md
|
@ -148,7 +148,7 @@ iterations of Miller-Rabin Probabilistic Primality Test (FIPS 186-4 C.3.1)</p>
|
|||
<dt><a href="#min">min(a, b)</a> ⇒ <code>bigint</code></dt>
|
||||
<dd><p>Minimum. min(a,b)==b if a>=b. min(a,b)==a if a<=b</p>
|
||||
</dd>
|
||||
<dt><a href="#modInv">modInv(a, n)</a> ⇒ <code>bigint</code> | <code>NaN</code></dt>
|
||||
<dt><a href="#modInv">modInv(a, n)</a> ⇒ <code>bigint</code></dt>
|
||||
<dd><p>Modular inverse.</p>
|
||||
</dd>
|
||||
<dt><a href="#modPow">modPow(b, e, n)</a> ⇒ <code>bigint</code></dt>
|
||||
|
@ -225,6 +225,10 @@ Take positive integers a, b as input, and return a triple (g, x, y), such that a
|
|||
|
||||
**Kind**: global function
|
||||
**Returns**: [<code>egcdReturn</code>](#egcdReturn) - A triple (g, x, y), such that ax + by = g = gcd(a, b).
|
||||
**Throws**:
|
||||
|
||||
- <code>RangeError</code> a and b MUST be > 0
|
||||
|
||||
|
||||
| Param | Type |
|
||||
| --- | --- |
|
||||
|
@ -318,11 +322,15 @@ Minimum. min(a,b)==b if a>=b. min(a,b)==a if a<=b
|
|||
|
||||
<a name="modInv"></a>
|
||||
|
||||
### modInv(a, n) ⇒ <code>bigint</code> \| <code>NaN</code>
|
||||
### modInv(a, n) ⇒ <code>bigint</code>
|
||||
Modular inverse.
|
||||
|
||||
**Kind**: global function
|
||||
**Returns**: <code>bigint</code> \| <code>NaN</code> - the inverse modulo n or NaN if it does not exist
|
||||
**Returns**: <code>bigint</code> - the inverse modulo n
|
||||
**Throws**:
|
||||
|
||||
- <code>RangeError</code> a does not have inverse modulo n
|
||||
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -39,6 +39,8 @@ function bitLength (a) {
|
|||
* @param {number|bigint} a
|
||||
* @param {number|bigint} b
|
||||
*
|
||||
* @throws {RangeError} a and b MUST be > 0
|
||||
*
|
||||
* @returns {egcdReturn} A triple (g, x, y), such that ax + by = g = gcd(a, b).
|
||||
*/
|
||||
function eGcd (a, b) {
|
||||
|
@ -152,19 +154,17 @@ function min (a, b) {
|
|||
* @param {number|bigint} a The number to find an inverse for
|
||||
* @param {number|bigint} n The modulo
|
||||
*
|
||||
* @returns {bigint|NaN} the inverse modulo n or NaN if it does not exist
|
||||
* @throws {RangeError} a does not have inverse modulo n
|
||||
*
|
||||
* @returns {bigint} the inverse modulo n
|
||||
*/
|
||||
function modInv (a, n) {
|
||||
try {
|
||||
const egcd = eGcd(toZn(a, n), n)
|
||||
if (egcd.g !== 1n) {
|
||||
return NaN // modular inverse does not exist
|
||||
throw new RangeError(`${a.toString()} does not have inverse modulo ${n.toString()}`) // modular inverse does not exist
|
||||
} else {
|
||||
return toZn(egcd.x, n)
|
||||
}
|
||||
} catch (error) {
|
||||
return NaN
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -178,7 +178,7 @@ function modInv (a, n) {
|
|||
*/
|
||||
function modPow (b, e, n) {
|
||||
n = BigInt(n)
|
||||
if (n === 0n) { return NaN } else if (n === 1n) { return BigInt(0) }
|
||||
if (n === 0n) { throw new RangeError('n must be > 0') } else if (n === 1n) { return BigInt(0) }
|
||||
|
||||
b = toZn(b, n)
|
||||
|
||||
|
|
|
@ -41,6 +41,8 @@ function bitLength (a) {
|
|||
* @param {number|bigint} a
|
||||
* @param {number|bigint} b
|
||||
*
|
||||
* @throws {RangeError} a and b MUST be > 0
|
||||
*
|
||||
* @returns {egcdReturn} A triple (g, x, y), such that ax + by = g = gcd(a, b).
|
||||
*/
|
||||
function eGcd (a, b) {
|
||||
|
@ -154,19 +156,17 @@ function min (a, b) {
|
|||
* @param {number|bigint} a The number to find an inverse for
|
||||
* @param {number|bigint} n The modulo
|
||||
*
|
||||
* @returns {bigint|NaN} the inverse modulo n or NaN if it does not exist
|
||||
* @throws {RangeError} a does not have inverse modulo n
|
||||
*
|
||||
* @returns {bigint} the inverse modulo n
|
||||
*/
|
||||
function modInv (a, n) {
|
||||
try {
|
||||
const egcd = eGcd(toZn(a, n), n)
|
||||
if (egcd.g !== 1n) {
|
||||
return NaN // modular inverse does not exist
|
||||
throw new RangeError(`${a.toString()} does not have inverse modulo ${n.toString()}`) // modular inverse does not exist
|
||||
} else {
|
||||
return toZn(egcd.x, n)
|
||||
}
|
||||
} catch (error) {
|
||||
return NaN
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -180,7 +180,7 @@ function modInv (a, n) {
|
|||
*/
|
||||
function modPow (b, e, n) {
|
||||
n = BigInt(n)
|
||||
if (n === 0n) { return NaN } else if (n === 1n) { return BigInt(0) }
|
||||
if (n === 0n) { throw new RangeError('n must be > 0') } else if (n === 1n) { return BigInt(0) }
|
||||
|
||||
b = toZn(b, n)
|
||||
|
||||
|
|
|
@ -39,6 +39,8 @@ export function bitLength (a) {
|
|||
* @param {number|bigint} a
|
||||
* @param {number|bigint} b
|
||||
*
|
||||
* @throws {RangeError} a and b MUST be > 0
|
||||
*
|
||||
* @returns {egcdReturn} A triple (g, x, y), such that ax + by = g = gcd(a, b).
|
||||
*/
|
||||
export function eGcd (a, b) {
|
||||
|
@ -152,19 +154,17 @@ export function min (a, b) {
|
|||
* @param {number|bigint} a The number to find an inverse for
|
||||
* @param {number|bigint} n The modulo
|
||||
*
|
||||
* @returns {bigint|NaN} the inverse modulo n or NaN if it does not exist
|
||||
* @throws {RangeError} a does not have inverse modulo n
|
||||
*
|
||||
* @returns {bigint} the inverse modulo n
|
||||
*/
|
||||
export function modInv (a, n) {
|
||||
try {
|
||||
const egcd = eGcd(toZn(a, n), n)
|
||||
if (egcd.g !== 1n) {
|
||||
return NaN // modular inverse does not exist
|
||||
throw new RangeError(`${a.toString()} does not have inverse modulo ${n.toString()}`) // modular inverse does not exist
|
||||
} else {
|
||||
return toZn(egcd.x, n)
|
||||
}
|
||||
} catch (error) {
|
||||
return NaN
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -178,7 +178,7 @@ export function modInv (a, n) {
|
|||
*/
|
||||
export function modPow (b, e, n) {
|
||||
n = BigInt(n)
|
||||
if (n === 0n) { return NaN } else if (n === 1n) { return BigInt(0) }
|
||||
if (n === 0n) { throw new RangeError('n must be > 0') } else if (n === 1n) { return BigInt(0) }
|
||||
|
||||
b = toZn(b, n)
|
||||
|
||||
|
|
|
@ -21,21 +21,20 @@ const inputs = [
|
|||
a: BigInt(-2),
|
||||
n: BigInt(5),
|
||||
modInv: BigInt(2)
|
||||
},
|
||||
}]
|
||||
|
||||
const invalidInputs = [
|
||||
{
|
||||
a: BigInt(2),
|
||||
n: BigInt(4),
|
||||
modInv: NaN
|
||||
n: BigInt(4)
|
||||
},
|
||||
{
|
||||
a: BigInt(0),
|
||||
n: BigInt(0),
|
||||
modInv: NaN
|
||||
n: BigInt(0)
|
||||
},
|
||||
{
|
||||
a: BigInt(0),
|
||||
n: BigInt(37),
|
||||
modInv: NaN
|
||||
n: BigInt(37)
|
||||
}
|
||||
]
|
||||
|
||||
|
@ -49,4 +48,16 @@ describe('modInv', function () {
|
|||
})
|
||||
})
|
||||
}
|
||||
for (const input of invalidInputs) {
|
||||
describe(`modInv(${input.a}, ${input.n})`, function () {
|
||||
it('should throw RangeError', function () {
|
||||
try {
|
||||
_pkg.modInv(input.a, input.n)
|
||||
throw new Error('should have failed')
|
||||
} catch (err) {
|
||||
chai.expect(err).to.be.instanceOf(RangeError)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
|
|
|
@ -7,12 +7,6 @@ const chai = require('chai')
|
|||
// <--
|
||||
|
||||
const inputs = [
|
||||
{
|
||||
a: BigInt(4),
|
||||
b: BigInt(-1),
|
||||
n: BigInt(0),
|
||||
modPow: NaN
|
||||
},
|
||||
{
|
||||
a: BigInt(4),
|
||||
b: BigInt(-1),
|
||||
|
@ -42,6 +36,13 @@ const inputs = [
|
|||
b: BigInt(3),
|
||||
n: BigInt(25),
|
||||
modPow: BigInt(2)
|
||||
}]
|
||||
|
||||
const invalidInputs = [
|
||||
{
|
||||
a: BigInt(4),
|
||||
b: BigInt(-1),
|
||||
n: BigInt(0)
|
||||
}
|
||||
]
|
||||
|
||||
|
@ -55,6 +56,18 @@ describe('modPow', function () {
|
|||
})
|
||||
})
|
||||
}
|
||||
for (const input of invalidInputs) {
|
||||
describe(`modPow(${input.a}, ${input.b}, ${input.n})`, function () {
|
||||
it('should throw RangeError', function () {
|
||||
try {
|
||||
_pkg.modPow(input.a, input.b, input.n)
|
||||
throw new Error('should have failed')
|
||||
} catch (err) {
|
||||
chai.expect(err).to.be.instanceOf(RangeError)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
describe('Time profiling', function () {
|
||||
let iterations = 500
|
||||
it(`just testing ${iterations} iterations of a big modular exponentiation (1024 bits)`, function () {
|
||||
|
|
|
@ -34,6 +34,8 @@ export function bitLength(a: number | bigint): number;
|
|||
* @param {number|bigint} a
|
||||
* @param {number|bigint} b
|
||||
*
|
||||
* @throws {RangeError} a and b MUST be > 0
|
||||
*
|
||||
* @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;
|
||||
|
@ -91,9 +93,11 @@ export function min(a: number | bigint, b: number | bigint): bigint;
|
|||
* @param {number|bigint} a The number to find an inverse for
|
||||
* @param {number|bigint} n The modulo
|
||||
*
|
||||
* @returns {bigint|NaN} the inverse modulo n or NaN if it does not exist
|
||||
* @throws {RangeError} a does not have inverse modulo n
|
||||
*
|
||||
* @returns {bigint} the inverse modulo n
|
||||
*/
|
||||
export function modInv(a: number | bigint, n: number | bigint): number | bigint;
|
||||
export function modInv(a: number | bigint, n: number | bigint): bigint;
|
||||
/**
|
||||
* Modular exponentiation b**e mod n. Currently using the right-to-left binary method
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue