Python-Code:
def f(x, n):
return ((x*0x156)^0xfca802c7) % n
solns = [1] # The one solution modulo 2, see text for explanation
n = 1
while n < 2**32:
prev_n = n
n = n * 2
lifted_solns = []
for soln in solns:
if f(soln, n) == soln:
lifted_solns.append(soln)
if f(soln + prev_n, n) == soln + prev_n:
lifted_solns.append(soln + prev_n)
solns = lifted_solns
for soln in solns:
print soln, "evaluates to ", f(soln, 2**32)
Ausgang: 150129329 ausgewertet 150129329
Idee hinter dem Algorithmus: Wir versuchen x XOR 0xfca802c7 = x*0x156 modulo n
, wo in unserem Fall n=2^32
zu finden. Ich habe es so geschrieben, weil die rechte Seite eine einfache modulare Multiplikation ist, die sich gut mit der linken Seite verhält.
Die Haupteigenschaft, die wir verwenden werden, ist, dass eine Lösung zu x XOR 0xfca802c7 = x*0x156 modulo 2^(i+1)
zu einer Lösung zu x XOR 0xfca802c7 = x*0x156 modulo 2^i
reduziert. Eine andere Art zu sagen ist, dass eine Lösung zu x XOR 0xfca802c7 = x*0x156 modulo 2^i
übersetzt zu einer oder zwei Lösungen modulo 2^(i+1)
: diese Möglichkeiten sind entweder x
und/oder x+2^i
(wenn wir genauer sein wollen, betrachten wir nur ganze Zahlen zwischen 0, ... , Modulgröße - 1, wenn wir "Lösung" sagen).
Wir können dies leicht für i=1
lösen: x XOR 0xfca802c7 = x*0x156 modulo 2^1
ist die gleiche wie x XOR 1 = x*0 mod 2
, was bedeutet, x=1
die einzige Lösung ist. Von dort wissen wir, dass nur 1 und 3 die möglichen Lösungen sind modulo 2^2 = 4
. Wir haben also nur zwei zu versuchen. Es stellt sich heraus, dass nur einer funktioniert. Das ist unsere aktuelle Lösung modulo 4. Wir können diese Lösung dann auf die Möglichkeiten modulo 8 heben. Und so weiter. Irgendwann bekommen wir alle solche Lösungen.
Bemerkung1: Dieser Code findet alle Lösungen. In diesem Fall gibt es nur einen, aber für allgemeinere Parameter kann es mehr als einen geben.
Bemerkung2: Die Laufzeit ist O (max [Anzahl der Lösungen, Modulgröße in Bits]), vorausgesetzt, ich habe keinen Fehler gemacht. Es ist also schnell, es sei denn, es gibt viele, viele Fixpunkte. In diesem Fall scheint es nur einen zu geben.
Sie benötigen um die Gleichung "x = x * 0x156^0xfca802c7" mit Überlaufarithmetik zu lösen. – aioobe
Es gibt keine festen Punkte, denn wenn x gerade ist, ist der Rückgabewert ungerade. Das reduziert das Problem um die Hälfte. Noch viel zu tun. – TheGreatContini
Ich würde erwarten, dass dieses Problem schwierig ist. Multiplikation und XOR sind algebraisch "inkompatible" Operationen, und es ist nicht einfach, über diese Art von Logik nachzudenken. Tatsächlich gibt es Verschlüsselungen und Hash-Funktionen, die darauf beruhen, Addition, Multiplikation und XOR (z. B. TEA, MurmurHash) genau zu mischen, weil sie schwer zu analysieren sind. – Nayuki