1
1
package eu .sim642 .adventofcode2020
2
2
3
3
import eu .sim642 .adventofcodelib .IntegralImplicits ._
4
+ import eu .sim642 .adventofcodelib .NumberTheory
5
+ import eu .sim642 .adventofcodelib .IteratorImplicits ._
4
6
5
7
object Day25 {
6
8
@@ -10,14 +12,39 @@ object Day25 {
10
12
subjectNumber.toLong.modPow(loopSize, modulo).toInt
11
13
}
12
14
13
- def findLoopSize (publicKey : Int , subjectNumber : Int = 7 ): Int = {
14
- Iterator .iterate(1 )(value => (subjectNumber * value) % modulo)
15
+ // TODO: move discrete log to NumberTheory
16
+
17
+ def discreteLogNaive (a : Int , b : Int , n : Int ): Int = {
18
+ Iterator .iterate(1 )(value => (a * value) % n)
15
19
.zipWithIndex
16
- .find(_._1 == publicKey )
20
+ .find(_._1 == b )
17
21
.get
18
22
._2
19
23
}
20
24
25
+ def discreteLogBabyStepGiantStep (a : Int , b : Int , n : Int ): Int = {
26
+ // https://en.wikipedia.org/wiki/Baby-step_giant-step
27
+ val m = math.sqrt(n).ceil.toInt
28
+ val map = {
29
+ Iterator .iterate(1 , m)(acc => ((a * acc.toLong) % n).toInt)
30
+ .zipWithIndex
31
+ .toMap
32
+ }
33
+
34
+ val amm = NumberTheory .modInv(a.toLong, n).modPow(m, n).toInt
35
+ Iterator .iterate(b, m)(acc => ((amm * acc.toLong) % n).toInt)
36
+ .zipWithIndex
37
+ .flatMap({ case (gamma, i) =>
38
+ map.get(gamma).map(j => i * m + j)
39
+ })
40
+ .head
41
+ }
42
+
43
+ def findLoopSize<
5F0E
/span>(publicKey : Int , subjectNumber : Int = 7 ): Int = {
44
+ // discreteLogNaive(subjectNumber, publicKey, modulo)
45
+ discreteLogBabyStepGiantStep(subjectNumber, publicKey, modulo)
46
+ }
47
+
21
48
def findEncryptionKey (publicKeys : (Int , Int )): Int = {
22
49
val (publicKey1, publicKey2) = publicKeys
23
50
val loopSize1 = findLoopSize(publicKey1)
0 commit comments