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>
|
<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><p>Minimum. min(a,b)==b if a>=b. min(a,b)==a if a<=b</p>
|
||||||
</dd>
|
</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><p>Modular inverse.</p>
|
||||||
</dd>
|
</dd>
|
||||||
<dt><a href="#modPow">modPow(b, e, n)</a> ⇒ <code>bigint</code></dt>
|
<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
|
**Kind**: global function
|
||||||
**Returns**: [<code>egcdReturn</code>](#egcdReturn) - A triple (g, x, y), such that ax + by = g = gcd(a, b).
|
**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 |
|
| 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>
|
<a name="modInv"></a>
|
||||||
|
|
||||||
### modInv(a, n) ⇒ <code>bigint</code> \| <code>NaN</code>
|
### modInv(a, n) ⇒ <code>bigint</code>
|
||||||
Modular inverse.
|
Modular inverse.
|
||||||
|
|
||||||
**Kind**: global function
|
**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 |
|
| 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} a
|
||||||
* @param {number|bigint} b
|
* @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).
|
* @returns {egcdReturn} A triple (g, x, y), such that ax + by = g = gcd(a, b).
|
||||||
*/
|
*/
|
||||||
function eGcd (a, b) {
|
function eGcd (a, b) {
|
||||||
|
@ -152,18 +154,16 @@ function min (a, b) {
|
||||||
* @param {number|bigint} a The number to find an inverse for
|
* @param {number|bigint} a The number to find an inverse for
|
||||||
* @param {number|bigint} n The modulo
|
* @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) {
|
function modInv (a, n) {
|
||||||
try {
|
const egcd = eGcd(toZn(a, n), n)
|
||||||
const egcd = eGcd(toZn(a, n), n)
|
if (egcd.g !== 1n) {
|
||||||
if (egcd.g !== 1n) {
|
throw new RangeError(`${a.toString()} does not have inverse modulo ${n.toString()}`) // modular inverse does not exist
|
||||||
return NaN // modular inverse does not exist
|
} else {
|
||||||
} else {
|
return toZn(egcd.x, n)
|
||||||
return toZn(egcd.x, n)
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
return NaN
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,7 +178,7 @@ function modInv (a, n) {
|
||||||
*/
|
*/
|
||||||
function modPow (b, e, n) {
|
function modPow (b, e, n) {
|
||||||
n = BigInt(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)
|
b = toZn(b, n)
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,8 @@ function bitLength (a) {
|
||||||
* @param {number|bigint} a
|
* @param {number|bigint} a
|
||||||
* @param {number|bigint} b
|
* @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).
|
* @returns {egcdReturn} A triple (g, x, y), such that ax + by = g = gcd(a, b).
|
||||||
*/
|
*/
|
||||||
function eGcd (a, b) {
|
function eGcd (a, b) {
|
||||||
|
@ -154,18 +156,16 @@ function min (a, b) {
|
||||||
* @param {number|bigint} a The number to find an inverse for
|
* @param {number|bigint} a The number to find an inverse for
|
||||||
* @param {number|bigint} n The modulo
|
* @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) {
|
function modInv (a, n) {
|
||||||
try {
|
const egcd = eGcd(toZn(a, n), n)
|
||||||
const egcd = eGcd(toZn(a, n), n)
|
if (egcd.g !== 1n) {
|
||||||
if (egcd.g !== 1n) {
|
throw new RangeError(`${a.toString()} does not have inverse modulo ${n.toString()}`) // modular inverse does not exist
|
||||||
return NaN // modular inverse does not exist
|
} else {
|
||||||
} else {
|
return toZn(egcd.x, n)
|
||||||
return toZn(egcd.x, n)
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
return NaN
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,7 +180,7 @@ function modInv (a, n) {
|
||||||
*/
|
*/
|
||||||
function modPow (b, e, n) {
|
function modPow (b, e, n) {
|
||||||
n = BigInt(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)
|
b = toZn(b, n)
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,8 @@ export function bitLength (a) {
|
||||||
* @param {number|bigint} a
|
* @param {number|bigint} a
|
||||||
* @param {number|bigint} b
|
* @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).
|
* @returns {egcdReturn} A triple (g, x, y), such that ax + by = g = gcd(a, b).
|
||||||
*/
|
*/
|
||||||
export function eGcd (a, b) {
|
export function eGcd (a, b) {
|
||||||
|
@ -152,18 +154,16 @@ export function min (a, b) {
|
||||||
* @param {number|bigint} a The number to find an inverse for
|
* @param {number|bigint} a The number to find an inverse for
|
||||||
* @param {number|bigint} n The modulo
|
* @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) {
|
export function modInv (a, n) {
|
||||||
try {
|
const egcd = eGcd(toZn(a, n), n)
|
||||||
const egcd = eGcd(toZn(a, n), n)
|
if (egcd.g !== 1n) {
|
||||||
if (egcd.g !== 1n) {
|
throw new RangeError(`${a.toString()} does not have inverse modulo ${n.toString()}`) // modular inverse does not exist
|
||||||
return NaN // modular inverse does not exist
|
} else {
|
||||||
} else {
|
return toZn(egcd.x, n)
|
||||||
return toZn(egcd.x, n)
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
return NaN
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,7 +178,7 @@ export function modInv (a, n) {
|
||||||
*/
|
*/
|
||||||
export function modPow (b, e, n) {
|
export function modPow (b, e, n) {
|
||||||
n = BigInt(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)
|
b = toZn(b, n)
|
||||||
|
|
||||||
|
|
|
@ -21,21 +21,20 @@ const inputs = [
|
||||||
a: BigInt(-2),
|
a: BigInt(-2),
|
||||||
n: BigInt(5),
|
n: BigInt(5),
|
||||||
modInv: BigInt(2)
|
modInv: BigInt(2)
|
||||||
},
|
}]
|
||||||
|
|
||||||
|
const invalidInputs = [
|
||||||
{
|
{
|
||||||
a: BigInt(2),
|
a: BigInt(2),
|
||||||
n: BigInt(4),
|
n: BigInt(4)
|
||||||
modInv: NaN
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
a: BigInt(0),
|
a: BigInt(0),
|
||||||
n: BigInt(0),
|
n: BigInt(0)
|
||||||
modInv: NaN
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
a: BigInt(0),
|
a: BigInt(0),
|
||||||
n: BigInt(37),
|
n: BigInt(37)
|
||||||
modInv: NaN
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -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 = [
|
const inputs = [
|
||||||
{
|
|
||||||
a: BigInt(4),
|
|
||||||
b: BigInt(-1),
|
|
||||||
n: BigInt(0),
|
|
||||||
modPow: NaN
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
a: BigInt(4),
|
a: BigInt(4),
|
||||||
b: BigInt(-1),
|
b: BigInt(-1),
|
||||||
|
@ -42,6 +36,13 @@ const inputs = [
|
||||||
b: BigInt(3),
|
b: BigInt(3),
|
||||||
n: BigInt(25),
|
n: BigInt(25),
|
||||||
modPow: BigInt(2)
|
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 () {
|
describe('Time profiling', function () {
|
||||||
let iterations = 500
|
let iterations = 500
|
||||||
it(`just testing ${iterations} iterations of a big modular exponentiation (1024 bits)`, function () {
|
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} a
|
||||||
* @param {number|bigint} b
|
* @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).
|
* @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;
|
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} a The number to find an inverse for
|
||||||
* @param {number|bigint} n The modulo
|
* @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
|
* Modular exponentiation b**e mod n. Currently using the right-to-left binary method
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue