@@ -3543,6 +3543,9 @@ def discrete_log(self, Q, ord=None):
3543
3543
- Otherwise (if this test is inconclusive), check that the Weil
3544
3544
pairing of `P` and `Q` is trivial.
3545
3545
3546
+ For anomalous curves with `\#E = p`, the
3547
+ :meth:`padic_elliptic_logarithm` function is called.
3548
+
3546
3549
INPUT:
3547
3550
3548
3551
- ``Q`` (point) -- another point on the same curve as ``self``.
@@ -3601,12 +3604,106 @@ def discrete_log(self, Q, ord=None):
3601
3604
if n * Q :
3602
3605
raise ValueError ('ECDLog problem has no solution (order of Q does not divide order of P)' )
3603
3606
E = self .curve ()
3604
- if hasattr (E , '_order' ) and E ._order .gcd (n ** 2 ) == n :
3607
+ F = E .base_ring ()
3608
+ p = F .cardinality ()
3609
+ if F .is_prime_field () and n == p :
3610
+ # Anomalous case
3611
+ return self .padic_elliptic_logarithm (Q , p )
3612
+ elif hasattr (E , '_order' ) and E ._order .gcd (n ** 2 ) == n :
3605
3613
pass # cyclic rational n-torsion -> okay
3606
3614
elif self .weil_pairing (Q , n ) != 1 :
3607
3615
raise ValueError ('ECDLog problem has no solution (non-trivial Weil pairing)' )
3616
+
3608
3617
return ZZ (pari .elllog (self .curve (), Q , self , n ))
3609
3618
3619
+ def padic_elliptic_logarithm (self ,Q , p ):
3620
+ r"""
3621
+ Return the discrete logarithm of `Q` to base `P` = ``self``,
3622
+ that is, an integer `x` such that `xP = Q` only for anomalous curves.
3623
+
3624
+ ALGORITHM:
3625
+
3626
+ Discrete logarithm computed as in [Sma1999]_ with a loop to avoid
3627
+ the canonical lift.
3628
+
3629
+ INPUT:
3630
+
3631
+ - ``Q`` (point) -- another point on the same curve as ``self``.
3632
+ - ``p`` (integer) -- a prime equals the order of the curve.
3633
+
3634
+ OUTPUT:
3635
+
3636
+ (integer) -- The discrete logarithm of `Q` with respect to `P`,
3637
+ which is an integer `x` with `0\le x<\mathrm{ord}(P)` such that
3638
+ `xP=Q`.
3639
+
3640
+ AUTHORS:
3641
+
3642
+ - Sylvain Pelissier (2022) based on Samuel Neves code_.
3643
+
3644
+ .. _code: https://crypto.stackexchange.com/questions/70454/why-smarts-attack-doesnt-work-on-this-ecdlp/70508#70508
3645
+
3646
+ EXAMPLES::
3647
+
3648
+ sage: p=235322474717419
3649
+ sage: b=8856682
3650
+ sage: E = EllipticCurve(GF(p), [0, b])
3651
+ sage: P = E(200673830421813, 57025307876612)
3652
+ sage: Q = E(40345734829479, 211738132651297)
3653
+ sage: x = P.padic_elliptic_logarithm(Q, p)
3654
+ sage: x * P == Q
3655
+ True
3656
+
3657
+ TESTS:
3658
+
3659
+ Some testing::
3660
+
3661
+ sage: a = 49850651047495986645822557378918223
3662
+ sage: b = 21049438014429831351540675253466229
3663
+ sage: p = 54283205379427155782089046839411711
3664
+ sage: E = EllipticCurve(GF(p),[a, b])
3665
+ sage: P = E.random_point()
3666
+ sage: Q = randrange(0, p-1) * P
3667
+ sage: x = P.padic_elliptic_logarithm(Q, p)
3668
+ sage: x*P == Q
3669
+ True
3670
+ """
3671
+ E = self .curve ()
3672
+ F = E .base ()
3673
+
3674
+ if Q .is_zero ():
3675
+ k = 0
3676
+ else :
3677
+ for k in range (0 ,p ):
3678
+ Eqp = EllipticCurve (Qp (p , 2 ), [ ZZ (t ) + k * p for t in E .a_invariants () ])
3679
+
3680
+ P_Qps = Eqp .lift_x (ZZ (self .xy ()[0 ]), all = True )
3681
+ for P_Qp in P_Qps :
3682
+ if F (P_Qp .xy ()[1 ]) == self .xy ()[1 ]:
3683
+ break
3684
+
3685
+ Q_Qps = Eqp .lift_x (ZZ (Q .xy ()[0 ]), all = True )
3686
+ for Q_Qp in Q_Qps :
3687
+ if F (Q_Qp .xy ()[1 ]) == Q .xy ()[1 ]:
3688
+ break
3689
+
3690
+ pP = p * P_Qp
3691
+ pQ = p * Q_Qp
3692
+ if (pP .is_zero () or pQ .is_zero ()):
3693
+ # Should happen with probability 1/p
3694
+ continue
3695
+ else :
3696
+ break
3697
+
3698
+ x_P ,y_P = pP .xy ()
3699
+ x_Q ,y_Q = pQ .xy ()
3700
+
3701
+ phi_P = - (x_P / y_P )
3702
+ phi_Q = - (x_Q / y_Q )
3703
+ k = phi_Q / phi_P
3704
+
3705
+ return ZZ (k % p )
3706
+
3610
3707
def has_finite_order (self ):
3611
3708
r"""
3612
3709
Return ``True`` if this point has finite additive order as an element
0 commit comments