Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/groups/generic.py
8814 views
1
"""
2
Miscellaneous generic functions
3
4
A collection of functions implementing generic algorithms in arbitrary
5
groups, including additive and multiplicative groups.
6
7
In all cases the group operation is specified by a parameter
8
'operation', which is a string either one of the set of
9
multiplication_names or addition_names specified below, or 'other'.
10
In the latter case, the caller must provide an identity, inverse() and
11
op() functions.
12
13
::
14
15
multiplication_names = ( 'multiplication', 'times', 'product', '*')
16
addition_names = ( 'addition', 'plus', 'sum', '+')
17
18
19
Also included are a generic function for computing multiples (or
20
powers), and an iterator for general multiples and powers.
21
22
EXAMPLES:
23
24
Some examples in the multiplicative group of a finite field:
25
26
- Discrete logs::
27
28
sage: K = GF(3^6,'b')
29
sage: b = K.gen()
30
sage: a = b^210
31
sage: discrete_log(a, b, K.order()-1)
32
210
33
34
- Linear relation finder::
35
36
sage: F.<a>=GF(3^6,'a')
37
sage: a.multiplicative_order().factor()
38
2^3 * 7 * 13
39
sage: b=a^7
40
sage: c=a^13
41
sage: linear_relation(b,c,'*')
42
(13, 7)
43
sage: b^13==c^7
44
True
45
46
- Orders of elements::
47
48
sage: k.<a> = GF(5^5)
49
sage: b = a^4
50
sage: order_from_multiple(b,5^5-1,operation='*')
51
781
52
sage: order_from_bounds(b,(5^4,5^5),operation='*')
53
781
54
55
Some examples in the group of points of an elliptic curve over a finite field:
56
57
- Discrete logs::
58
59
sage: F=GF(37^2,'a')
60
sage: E=EllipticCurve(F,[1,1])
61
sage: F.<a>=GF(37^2,'a')
62
sage: E=EllipticCurve(F,[1,1])
63
sage: P=E(25*a + 16 , 15*a + 7 )
64
sage: P.order()
65
672
66
sage: Q=39*P; Q
67
(36*a + 32 : 5*a + 12 : 1)
68
sage: discrete_log(Q,P,P.order(),operation='+')
69
39
70
71
- Linear relation finder::
72
73
sage: F.<a>=GF(3^6,'a')
74
sage: E=EllipticCurve([a^5 + 2*a^3 + 2*a^2 + 2*a, a^4 + a^3 + 2*a + 1])
75
sage: P=E(a^5 + a^4 + a^3 + a^2 + a + 2 , 0)
76
sage: Q=E(2*a^3 + 2*a^2 + 2*a , a^3 + 2*a^2 + 1)
77
sage: linear_relation(P,Q,'+')
78
(1, 2)
79
sage: P == 2*Q
80
True
81
82
- Orders of elements::
83
84
sage: k.<a> = GF(5^5)
85
sage: E = EllipticCurve(k,[2,4])
86
sage: P = E(3*a^4 + 3*a , 2*a + 1 )
87
sage: M = E.cardinality(); M
88
3227
89
sage: plist = M.prime_factors()
90
sage: order_from_multiple(P, M, plist, operation='+')
91
3227
92
sage: Q = E(0,2)
93
sage: order_from_multiple(Q, M, plist, operation='+')
94
7
95
sage: order_from_bounds(Q, Hasse_bounds(5^5), operation='+')
96
7
97
98
"""
99
100
###########################################################################
101
# Copyright (C) 2008 William Stein <[email protected]>
102
# John Cremona <[email protected]>
103
#
104
# Distributed under the terms of the GNU General Public License (GPL)
105
# http://www.gnu.org/licenses/
106
###########################################################################
107
108
from copy import copy
109
110
import sage.misc.misc as misc
111
import sage.rings.integer_ring as integer_ring
112
import sage.rings.integer
113
114
#
115
# Lists of names (as strings) which the user may use to identify one
116
# of the standard operations:
117
#
118
multiplication_names = ( 'multiplication', 'times', 'product', '*')
119
addition_names = ( 'addition', 'plus', 'sum', '+')
120
121
from sage.structure.element import generic_power as power
122
123
def multiple(a, n, operation='*', identity=None, inverse=None, op=None):
124
r"""
125
Returns either `na` or `a^n`, where `n` is any integer and `a` is
126
a Python object on which a group operation such as addition or
127
multiplication is defined. Uses the standard binary algorithm.
128
129
INPUT: See the documentation for ``discrete_logarithm()``.
130
131
EXAMPLES::
132
133
sage: multiple(2,5)
134
32
135
sage: multiple(RealField()('2.5'),4)
136
39.0625000000000
137
sage: multiple(2,-3)
138
1/8
139
sage: multiple(2,100,'+') == 100*2
140
True
141
sage: multiple(2,100) == 2**100
142
True
143
sage: multiple(2,-100,) == 2**-100
144
True
145
sage: R.<x>=ZZ[]
146
sage: multiple(x,100)
147
x^100
148
sage: multiple(x,100,'+')
149
100*x
150
sage: multiple(x,-10)
151
1/x^10
152
153
Idempotence is detected, making the following fast::
154
155
sage: multiple(1,10^1000)
156
1
157
158
sage: E=EllipticCurve('389a1')
159
sage: P=E(-1,1)
160
sage: multiple(P,10,'+')
161
(645656132358737542773209599489/22817025904944891235367494656 : 525532176124281192881231818644174845702936831/3446581505217248068297884384990762467229696 : 1)
162
sage: multiple(P,-10,'+')
163
(645656132358737542773209599489/22817025904944891235367494656 : -528978757629498440949529703029165608170166527/3446581505217248068297884384990762467229696 : 1)
164
165
166
"""
167
from operator import inv, mul, neg, add
168
169
if operation in multiplication_names:
170
identity = a.parent()(1)
171
inverse = inv
172
op = mul
173
elif operation in addition_names:
174
identity = a.parent()(0)
175
inverse = neg
176
op = add
177
else:
178
if identity is None or inverse is None or op is None:
179
raise ValueError, "identity, inverse and operation must all be specified"
180
181
if n == 0:
182
return identity
183
184
if n < 0:
185
n = -n
186
a = inverse(a)
187
188
if n == 1:
189
return a
190
191
# check for idempotence, and store the result otherwise
192
aa = op(a,a)
193
if aa == a:
194
return a
195
196
if n == 2:
197
return aa
198
199
if n == 3:
200
return op(aa,a)
201
202
if n == 4:
203
return op(aa,aa)
204
205
# since we've computed a^2, let's start squaring there
206
# so, let's keep the least-significant bit around, just
207
# in case.
208
m = n & 1
209
n = n >> 1
210
211
# One multiplication can be saved by starting with
212
# the second-smallest power needed rather than with 1
213
# we've already squared a, so let's start there.
214
apow = aa
215
while n&1 == 0:
216
apow = op(apow,apow)
217
n = n >> 1
218
power = apow
219
n = n >> 1
220
221
# now multiply that least-significant bit in...
222
if m:
223
power = op(power,a)
224
225
# and this is straight from the book.
226
while n != 0:
227
apow = op(apow,apow)
228
if n&1 != 0:
229
power = op(power,apow)
230
n = n >> 1
231
232
return power
233
234
235
#
236
# Generic iterator for looping through multiples or powers
237
#
238
239
class multiples:
240
r"""
241
Return an iterator which runs through ``P0+i*P`` for ``i`` in ``range(n)``.
242
243
``P`` and ``P0`` must be Sage objects in some group; if the operation is
244
multiplication then the returned values are instead ``P0*P**i``.
245
246
EXAMPLES::
247
248
sage: list(multiples(1,10))
249
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
250
sage: list(multiples(1,10,100))
251
[100, 101, 102, 103, 104, 105, 106, 107, 108, 109]
252
253
sage: E=EllipticCurve('389a1')
254
sage: P=E(-1,1)
255
sage: for Q in multiples(P,5): print Q, Q.height()/P.height()
256
(0 : 1 : 0) 0.000000000000000
257
(-1 : 1 : 1) 1.00000000000000
258
(10/9 : -35/27 : 1) 4.00000000000000
259
(26/361 : -5720/6859 : 1) 9.00000000000000
260
(47503/16641 : 9862190/2146689 : 1) 16.0000000000000
261
262
sage: R.<x>=ZZ[]
263
sage: list(multiples(x,5))
264
[0, x, 2*x, 3*x, 4*x]
265
sage: list(multiples(x,5,operation='*'))
266
[1, x, x^2, x^3, x^4]
267
sage: list(multiples(x,5,indexed=True))
268
[(0, 0), (1, x), (2, 2*x), (3, 3*x), (4, 4*x)]
269
sage: list(multiples(x,5,indexed=True,operation='*'))
270
[(0, 1), (1, x), (2, x^2), (3, x^3), (4, x^4)]
271
sage: for i,y in multiples(x,5,indexed=True): print "%s times %s = %s"%(i,x,y)
272
0 times x = 0
273
1 times x = x
274
2 times x = 2*x
275
3 times x = 3*x
276
4 times x = 4*x
277
278
sage: for i,n in multiples(3,5,indexed=True,operation='*'): print "3 to the power %s = %s"%(i,n)
279
3 to the power 0 = 1
280
3 to the power 1 = 3
281
3 to the power 2 = 9
282
3 to the power 3 = 27
283
3 to the power 4 = 81
284
"""
285
def __init__(self,P,n,P0=None,indexed=False, operation='+', op=None):
286
"""
287
Create a multiples iterator
288
289
INPUT:
290
291
- ``P`` - step value: any Sage object on which a binary
292
operation is defined
293
- ``n`` - number of multiples: non-negative integer
294
- ``P0`` - offset (default 0): Sage object which can be 'added' to P
295
- ``indexed`` - boolean (default False)
296
297
If ``indexed==False`` then the iterator delivers ``P0+i*P``
298
(if ``operation=='+'``) or ``P0*P**i`` (if
299
``operation=='*'``), for ``i`` in ``range(n)``.
300
301
If ``indexed==True`` then the iterator delivers tuples
302
``(i,P0+i*P)`` or ``(i,P0*P**i)``.
303
304
- ``operation`` - string: '+' (default ) or '*' or `other`.
305
306
If `other`, a function ``op()`` must be supplied (a function
307
of 2 arguments) defining the group binary operation; also
308
``P0`` must be supplied.
309
"""
310
if n<0:
311
raise ValueError, 'n cannot be negative in multiples'
312
313
from operator import mul, add
314
315
if operation in multiplication_names:
316
if P0 is None: P0 = P.parent()(1)
317
self.op = mul
318
elif operation in addition_names:
319
if P0 is None: P0 = P.parent()(0)
320
self.op = add
321
else:
322
self.op = op
323
if P0 is None:
324
raise ValueError, "P0 must be supplied when operation is neither addition nor multiplication"
325
if op is None:
326
raise ValueError, "op() must both be supplied when operation is neither addition nor multiplication"
327
328
self.P=copy(P)
329
self.Q=copy(P0)
330
assert self.P is not None and self.Q is not None
331
self.i = 0
332
self.bound = n
333
self.indexed = indexed
334
335
336
def next(self):
337
"""
338
Returns the next item in this multiples iterator.
339
"""
340
if self.i >= self.bound:
341
raise StopIteration
342
i = self.i
343
val = self.Q
344
self.i +=1
345
self.Q=self.op(self.Q,self.P)
346
if self.indexed:
347
return (i,val)
348
else:
349
return val
350
def __iter__(self):
351
"""
352
Standard member function making this class an iterator.
353
"""
354
return self
355
356
357
def bsgs(a, b, bounds, operation='*', identity=None, inverse=None, op=None):
358
r"""
359
Totally generic discrete baby-step giant-step function.
360
361
Solves `na=b` (or `a^n=b`) with `lb\le n\le ub` where ``bounds==(lb,ub)``,
362
raising an error if no such `n` exists.
363
364
`a` and `b` must be elements of some group with given identity,
365
inverse of ``x`` given by ``inverse(x)``, and group operation on
366
``x``, ``y`` by ``op(x,y)``.
367
368
If operation is '*' or '+' then the other
369
arguments are provided automatically; otherwise they must be
370
provided by the caller.
371
372
INPUT:
373
374
- ``a`` - group element
375
- ``b`` - group element
376
- ``bounds`` - a 2-tuple of integers ``(lower,upper)`` with ``0<=lower<=upper``
377
- ``operation`` - string: '*', '+', 'other'
378
- ``identity`` - the identity element of the group
379
- ``inverse()`` - function of 1 argument ``x`` returning inverse of ``x``
380
- ``op()`` - function of 2 arguments ``x``, ``y`` returning ``x*y`` in group
381
382
OUTPUT:
383
384
An integer `n` such that `a^n = b` (or `na = b`). If no
385
such `n` exists, this function raises a ValueError exception.
386
387
NOTE: This is a generalization of discrete logarithm. One
388
situation where this version is useful is to find the order of
389
an element in a group where we only have bounds on the group
390
order (see the elliptic curve example below).
391
392
ALGORITHM: Baby step giant step. Time and space are soft
393
`O(\sqrt{n})` where `n` is the difference between upper and lower
394
bounds.
395
396
EXAMPLES::
397
398
sage: b = Mod(2,37); a = b^20
399
sage: bsgs(b, a, (0,36))
400
20
401
402
sage: p=next_prime(10^20)
403
sage: a=Mod(2,p); b=a^(10^25)
404
sage: bsgs(a, b, (10^25-10^6,10^25+10^6)) == 10^25
405
True
406
407
sage: K = GF(3^6,'b')
408
sage: a = K.gen()
409
sage: b = a^210
410
sage: bsgs(a, b, (0,K.order()-1))
411
210
412
413
sage: K.<z>=CyclotomicField(230)
414
sage: w=z^500
415
sage: bsgs(z,w,(0,229))
416
40
417
418
An additive example in an elliptic curve group::
419
420
sage: F.<a> = GF(37^5)
421
sage: E = EllipticCurve(F, [1,1])
422
sage: P = E.lift_x(a); P
423
(a : 28*a^4 + 15*a^3 + 14*a^2 + 7 : 1) # 32-bit
424
(a : 9*a^4 + 22*a^3 + 23*a^2 + 30 : 1) # 64-bit
425
426
This will return a multiple of the order of P::
427
428
sage: bsgs(P,P.parent()(0),Hasse_bounds(F.order()),operation='+')
429
69327408
430
431
AUTHOR:
432
433
- John Cremona (2008-03-15)
434
"""
435
Z = integer_ring.ZZ
436
437
from operator import inv, mul, neg, add
438
439
if operation in multiplication_names:
440
identity = a.parent()(1)
441
inverse = inv
442
op = mul
443
elif operation in addition_names:
444
identity = a.parent()(0)
445
inverse = neg
446
op = add
447
else:
448
if identity is None or inverse is None or op is None:
449
raise ValueError, "identity, inverse and operation must be given"
450
451
lb, ub = bounds
452
if lb<0 or ub<lb:
453
raise ValueError, "bsgs() requires 0<=lb<=ub"
454
455
if a.is_zero() and not b.is_zero():
456
raise ValueError, "No solution in bsgs()"
457
458
ran = 1 + ub - lb # the length of the interval
459
460
c = op(inverse(b),multiple(a,lb,operation=operation))
461
462
if ran < 30: # use simple search for small ranges
463
i = lb
464
d = c
465
# for i,d in multiples(a,ran,c,indexed=True,operation=operation):
466
for i0 in range(ran):
467
i = lb + i0
468
if identity == d: # identity == b^(-1)*a^i, so return i
469
return Z(i)
470
d = op(a,d)
471
raise ValueError, "No solution in bsgs()"
472
473
m = ran.isqrt()+1 # we need sqrt(ran) rounded up
474
table = dict() # will hold pairs (a^(lb+i),lb+i) for i in range(m)
475
476
d=c
477
for i0 in misc.srange(m):
478
i = lb + i0
479
if identity==d: # identity == b^(-1)*a^i, so return i
480
return Z(i)
481
table[d] = i
482
d=op(d,a)
483
484
c = op(c,inverse(d)) # this is now a**(-m)
485
d=identity
486
for i in misc.srange(m):
487
j = table.get(d)
488
if j is not None: # then d == b*a**(-i*m) == a**j
489
return Z(i*m + j)
490
d=op(c,d)
491
492
raise ValueError, "Log of %s to the base %s does not exist in %s."%(b,a,bounds)
493
494
def discrete_log_rho(a, base, ord=None, operation='*', hash_function=hash):
495
"""
496
Pollard Rho algorithm for computing discrete logarithm in cyclic
497
group of prime order.
498
If the group order is very small it falls back to the baby step giant step
499
algorithm.
500
501
INPUT:
502
503
- ``a`` -- a group element
504
- ``base`` -- a group element
505
- ``ord`` -- the order of ``base`` or ``None``, in this case we try
506
to compute it
507
- ``operation`` -- a string (default: ``'*'``) denoting whether we
508
are in an additive group or a multiplicative one
509
- ``hash_function`` -- having an efficient hash function is critical
510
for this algorithm (see examples)
511
512
OUTPUT: an integer `n` such that `a = base^n` (or `a = n*base`)
513
514
ALGORITHM: Pollard rho for discrete logarithm, adapted from the
515
article of Edlyn Teske, 'A space efficient algorithm for group
516
structure computation'.
517
518
EXAMPLES::
519
520
sage: F.<a> = GF(2^13)
521
sage: g = F.gen()
522
sage: discrete_log_rho(g^1234, g)
523
1234
524
525
sage: F.<a> = GF(37^5)
526
sage: E = EllipticCurve(F, [1,1])
527
sage: G = (3*31*2^4)*E.lift_x(a)
528
sage: discrete_log_rho(12345*G, G, ord=46591, operation='+')
529
12345
530
531
It also works with matrices::
532
533
sage: A = matrix(GF(50021),[[10577,23999,28893],[14601,41019,30188],[3081,736,27092]])
534
sage: discrete_log_rho(A^1234567, A)
535
1234567
536
537
Beware, the order must be prime::
538
539
sage: I = IntegerModRing(171980)
540
sage: discrete_log_rho(I(2), I(3))
541
Traceback (most recent call last):
542
...
543
ValueError: for Pollard rho algorithm the order of the group must be prime
544
545
If it fails to find a suitable logarithm, it raises a ``ValueError``::
546
547
sage: I = IntegerModRing(171980)
548
sage: discrete_log_rho(I(31002),I(15501))
549
Traceback (most recent call last):
550
...
551
ValueError: Pollard rho algorithm failed to find a logarithm
552
553
The main limitation on the hash function is that we don't want to have
554
`hash(x*y) = hash(x) + hash(y)`::
555
556
sage: I = IntegerModRing(next_prime(2^23))
557
sage: def test():
558
....: try:
559
....: discrete_log_rho(I(123456),I(1),operation='+')
560
....: except Exception:
561
....: print "FAILURE"
562
sage: test() # random failure
563
FAILURE
564
565
If this happens, we can provide a better hash function::
566
567
sage: discrete_log_rho(I(123456),I(1),operation='+', hash_function=lambda x: hash(x*x))
568
123456
569
570
AUTHOR:
571
572
- Yann Laigle-Chapuy (2009-09-05)
573
574
"""
575
from sage.rings.integer import Integer
576
from sage.rings.finite_rings.integer_mod_ring import IntegerModRing
577
from operator import mul, add, pow
578
579
# should be reasonable choices
580
partition_size = 20
581
memory_size = 4
582
583
if operation in addition_names:
584
mult = add
585
power = mul
586
if ord is None:
587
ord = base.additive_order()
588
elif operation in multiplication_names:
589
mult = mul
590
power = pow
591
if ord is None:
592
ord = base.multiplicative_order()
593
else:
594
raise(ValueError, "unknown operation")
595
596
ord = Integer(ord)
597
598
if not ord.is_prime():
599
raise ValueError,"for Pollard rho algorithm the order of the group must be prime"
600
601
# check if we need to set immutable before hashing
602
mut = hasattr(base,'set_immutable')
603
604
isqrtord=ord.isqrt()
605
606
if isqrtord < partition_size: #setup to costly, use bsgs
607
return bsgs(base,a, bounds=(0,ord), operation=operation)
608
609
reset_bound = 8*isqrtord # we take some margin
610
611
I=IntegerModRing(ord)
612
613
for s in xrange(10): # to avoid infinite loops
614
# random walk function setup
615
m=[I.random_element() for i in xrange(partition_size)]
616
n=[I.random_element() for i in xrange(partition_size)]
617
M=[mult(power(base,Integer(m[i])),power(a,Integer(n[i]))) for i in xrange(partition_size)]
618
619
ax = I.random_element()
620
x = power(base,Integer(ax))
621
if mut:
622
x.set_immutable()
623
624
bx = I(0)
625
626
sigma=[(0,None)]*memory_size
627
H={} # memory
628
i0=0
629
nextsigma = 0
630
for i in xrange(reset_bound):
631
#random walk, we need an efficient hash
632
s=hash_function(x) % partition_size
633
(x,ax,bx) = (mult(M[s],x), ax+m[s], bx+n[s])
634
if mut:
635
x.set_immutable()
636
# look for collisions
637
if x in H:
638
ay,by=H[x]
639
if bx == by:
640
break
641
else:
642
res = sage.rings.integer.Integer((ay-ax)/(bx-by))
643
if power(base,res) == a:
644
return res
645
else:
646
break
647
# should we remember this value?
648
elif i >= nextsigma:
649
if sigma[i0][1] is not None:
650
H.pop(sigma[i0][1])
651
sigma[i0]=(i,x)
652
i0 = (i0+1) % memory_size
653
nextsigma = 3*sigma[i0][0] #3 seems a good choice
654
H[x]=(ax,bx)
655
656
raise ValueError, "Pollard rho algorithm failed to find a logarithm"
657
658
def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, inverse=None, op=None):
659
r"""
660
Totally generic discrete log function.
661
662
INPUT:
663
664
- ``a`` - group element
665
- ``base`` - group element (the base)
666
- ``ord`` - integer (multiple of order of base, or ``None``)
667
- ``bounds`` - a priori bounds on the log
668
- ``operation`` - string: '*', '+', 'other'
669
- ``identity`` - the group's identity
670
- ``inverse()`` - function of 1 argument ``x`` returning inverse of ``x``
671
- ``op()`` - function of 2 arguments ``x``, ``y`` returning ``x*y`` in group
672
673
``a`` and ``base`` must be elements of some group with identity
674
given by identity, inverse of ``x`` by ``inverse(x)``, and group
675
operation on ``x``, ``y`` by ``op(x,y)``.
676
677
If operation is '*' or '+' then the other
678
arguments are provided automatically; otherwise they must be
679
provided by the caller.
680
681
OUTPUT: Returns an integer `n` such that `b^n = a` (or `nb = a`),
682
assuming that ``ord`` is a multiple of the order of the base `b`.
683
If ``ord`` is not specified, an attempt is made to compute it.
684
685
If no such `n` exists, this function raises a ValueError exception.
686
687
.. warning::
688
689
If ``x`` has a log method, it is likely to be vastly faster
690
than using this function. E.g., if ``x`` is an integer modulo
691
`n`, use its log method instead!
692
693
ALGORITHM: Pohlig-Hellman and Baby step giant step.
694
695
EXAMPLES::
696
697
sage: b = Mod(2,37); a = b^20
698
sage: discrete_log(a, b)
699
20
700
sage: b = Mod(2,997); a = b^20
701
sage: discrete_log(a, b)
702
20
703
704
sage: K = GF(3^6,'b')
705
sage: b = K.gen()
706
sage: a = b^210
707
sage: discrete_log(a, b, K.order()-1)
708
210
709
710
sage: b = Mod(1,37); x = Mod(2,37)
711
sage: discrete_log(x, b)
712
Traceback (most recent call last):
713
...
714
ValueError: No discrete log of 2 found to base 1
715
sage: b = Mod(1,997); x = Mod(2,997)
716
sage: discrete_log(x, b)
717
Traceback (most recent call last):
718
...
719
ValueError: No discrete log of 2 found to base 1
720
721
See trac\#2356:
722
sage: F.<w> = GF(121)
723
sage: v = w^120
724
sage: v.log(w)
725
0
726
727
sage: K.<z>=CyclotomicField(230)
728
sage: w=z^50
729
sage: discrete_log(w,z)
730
50
731
732
An example where the order is infinite: note that we must give
733
an upper bound here::
734
735
sage: K.<a> = QuadraticField(23)
736
sage: eps = 5*a-24 # a fundamental unit
737
sage: eps.multiplicative_order()
738
+Infinity
739
sage: eta = eps^100
740
sage: discrete_log(eta,eps,bounds=(0,1000))
741
100
742
743
In this case we cannot detect negative powers::
744
745
sage: eta = eps^(-3)
746
sage: discrete_log(eta,eps,bounds=(0,100))
747
Traceback (most recent call last):
748
...
749
ValueError: No discrete log of -11515*a - 55224 found to base 5*a - 24
750
751
But we can invert the base (and negate the result) instead::
752
753
sage: - discrete_log(eta^-1,eps,bounds=(0,100))
754
-3
755
756
An additive example: elliptic curve DLOG::
757
758
sage: F=GF(37^2,'a')
759
sage: E=EllipticCurve(F,[1,1])
760
sage: F.<a>=GF(37^2,'a')
761
sage: E=EllipticCurve(F,[1,1])
762
sage: P=E(25*a + 16 , 15*a + 7 )
763
sage: P.order()
764
672
765
sage: Q=39*P; Q
766
(36*a + 32 : 5*a + 12 : 1)
767
sage: discrete_log(Q,P,P.order(),operation='+')
768
39
769
770
An example of big smooth group::
771
772
sage: F.<a>=GF(2^63)
773
sage: g=F.gen()
774
sage: u=g**123456789
775
sage: discrete_log(u,g)
776
123456789
777
778
AUTHORS:
779
780
- William Stein and David Joyner (2005-01-05)
781
- John Cremona (2008-02-29) rewrite using ``dict()`` and make generic
782
783
"""
784
if ord is None:
785
if operation in multiplication_names:
786
try:
787
ord = base.multiplicative_order()
788
except Exception:
789
ord = base.order()
790
elif operation in addition_names:
791
try:
792
ord = base.additive_order()
793
except Exception:
794
ord = base.order()
795
else:
796
try:
797
ord = base.order()
798
except Exception:
799
raise ValueError, "ord must be specified"
800
try:
801
from sage.rings.infinity import Infinity
802
if ord==+Infinity:
803
return bsgs(base,a,bounds, operation=operation)
804
if ord==1 and a!=base:
805
raise ValueError
806
f=ord.factor()
807
l=[0]*len(f)
808
for i,(pi,ri) in enumerate(f):
809
for j in range(ri):
810
if operation in multiplication_names:
811
c=bsgs(base**(ord//pi),(a/base**l[i])**(ord//pi**(j+1)),(0,pi),operation=operation)
812
l[i] += c*(pi**j)
813
elif operation in addition_names:
814
c=bsgs(base*(ord//pi),(a-base*l[i])*(ord//pi**(j+1)),(0,pi),operation=operation)
815
l[i] += c*(pi**j)
816
from sage.rings.arith import CRT_list
817
return CRT_list(l,[pi**ri for pi,ri in f])
818
except ValueError:
819
raise ValueError, "No discrete log of %s found to base %s"%(a,base)
820
821
def discrete_log_generic(a, base, ord=None, bounds=None, operation='*', identity=None, inverse=None, op=None):
822
"""
823
Alias for ``discrete_log``.
824
"""
825
return discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, inverse=None, op=None)
826
827
def discrete_log_lambda(a, base, bounds, operation='*', hash_function=hash):
828
"""
829
Pollard Lambda algorithm for computing discrete logarithms. It uses
830
only a logarithmic amount of memory. It's useful if you have
831
bounds on the logarithm. If you are computing logarithms in a
832
whole finite group, you should use Pollard Rho algorithm.
833
834
INPUT:
835
836
- a - a group element
837
- base - a group element
838
- bounds - a couple (lb,ub) representing the range where we look for a logarithm
839
- operation - string: '+', '*' or 'other'
840
- hash_function -- having an efficient hash function is critical for this algorithm
841
842
OUTPUT: Returns an integer `n` such that `a=base^n` (or `a=n*base`)
843
844
ALGORITHM: Pollard Lambda, if bounds are (lb,ub) it has time complexity
845
O(sqrt(ub-lb)) and space complexity O(log(ub-lb))
846
847
EXEMPLES::
848
849
sage: F.<a> = GF(2^63)
850
sage: discrete_log_lambda(a^1234567, a, (1200000,1250000))
851
1234567
852
853
sage: F.<a> = GF(37^5)
854
sage: E = EllipticCurve(F, [1,1])
855
sage: P = E.lift_x(a); P
856
(a : 9*a^4 + 22*a^3 + 23*a^2 + 30 : 1) # 32-bit
857
(a : 28*a^4 + 15*a^3 + 14*a^2 + 7 : 1) # 64-bit
858
859
This will return a multiple of the order of P::
860
861
sage: discrete_log_lambda(P.parent()(0), P, Hasse_bounds(F.order()), operation='+')
862
69327408
863
864
sage: K.<a> = GF(89**5)
865
sage: hs = lambda x: hash(x) + 15
866
sage: discrete_log_lambda(a**(89**3 - 3), a, (89**2, 89**4), operation = '*', hash_function = hs) # long time (10s on sage.math, 2011)
867
704966
868
869
AUTHOR:
870
871
-- Yann Laigle-Chapuy (2009-01-25)
872
873
"""
874
from sage.rings.integer import Integer
875
from operator import mul, add, pow
876
877
if operation in addition_names:
878
mult=add
879
power=mul
880
elif operation in multiplication_names:
881
mult=mul
882
power=pow
883
else:
884
raise ValueError("unknown operation")
885
886
lb,ub = bounds
887
if lb<0 or ub<lb:
888
raise ValueError, "discrete_log_lambda() requires 0<=lb<=ub"
889
890
# check for mutability
891
mut = hasattr(base,'set_immutable')
892
893
width = Integer(ub-lb)
894
N = width.isqrt()+1
895
896
M = dict()
897
for s in xrange(10): #to avoid infinite loops
898
#random walk function setup
899
k = 0
900
while (2**k<N):
901
r = sage.misc.prandom.randrange(1,N)
902
M[k] = (r , power(base,r))
903
k += 1
904
#first random walk
905
H = power(base,ub)
906
c = ub
907
for i in xrange(N):
908
if mut: H.set_immutable()
909
r,e = M[hash_function(H)%k]
910
H = mult(H,e)
911
c += r
912
if mut: H.set_immutable()
913
mem=set([H])
914
#second random walk
915
H = a
916
d=0
917
while c-d >= lb:
918
if mut: H.set_immutable()
919
if ub > c-d and H in mem:
920
return c-d
921
r,e = M[hash_function(H)%k]
922
H = mult(H,e)
923
d += r
924
925
raise ValueError, "Pollard Lambda failed to find a log"
926
927
928
################################################################
929
#
930
# Generic linear relation finder
931
#
932
################################################################
933
934
def linear_relation(P, Q, operation='+', identity=None, inverse=None, op=None):
935
r"""
936
Function which solves the equation ``a*P=m*Q`` or ``P^a=Q^m``.
937
938
Additive version: returns `(a,m)` with minimal `m>0` such that
939
`aP=mQ`. Special case: if `\left<P\right>` and `\left<Q\right>`
940
intersect only in `\{0\}` then `(a,m)=(0,n)` where `n` is
941
``Q.additive_order()``.
942
943
Multiplicative version: returns `(a,m)` with minimal `m>0` such
944
that `P^a=Q^m`. Special case: if `\left<P\right>` and
945
`\left<Q\right>` intersect only in `\{1\}` then `(a,m)=(0,n)`
946
where `n` is ``Q.multiplicative_order()``.
947
948
ALGORITHM:
949
950
Uses the generic ``bsgs()`` function, and so works in general
951
finite abelian groups.
952
953
EXAMPLES:
954
955
An additive example (in an elliptic curve group)::
956
957
sage: F.<a>=GF(3^6,'a')
958
sage: E=EllipticCurve([a^5 + 2*a^3 + 2*a^2 + 2*a, a^4 + a^3 + 2*a + 1])
959
sage: P=E(a^5 + a^4 + a^3 + a^2 + a + 2 , 0)
960
sage: Q=E(2*a^3 + 2*a^2 + 2*a , a^3 + 2*a^2 + 1)
961
sage: linear_relation(P,Q,'+')
962
(1, 2)
963
sage: P == 2*Q
964
True
965
966
A multiplicative example (in a finite field's multiplicative group)::
967
968
sage: F.<a>=GF(3^6,'a')
969
sage: a.multiplicative_order().factor()
970
2^3 * 7 * 13
971
sage: b=a^7
972
sage: c=a^13
973
sage: linear_relation(b,c,'*')
974
(13, 7)
975
sage: b^13==c^7
976
True
977
"""
978
979
from operator import mul, add
980
Z = integer_ring.ZZ
981
982
if operation in multiplication_names:
983
op = mul
984
try:
985
n = P.multiplicative_order()
986
m = Q.multiplicative_order()
987
except Exception:
988
n = P.order()
989
m = Q.order()
990
elif operation in addition_names:
991
op = add
992
try:
993
n = P.additive_order()
994
m = Q.additive_order()
995
except Exception:
996
n = P.order()
997
m = Q.order()
998
else:
999
if op is None:
1000
raise ValueError, "operation must be specified"
1001
n = P.order()
1002
m = Q.order()
1003
1004
g = sage.rings.arith.gcd(n,m)
1005
if g==1: return (m,Z(0))
1006
n1 = n//g
1007
m1 = m//g
1008
P1 = multiple(P,n1,operation=operation) # has exact order g
1009
Q1 = multiple(Q,m1,operation=operation) # has exact order g
1010
1011
# now see if Q1 is a multiple of P1; the only multiples we
1012
# need check are h*Q1 where h divides g
1013
for h in g.divisors(): # positive divisors!
1014
try:
1015
Q2 = multiple(Q1,h,operation=operation)
1016
return (n1 * bsgs(P1,Q2,(0,g-1),operation=operation),
1017
m1 * h)
1018
except ValueError:
1019
pass # to next h
1020
raise ValueError, "No solution found in linear_relation!"
1021
1022
################################################################
1023
#
1024
# Generic functions to find orders of elements
1025
#
1026
# 1. order_from_multiple: finds the order given a multiple of the order
1027
#
1028
# 2. order_from_bounds: finds the order given an interval containing a
1029
# multiple of the order
1030
#
1031
################################################################
1032
1033
def order_from_multiple(P, m, plist=None, factorization=None, check=True,
1034
operation='+'):
1035
r"""
1036
Generic function to find order of a group element given a multiple
1037
of its order.
1038
1039
INPUT:
1040
1041
- ``P`` - a Sage object which is a group element;
1042
- ``m`` - a Sage integer which is a multiple of the order of ``P``,
1043
i.e. we require that ``m*P=0`` (or ``P**m=1``);
1044
- ``check`` - a Boolean (default:True), indicating whether we check if ``m``
1045
really is a multiple of the order;
1046
- ``factorization`` - the factorization of ``m``, or ``None`` in which
1047
case this function will need to factor ``m``;
1048
- ``plist`` - a list of the prime factors of ``m``, or ``None`` - kept for compatibility only,
1049
prefer the use of ``factorization``;
1050
- ``operation`` - string: '+' (default) or '*'.
1051
1052
.. note::
1053
1054
It is more efficient for the caller to factor ``m`` and cache
1055
the factors for subsequent calls.
1056
1057
EXAMPLES::
1058
1059
sage: k.<a> = GF(5^5)
1060
sage: b = a^4
1061
sage: order_from_multiple(b,5^5-1,operation='*')
1062
781
1063
sage: E = EllipticCurve(k,[2,4])
1064
sage: P = E(3*a^4 + 3*a , 2*a + 1 )
1065
sage: M = E.cardinality(); M
1066
3227
1067
sage: F = M.factor()
1068
sage: order_from_multiple(P, M, factorization=F, operation='+')
1069
3227
1070
sage: Q = E(0,2)
1071
sage: order_from_multiple(Q, M, factorization=F, operation='+')
1072
7
1073
1074
sage: K.<z>=CyclotomicField(230)
1075
sage: w=z^50
1076
sage: order_from_multiple(w,230,operation='*')
1077
23
1078
1079
sage: F=GF(2^1279,'a')
1080
sage: n=F.cardinality()-1 # Mersenne prime
1081
sage: order_from_multiple(F.random_element(),n,factorization=[(n,1)],operation='*')==n
1082
True
1083
1084
sage: K.<a> = GF(3^60)
1085
sage: order_from_multiple(a, 3^60-1, operation='*', check=False)
1086
42391158275216203514294433200
1087
"""
1088
from operator import mul, add
1089
Z = integer_ring.ZZ
1090
1091
if operation in multiplication_names:
1092
identity = P.parent()(1)
1093
elif operation in addition_names:
1094
identity = P.parent()(0)
1095
else:
1096
raise ValueError, "unknown group operation"
1097
1098
if P == identity:
1099
return Z(1)
1100
1101
M=Z(m)
1102
if check:
1103
assert multiple(P,M,operation=operation) == identity
1104
1105
if factorization:
1106
F = factorization
1107
elif plist:
1108
F = [(p,M.valuation(p)) for p in plist]
1109
else:
1110
F = M.factor()
1111
1112
if len(F) == 1 and list(F) == [(M,1)]:
1113
return M
1114
1115
# Efficiency improvement (2009-10-27, implemented by Yann Laigle-Chapuy):
1116
# we use an internal recursive function to avoid unnecessary computations.
1117
def _order_from_multiple_helper(Q, L, S):
1118
"""
1119
internal use, to minimize the number of group operations.
1120
"""
1121
l = len(L)
1122
if l == 1:
1123
# we determine the power of p dividing the order,
1124
1125
# Efficiency improvement (2009-04-01, suggested by Ryan Hinton,
1126
# implemented by John Cremona): avoid the last multiplication by p.
1127
# For example, if M itself is prime the code used to compute M*P
1128
# twice (unless P=0), now it does it once.
1129
p,e = L[0]
1130
e0 = 0
1131
while (Q != identity) and (e0<e-1):
1132
Q = multiple(Q,p,operation=operation)
1133
e0 += 1
1134
if (Q != identity):
1135
e0 += 1
1136
return p**e0
1137
else:
1138
# try to split the list wisely
1139
sum_left = 0
1140
i = 0
1141
for k in range(l):
1142
p,e = L[k]
1143
# multiplying by p**e require roughly 'e log_2(p) / 2' additions
1144
v = e * sage.functions.log.log(float(p))
1145
if abs(sum_left + v - (S / 2)) > abs(sum_left - (S / 2)):
1146
break
1147
sum_left += v
1148
L1 = L[:k]
1149
L2 = L[k:]
1150
# recursive calls
1151
o1 = _order_from_multiple_helper(
1152
multiple(Q, sage.misc.misc.prod([p**e for p,e in L2]), operation),
1153
L1,
1154
sum_left)
1155
o2 = _order_from_multiple_helper(
1156
multiple(Q, o1 , operation),
1157
L2,
1158
S-sum_left)
1159
return o1*o2
1160
1161
return _order_from_multiple_helper(P, F, sage.functions.log.log(float(M)) )
1162
1163
1164
1165
1166
def order_from_bounds(P, bounds, d=None, operation='+',
1167
identity=None, inverse=None, op=None):
1168
r"""
1169
Generic function to find order of a group element, given only
1170
upper and lower bounds for a multiple of the order (e.g. bounds on
1171
the order of the group of which it is an element)
1172
1173
INPUT:
1174
1175
- ``P`` - a Sage object which is a group element
1176
1177
- ``bounds`` - a 2-tuple ``(lb,ub)`` such that ``m*P=0`` (or
1178
``P**m=1``) for some ``m`` with ``lb<=m<=ub``.
1179
1180
- ``d`` - (optional) a positive integer; only ``m`` which are
1181
multiples of this will be considered.
1182
1183
- ``operation`` - string: '+' (default ) or '*' or other.
1184
If other, the following must be supplied:
1185
1186
- ``identity``: the identity element for the group;
1187
- ``inverse()``: a function of one argument giving the inverse
1188
of a group element;
1189
- ``op()``: a function of 2 arguments defining the group binary
1190
operation.
1191
1192
1193
.. note::
1194
1195
Typically ``lb`` and ``ub`` will be bounds on the group order,
1196
and from previous calculation we know that the group order is
1197
divisible by ``d``.
1198
1199
EXAMPLES::
1200
1201
sage: k.<a> = GF(5^5)
1202
sage: b = a^4
1203
sage: order_from_bounds(b,(5^4,5^5),operation='*')
1204
781
1205
sage: E = EllipticCurve(k,[2,4])
1206
sage: P = E(3*a^4 + 3*a , 2*a + 1 )
1207
sage: bounds = Hasse_bounds(5^5)
1208
sage: Q = E(0,2)
1209
sage: order_from_bounds(Q, bounds, operation='+')
1210
7
1211
sage: order_from_bounds(P, bounds, 7, operation='+')
1212
3227
1213
1214
sage: K.<z>=CyclotomicField(230)
1215
sage: w=z^50
1216
sage: order_from_bounds(w,(200,250),operation='*')
1217
23
1218
1219
"""
1220
from operator import mul, add
1221
Z = integer_ring.ZZ
1222
1223
if operation in multiplication_names:
1224
op = mul
1225
identity = P.parent()(1)
1226
elif operation in addition_names:
1227
op = add
1228
identity = P.parent()(0)
1229
else:
1230
if op is None:
1231
raise ValueError, "operation and identity must be specified"
1232
1233
Q = P
1234
if d is None: d = 1
1235
if d > 1:
1236
Q = multiple(P,d,operation=operation)
1237
lb, ub = bounds
1238
bounds = ( sage.rings.arith.integer_ceil(lb/d),
1239
sage.rings.arith.integer_floor(ub/d) )
1240
1241
# Use generic bsgs to find n=d*m with lb<=n<=ub and n*P=0
1242
1243
m = d * bsgs(Q, identity, bounds, operation=operation)
1244
1245
# Now use the order_from_multiple() function to finish the job:
1246
1247
return order_from_multiple(P, m, operation=operation, check=False)
1248
1249
def merge_points(P1,P2, operation='+',
1250
identity=None, inverse=None, op=None, check=True):
1251
r"""
1252
Returns a group element whose order is the lcm of the given elements.
1253
1254
INPUT:
1255
1256
- ``P1`` -- a pair `(g_1,n_1)` where `g_1` is a group element of order `n_1`
1257
- ``P2`` -- a pair `(g_2,n_2)` where `g_2` is a group element of order `n_2`
1258
- ``operation`` -- string: '+' (default ) or '*' or other. If
1259
other, the following must be supplied:
1260
1261
- ``identity``: the identity element for the group;
1262
- ``inverse()``: a function of one argument giving the inverse
1263
of a group element;
1264
- ``op()``: a function of 2 arguments defining the group
1265
binary operation.
1266
1267
1268
OUTPUT:
1269
1270
A pair `(g_3,n_3)` where `g_3` has order `n_3=\hbox{lcm}(n_1,n_2)`.
1271
1272
EXAMPLES::
1273
1274
sage: F.<a>=GF(3^6,'a')
1275
sage: b = a^7
1276
sage: c = a^13
1277
sage: ob = (3^6-1)//7
1278
sage: oc = (3^6-1)//13
1279
sage: merge_points((b,ob),(c,oc),operation='*')
1280
(a^4 + 2*a^3 + 2*a^2, 728)
1281
sage: d,od = merge_points((b,ob),(c,oc),operation='*')
1282
sage: od == d.multiplicative_order()
1283
True
1284
sage: od == lcm(ob,oc)
1285
True
1286
1287
sage: E=EllipticCurve([a^5 + 2*a^3 + 2*a^2 + 2*a, a^4 + a^3 + 2*a + 1])
1288
sage: P=E(2*a^5 + 2*a^4 + a^3 + 2 , a^4 + a^3 + a^2 + 2*a + 2)
1289
sage: P.order()
1290
7
1291
sage: Q=E(2*a^5 + 2*a^4 + 1 , a^5 + 2*a^3 + 2*a + 2 )
1292
sage: Q.order()
1293
4
1294
sage: R,m = merge_points((P,7),(Q,4), operation='+')
1295
sage: R.order() == m
1296
True
1297
sage: m == lcm(7,4)
1298
True
1299
"""
1300
from operator import mul, add
1301
Z = integer_ring.ZZ
1302
1303
g1, n1 = P1
1304
g2, n2 = P2
1305
1306
if operation in multiplication_names:
1307
op = mul
1308
identity = g1.parent()(1)
1309
elif operation in addition_names:
1310
op = add
1311
identity = g1.parent()(0)
1312
else:
1313
if op is None:
1314
raise ValueError, "operation and identity must be specified"
1315
1316
if check:
1317
assert multiple(g1,n1,operation=operation) == identity
1318
assert multiple(g2,n2,operation=operation) == identity
1319
1320
# trivial cases
1321
if n1.divides(n2):
1322
return (g2,n2)
1323
if n2.divides(n1):
1324
return (g1,n1)
1325
1326
m,k1,k2 = sage.rings.arith.xlcm(n1,n2);
1327
m1 = n1//k1
1328
m2 = n2//k2
1329
g1 = multiple(g1,m1,operation=operation)
1330
g2 = multiple(g2,m2,operation=operation)
1331
return (op(g1,g2), m)
1332
1333