-
-
Notifications
You must be signed in to change notification settings - Fork 5.8k
Expand file tree
/
Copy pathBabyStepGiantStep.js
More file actions
68 lines (60 loc) · 1.77 KB
/
Copy pathBabyStepGiantStep.js
File metadata and controls
68 lines (60 loc) · 1.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/**
* Baby-step giant-step discrete logarithm modulo a prime.
* https://en.wikipedia.org/wiki/Baby-step_giant-step
*
* Solves base^x ≡ target (mod modulus) for the smallest non-negative x.
*/
/**
* @param {number} base
* @param {number} target
* @param {number} modulus prime (or modulus where base is invertible)
* @returns {number} smallest non-negative discrete log
*/
export function babyStepGiantStep(base, target, modulus) {
if (
typeof base !== 'number' ||
typeof target !== 'number' ||
typeof modulus !== 'number' ||
!Number.isInteger(base) ||
!Number.isInteger(target) ||
!Number.isInteger(modulus)
) {
throw new TypeError('Arguments must be integers')
}
if (modulus <= 1) throw new RangeError('modulus must be > 1')
base = ((base % modulus) + modulus) % modulus
target = ((target % modulus) + modulus) % modulus
if (target === 1) return 0
if (base === 0) {
if (target === 0) return 1
throw new RangeError('no discrete log')
}
const modPow = (b, e, mod) => {
let r = 1
b = ((b % mod) + mod) % mod
while (e > 0) {
if (e % 2 === 1) r = (r * b) % mod
b = (b * b) % mod
e = Math.floor(e / 2)
}
return r
}
const m = Math.ceil(Math.sqrt(modulus - 1))
const baby = new Map()
let value = 1
for (let j = 0; j < m; j++) {
if (!baby.has(value)) baby.set(value, j)
value = (value * base) % modulus
}
// factor = base^{-m} mod modulus (Fermat inverse assumes prime modulus)
const invBase = modPow(base, modulus - 2, modulus)
const factor = modPow(invBase, m, modulus)
let gamma = target
for (let i = 0; i < m; i++) {
if (baby.has(gamma)) {
return i * m + baby.get(gamma)
}
gamma = (gamma * factor) % modulus
}
throw new RangeError('no discrete log')
}