2 This program is free software
; you can redistribute it and/or modify
3 it under the terms of the GNU General Public License as published by
4 the Free Software Foundation
; either version 2 of the License, or
5 (at your option
) any later version.
7 This program is distributed in the hope that it will be useful
,
8 but WITHOUT ANY WARRANTY
; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
12 You should have received a copy of the GNU General Public License
13 along with this program
; if not, write to the Free Software
14 Foundation
, Inc.
, 51 Franklin Street
, Fifth Floor
, Boston
,
18 *** Elliptic Curves
*********************************************************
20 Copyright Volker van Nek
, 2015
22 This file contains some algorithms for elliptic curves over prime fields.
25 ec_set_curve
, ec_add
, ec_mult
, ec_random
, ec_point_p
, ec_point_order
,
26 ec_log
, ec_twist_curve
, ec_trace
29 ec_balanced
, ec_sea_verbose
31 (The SEA-implementation also contains test functions at Maxima level.
)
33 The computation of the trace takes some time for characteristics larger than
34 112 bit and the user should consider to compile this file. The database of
35 modular polynomials is limited and for parameters larger than
256 bit it is
36 recommended to use pari
/gp.
40 (%i1
) load
("elliptic_curves")$
42 (%i2
) p
: 4451685225093714772084598273548427$
44 (%i4
) b
: 2061118396808653202902996166388514$
45 (%i5
) ec_set_curve
(p,a
,b
)$
47 This is curve secp112r1.
49 (%i6
) ord
: p
+ 1 - ec_trace
();
50 (%o6
) 4451685225093714776491891542548933
54 The order is a prime number and every random curve point is a generator.
56 (%i8
) pt
: ec_random
()$
57 (%i9
) is
(ec_point_order(pt, ord
) = ord
);
60 The point at infinity is ec_inf.
62 (%i10
) ec_mult
(ord, pt
);
68 *ec-a
* *ec-b
* *ec-p
* *ec-inv2
* *ec-set?
*
69 *ec-g
* *ec-g1
* *ec-sea-data?
*
70 *ec-psi
* *ec-psi-i
* *ec-psi-red
* *ec-psi2
* *ec-psi3
*
72 *gf-char
* *ef-arith?
* ))
74 (defmvar $ec_balanced nil
"point coordinates are balanced?")
75 (defmvar $ec_sea_verbose nil
"print splitting type and traces")
79 ;; define a curve over a prime field (as global variables)
81 (defmfun $ec_set_curve
(p a b
)
82 (let ((fn "ec_set_curve"))
83 (unless (and (integerp p
) (integerp a
) (integerp b
))
84 (gf-merror (intl:gettext
"`~m': Arguments must be a integers.") fn
) )
85 (unless (and (primep p
) (> p
3))
86 (gf-merror (intl:gettext
87 "`~m': First argument must be a prime number greater than 3. Found ~m." ) fn p
) )
88 (if (= 0 (mod (+ (* 4 a a a
) (* 27 b b
)) p
))
93 *ec-inv2
* (inv-mod 2 p
)
98 (gf-merror (intl:gettext
"`~m': The curve is not defined yet.") fun
) ))
101 ;; convert between Maxima and Lisp level
103 (defun ec-m2l (pt_m fn
)
106 ((equal pt_m
'$ec_inf
) nil
) ;; neutral element, point of infinity (nil at Lisp level)
107 ((not (and ($listp pt_m
)
109 (every #'integerp pt
) ))
110 (gf-merror (intl:gettext
"`~m': Unsuitable argument: ~m") fn pt_m
) )
112 (mapcar #'(lambda (n) (mod n
*ec-p
*)) pt
) ))))
116 (cons '(mlist simp
) (ec-balance pt
))
119 (defun ec-balance (pt)
121 (mapcar #'(lambda (n) (if (< (ash *ec-p
* -
1) n
) (- n
*ec-p
*) n
)) pt
)
125 ;; point addition (use affine coords at Maxima level, projective at Lisp level)
127 (defmfun $ec_add
(pt qt
)
130 (setq pt
(ec-projectify (ec-m2l pt fn
))
131 qt
(ec-projectify (ec-m2l qt fn
)) )
132 (ec-l2m (ec-affinify (ec-padd pt qt
))) ))
135 ;; point multiplication
137 (defmfun $ec_mult
(n pt
)
138 (let ((fn "ec_mult"))
141 (gf-merror (intl:gettext
"`~m': First argument must be an integer.") fn
) )
142 (setq pt
(ec-projectify (ec-m2l pt fn
)))
143 (ec-l2m (ec-affinify (ec-pmult n pt
))) ))
146 ;; -------------------------------------------------------------------------- ;;
148 ;; arithmetic in affine coordinates
150 (defun ec-add (pt qt
)
154 ((equal pt qt
) (ec-double pt
))
155 ((eql (car pt
) (car qt
)) nil
) ;; erroneous if pt or qt is not on the curve
157 (xp (car pt
)) (yp (cadr pt
))
158 (xq (car qt
)) (yq (cadr qt
))
159 (m (zn-quo (- yq yp
) (- xq xp
) p
))
160 (xx (mod (- (* m m
) xq xp
) p
))
161 (yy (mod (- (* m
(- xp xx
)) yp
) p
)) )
164 (defun ec-double (pt)
167 ((= 0 (cadr pt
)) nil
)
169 (x (car pt
)) (y (cadr pt
))
170 (m (zn-quo (+ (* 3 x x
) *ec-a
*) (ash y
1) p
))
171 (xx (mod (- (* m m
) (ash x
1)) p
))
172 (yy (mod (- (* m
(- x xx
)) y
) p
)) )
175 (defun ec-mult (n pt
)
177 ((or (= 0 n
) (null pt
)) nil
)
179 (setq n
(- n
) pt
(ec-neg pt
))
184 (setq res
(ec-add pt res
))
185 (when (= 1 n
) (return res
)) )
187 pt
(ec-double pt
) )) )))
190 (when pt
(list (car pt
) (- *ec-p
* (cadr pt
)))) )
193 ;; arithmetic in projective coordinates ------------------------------------- ;;
195 (defun ec-projectify (pt)
200 (defun ec-affinify (pt)
201 (unless (= (caddr pt
) 0)
203 (i (inv-mod (caddr pt
) p
))
205 (x (mod (* ii
(car pt
)) p
))
206 (y (mod (* ii i
(cadr pt
)) p
)) )
209 (defun ec-pdouble (pt)
211 ((= (caddr pt
) 0) pt
)
214 (x1 (car pt
)) (y1 (cadr pt
)) (z1 (caddr pt
))
217 (l1 (if (= a -
3) ;; NIST curves have a = -3
218 (* 3 (- x1 z11
) (+ x1 z11
))
219 (+ (* 3 x1 x1
) (* a z11 z11
)) ))
220 (z3 (ash (* y1 z1
) 1))
221 (l2 (ash (* x1 y11
) 2))
222 (x3 (- (* l1 l1
) (ash l2
1)))
223 (l3 (ash (* y11 y11
) 3))
224 (y3 (- (* l1
(- l2 x3
)) l3
)) )
225 (list (mod x3 p
) (mod y3 p
) (mod z3 p
)) ))))
227 (defun ec-padd (pt qt
)
229 ((= (caddr pt
) 0) qt
)
230 ((= (caddr qt
) 0) pt
)
232 (x1 (car pt
)) (y1 (cadr pt
)) (z1 (caddr pt
))
233 (x2 (car qt
)) (y2 (cadr qt
)) (z2 (caddr qt
))
238 (l3 (mod (- l1 l2
) p
))
241 (l6 (mod (- l4 l5
) p
)) )
246 (let* ((l7 (+ l1 l2
))
248 (z3 (mod (* z1 z2 l3
) p
))
251 (x3 (mod (- (* l6 l6
) l733
) p
))
252 (l9 (- l733
(ash x3
1)))
253 (y3 (mod (* *ec-inv2
* (- (* l9 l6
) (* l8 l33 l3
))) p
)) )
254 (list x3 y3 z3
) ))))))
256 (defun ec-pmult (n pt
)
258 ((or (= 0 n
) (= (caddr pt
) 0)) (list 1 1 0))
260 (setq n
(- n
) pt
(ec-pneg pt
))
263 (do ((res (list 1 1 0))) (())
265 (setq res
(ec-padd pt res
))
266 (when (= 1 n
) (return res
)) )
268 pt
(ec-pdouble pt
) )) )
270 (ec-pmult-sliding-window n pt
) )))
273 (when pt
(list (car pt
) (- *ec-p
* (cadr pt
)) (caddr pt
))) )
275 (defun ec-pmult-sliding-window (n pt
)
276 (let* ((l (integer-length n
))
277 (k (cond ((<= l
64) 3)
282 (tab (ec-pmult-table pt k
))
283 (i (1- l
)) (s 0) (h 0)
289 (setq s
(max (1+ (- i k
)) 0))
290 (do () ((logbitp s n
)) (incf s
))
291 (setq h
(1+ (- i s
)))
292 (dotimes (j h
) (setq res
(ec-pdouble res
)))
293 (setq u
(ldb (byte h s
) n
))
294 (unless (= u
0) (setq res
(ec-padd res
(svref tab
(ash u -
1)))))
297 (setq res
(ec-pdouble res
))
300 (defun ec-pmult-table (pt k
)
301 (let* ((l (ash 1 (1- k
)))
302 (tab (make-array l
:element-type
'list
:initial-element nil
))
304 (pt2 (ec-pdouble pt
))
306 (setf (svref tab
0) pt
)
308 (setq pti
(ec-padd pti pt2
))
309 (setf (svref tab i
) pti
)
312 ;; -------------------------------------------------------------------------- ;;
315 ;; find random point on given curve
317 (defmfun $ec_random
()
318 (ec-set?
"ec_random")
319 (ec-l2m (ec-random)) ) ;; does not return $ec_inf
321 (defun ec-random () ;; does not return null
322 (do ((p *ec-p
*) (a *ec-a
*) (b *ec-b
*)
325 (setq x
($random p
) ;; $random is set by set_random_state
326 y
(mod (+ (power-mod x
3 p
) (* a x
) b
) p
) )
328 (and (= 1 ($jacobi y p
))
329 (setq rts
(zn-nrt y
2 p
`((,p
1)))
330 y
(if (= 0 ($random
2)) (car rts
) (cadr rts
)) ))) ;; y#0, p>3: 2 solutions
331 (return (list x y
)) )))
334 ;; check if point is on the current curve
336 (defun $ec_point_p
(pt)
337 (let ((fn "ec_point_p"))
340 ((equal pt
'$ec_inf
) t
)
341 (t (ec-point-p (ec-m2l pt fn
))) )))
343 (defun ec-point-p (pt) ;; check only non-infinite points
345 (x (car pt
)) (y (cadr pt
)) )
347 (mod (+ (power-mod x
3 p
) (* *ec-a
* x
) *ec-b
*) p
) )))
350 ;; order of a point (as a factor of a given group order)
352 (defmfun $ec_point_order
(pt ord
&optional fs-ord
)
353 (let ((fn "ec_point_order"))
355 (setq pt
(ec-m2l pt fn
))
356 (unless (ec-point-p pt
)
357 (gf-merror (intl:gettext
358 "`~m': [~m,~m] is no curve point." ) fn
(car pt
) (cadr pt
)) )
359 (unless (and (integerp ord
) (> ord
0))
360 (gf-merror (intl:gettext
361 "`~m': Second argument must be a positive integer. Found ~m." ) fn ord
) )
363 (if (and ($listp fs-ord
) (setq fs-ord
(cdr fs-ord
))
364 (every #'$listp fs-ord
) )
365 (setq fs-ord
(mapcar #'cdr fs-ord
))
366 (gf-merror (intl:gettext
367 "Third argument to `~m' must be of the form [[p1, e1], ..., [pk, ek]]." ) fn
))
368 (setq fs-ord
(let (($intfaclim
)) (get-factor-list ord
))) )
369 (ec-point-order pt ord fs-ord
) ))
371 (defun ec-point-order (pt ord fs-ord
)
372 (setq pt
(ec-projectify pt
))
373 (let ((s ord
) qt fp fe
)
377 s
(truncate s
(expt fp fe
)) )
379 (setq qt
(ec-pmult s pt
))
380 (when (= (caddr qt
) 0) (return))
381 (setq qt
(ec-pmult fp qt
)
385 ;; discrete logarithm (simple baby-giant-variant, p < 2^36)
387 (defmfun $ec_log
(pt gen
)
390 (when (> (integer-length *ec-p
*) 36)
391 (gf-merror (intl:gettext
392 "`~m': The characteristic should not exceed a length of 36 bit." ) fn
) )
393 (setq pt
(ec-m2l pt fn
)
394 gen
(ec-m2l gen fn
) )
395 (ec-dlog-baby-giant pt gen
*ec-p
*) ))
397 (defun ec-dlog-baby-giant (pt gen p
)
398 (let* ((lim (+ p
2 (* 2 (isqrt p
))))
400 (s (floor (* 1.3 m
)))
401 (gi (ec-neg gen
)) ;; additive inverse
404 (make-hash-table :size s
:test
#'equal
:rehash-threshold
0.9) )
407 (setq b
(ec-add pt acc
))
408 (when (null b
) ;; point of infinity
410 (return-from ec-dlog-baby-giant r
) )
411 (setf (gethash b babies
) r
)
413 (when (= r m
) (return))
414 (setq acc
(ec-add gi acc
)) )
415 (setq mg
(ec-mult m gen
))
416 (do ((rr 1) (bb mg
) r
)
418 (when (setq r
(gethash bb babies
)) ;; points don't match if we would use projective coords
420 (return-from ec-dlog-baby-giant
(+ (* rr m
) r
)) )
422 (setq bb
(ec-add mg bb
)) )))
427 (defmfun $ec_twist_curve
()
428 (ec-set?
"ec_twist_curve")
429 (cons '(mlist simp
) (ec-twist-curve)) )
431 (defun ec-twist-curve ()
434 (do () ((= ($jacobi n p
) -
1))
437 a
(mod (* nn
*ec-a
*) p
)
438 b
(mod (* n nn
*ec-b
*) p
) )
442 ;; trace of Frobenius (ord = #E = p+1 - trace)
444 (defmfun $ec_trace
()
446 (let ((*gf-char
* *ec-p
*)
448 (ec-mueller-10-5 *ec-a
* *ec-b
* *ec-p
*) )) ;; naive, Shanks-Mestre or SEA
450 ;; *** SEA ****************************************************************** ;;
452 ;; This Lisp-implementation of the Schoof-Elkies-Atkin algorithm is based on
453 ;; Ein Algorithmus zur Bestimmung der Punktanzahl elliptischer
454 ;; Kurven ueber endlichen Koerpern der Charakteristic groesser drei
455 ;; by Volker Mueller.
456 ;; http://lecturer.ukdw.ac.id/vmueller/publications.php#thesis
458 ;; -------------------------------------------------------------------------- ;;
462 (defmfun $ec_j_invariant
() ;; test function
463 (ec-set?
"ec_j_invariant")
464 (ec-j-invariant *ec-a
* *ec-b
* *ec-p
*) )
466 (defun ec-j-invariant (a b p
)
467 (let ((a4aa (* 4 a a a
)))
468 (zn-quo (* 1728 a4aa
) (+ a4aa
(* 27 b b
)) p
) ))
470 ;; -------------------------------------------------------------------------- ;;
472 ;; modular polynomials ------------------------------------------------------ ;;
474 ;; We use precomputed Mueller and Atkin polynomials.
476 (defun ec-sea-data?
()
477 (unless (boundp '*ec-sea-data?
*)
478 ($load
"elliptic_curves/modular_polynomials.lisp") ))
480 ;; -------------------------------------------------------------------------- ;;
482 ;; -------------------------------------------------------------------------- ;;
484 ;; Mueller 7.3 [Computation of at,bt] (find isogenous curve)
486 (defmfun $ec_mueller_7_3
(l g
) ;; test function
487 (ec-set?
"ec_mueller_7_3")
492 (j (ec-j-invariant *ec-a
* *ec-b
* p
))
495 (setq gl
(svref *ec-g
* l
) f
'ec-mueller-7-3
) ;; Mueller modular poly
496 (setq gl
(svref *ec-g1
* l
) f
'ec-isogenous-from-atkin
) ) ;; Atkin modular poly
499 (apply f
(list l
(ec-gl-mod-p gl p
) g j
*ec-a
* *ec-b
* p
)) ))))
501 (defun ec-mueller-7-3 (l gl g j a b p
) ;; g is a root of gl(x,j). (-> ec-glj-roots)
502 (let* ((glx (ec-dx gl
))
504 (glxgj (ec-at-xy glx g j
))
505 (glygj (ec-at-xy gly g j
))
506 (glxxgj (ec-at-xy (ec-dx glx
) g j
))
507 (glxygj (ec-at-xy (ec-dy glx
) g j
))
508 (glyygj (ec-at-xy (ec-dy gly
) g j
))
509 ;; choose s minimal, so that s*(l-1)/12 is an integer (page 58):
510 (ggt (gcd (1- l
) 12)) ;; 12/s
511 (s (truncate 12 ggt
))
512 (s/12 (inv-mod ggt p
))
516 (delta (zn-quo (* e4 e4 e4
) j p
)) ;; = (e4^3 - e6^2)/1728
517 (deltal (zn-quo (* delta
(power-mod g ggt p
)) (power-mod l
12 p
) p
))
519 (dg (mod (* g glxgj
) p
)) ;; DF in Mueller 7.3
520 (dj (mod (* j glygj
) p
)) )
523 ;; remark 7.2, page 110:
524 ;; p = 65537, a = 1, b = 33965, l = 19 => j = 19797, roots = [24273,1616]
525 ;; with g = 24273 we have dj = 0
527 (let* ((e4l (zn-quo e4
(* l l
) p
))
528 (at (mod (* -
3 e4l
(power-mod l
4 p
)) p
))
529 (jl (zn-quo (* e4l e4l e4l
) deltal p
))
530 (e6l (car (zn-nrt (* (- jl
1728) deltal
) 2 p
)))
531 ;; Mueller suggests to return the neg. and pos. root (step 6).
532 ;; Do we need two solutions?
533 ;; The above example results the same trace = 3 mod 19 for both roots.
534 (bt (mod (* 2 e6l
(power-mod l
6 p
)) p
))
539 (let* ((e2* (zn-quo (* -
12 e6 dj
) (* s e4 dg
) p
))
540 (e0 (zn-quo e6
(* e4 e2
*) p
))
541 (gq (mod (* -
1 s
/12 e2
* g
) p
))
542 (jq (zn-quo (* -
1 e4 e4 e6
) delta p
))
544 (dgq (mod (+ (* gq glxgj
) (* g
(+ (* gq glxxgj
) (* jq glxygj
)))) p
))
545 (djq (mod (+ (* jq glygj
) (* j
(+ (* jq glyygj
) (* gq glxygj
)))) p
))
547 (e0q (zn-quo (- (* -
1 s
/12 dgq
) (* e0 djq
)) dj p
))
548 (tmp (+ (* 12 e0q
(inv-mod e0 p
)) (- (* 6 e4 e4
(inv-mod e6 p
)) (* 4 e6
(inv-mod e4 p
)))))
549 (e4l (zn-quo (+ e4
(* e2
* (- e2
* tmp
))) (* l l
) p
))
550 (jl (zn-quo (* e4l e4l e4l
) deltal p
))
551 (ff (zn-quo (power-mod l s p
) g p
))
552 (fq (mod (* s
/12 e2
* ff
) p
))
554 (dg2 (ec-at-xy glx ff jl
))
555 (dj2 (ec-at-xy gly ff jl
))
557 (jlq (zn-quo (* -
1 fq dg2
) (* l dj2
) p
))
558 (e6l (if (= e4l
0) 0 (zn-quo (* -
1 e4l jlq
) jl p
)))
559 ;; TODO: case e4l = 0: e6l = ?
560 ;; e.g. [a,b,p,l]:[625,41,907,7] (one-root-case)
562 (at (mod (* -
3 e4l
(power-mod l
4 p
)) p
))
563 (bt (mod (* -
2 e6l
(power-mod l
6 p
)) p
))
564 (p1 (zn-quo (* -
1 l e2
*) 2 p
)) )
565 (values at bt p1
) )))))
569 ;; x? and y? indicate whether this variable is present,
570 ;; e.g. if y? is nil then f is effectively a univariate poly in x.
572 ;; The global *gf-char* is used for reduction.
574 (defun ec-at-y (f x? y
)
577 (x?
(do ((itr f
(cddr itr
)) res cy
)
580 (when (consp cy
) (setq cy
(gf-at cy y
)))
581 (setq res
(nconc res
(list (car itr
) cy
))) ))
584 (defun ec-at-x (f x y?
)
587 (y?
(do ((res nil
) cy xx
) (())
589 (unless (consp cy
) (setq cy
(list 0 cy
)))
590 (setq res
(gf-nplus res cy
))
591 (when (null (cddr f
))
592 (setq xx
(gf-cpow x
(car f
)))
593 (return (gf-xctimes res xx
)) )
594 (setq xx
(gf-cpow x
(- (car f
) (caddr f
)))
595 res
(gf-xctimes res xx
)
599 (defun ec-at-xy (f x y
)
601 (ec-at-x (ec-at-y f t y
) x nil
) ))
603 ;; partial derivatives:
606 (do ((itr f
(cddr itr
)) res e cy
)
609 (when (= e
0) (return res
))
611 cy
(if (consp cy
) (gf-xctimes cy e
) (gf-ctimes e cy
)) )
612 (setq res
(nconc res
(list (1- e
) cy
))) ))
615 (do ((itr f
(cddr itr
)) res cy
)
619 (setq cy
(gf-diff cy
))
620 (when (= 0 (car cy
)) (setq cy
(cadr cy
)))
621 (setq res
(nconc res
(list (car itr
) cy
)) ))))
623 ;; For l > 43 a lot of mueller polynomials have sizes of more than 100 kB.
624 ;; We use Atkin polynimials instead. Mueller 7.3 needs some modifications.
625 ;; These are copied from pari-gp/src/modules/ellsea.c/find_isogenous_from_Atkin
628 (defun ec-isogenous-from-atkin (l gl g j a b p
) ;; g is a root of gl(x,j)
629 (let* ((glx (ec-dx gl
))
631 (glxgj (ec-at-xy glx g j
))
632 (glygj (ec-at-xy gly g j
))
633 (glxxg (ec-at-x (ec-dx glx
) g t
))
634 (glxyg (ec-at-x (ec-dy glx
) g t
))
635 (glyyg (ec-at-x (ec-dy gly
) g t
))
638 (dg (mod (* g glxgj
) p
)) ;; dx in pari-gp
639 (dj (mod (* j glygj
) p
)) ;; dJ
640 (aa (mod (* dj g e6
) p
))
641 (bb (mod (* dg e4
) p
))
642 gp u1 pg
* dg
* pj
* dj
* u v e4t e6t u2 p1 at bt fc ck wp
)
643 (when (or (= aa
0) (= bb
0)) (return-from ec-isogenous-from-atkin
(values)))
644 (setq gp
(zn-quo aa bb p
) ;; gprime
645 u1
(ec-compute-u gp glxxg glxyg glyyg j glygj glxgj
1 e4 e6 p
) )
646 (dolist (jt (ec-glg-roots gl g p
))
647 (setq pg
* (ec-at-xy glx g jt
)
648 dg
* (mod (* g pg
*) p
)
649 pj
* (ec-at-xy gly g jt
)
650 dj
* (mod (* jt l pj
*) p
)
651 u
(mod (* dg
* dj e6
) p
)
652 v
(mod (* dj
* dg e4
) p
)
653 e4t
(zn-quo (* u u jt
) (* v v
(- jt
1728)) p
)
654 e6t
(zn-quo (* u e4t
) v p
)
655 u2
(ec-compute-u gp glxxg glxyg glyyg jt pj
* pg
* l e4t e6t p
)
656 p1
(mod (* 3 l
(- u1 u2
)) p
)
657 at
(mod (* -
3 (power-mod l
4 p
) e4t
) p
)
658 bt
(mod (* -
2 (power-mod l
6 p
) e6t
) p
) )
659 (multiple-value-setq (fc ck wp
) (ec-mueller-7-8 l at bt p1 ck wp a b p
))
660 (ec-set-div-poly-mod l l fc a b p
)
661 (when (null (svref *ec-psi
* l
))
662 (return (values at bt fc
)) ))))
664 (defun ec-compute-u (gp glxxg glxyg glyyg j glygj glxgj q e4 e6 p
)
665 (let* ((glxxgj (ec-at-y glxxg nil j
))
666 (glxygj (ec-at-y glxyg nil j
))
667 (glyygj (ec-at-y glyyg nil j
))
668 (e6/e4
(zn-quo e6 e4 p
))
669 (aa (mod (* gp glxxgj
) p
))
670 (bb (mod (* 2 j q glxygj e6
/e4
) p
))
671 (cc (mod (* (zn-quo (* e6
/e4 e6
/e4
) gp p
) j
) p
))
672 (dd (mod (* cc q q
(+ glygj
(* j glyygj
))) p
))
673 (ee (mod (- (zn-quo e6
/e4
3 p
) (zn-quo (* e4 e4
) (* 2 e6
) p
)) p
))
674 (ff (mod (- bb aa dd
) p
)) )
675 (mod (+ (zn-quo ff glxgj p
) (* ee q
)) p
) ))
677 (defun ec-glg-roots (gl g p
)
678 (let ((glg (ec-at-x gl g t
))
680 (setq glg
(gf-xctimes glg
(inv-mod (cadr glg
) p
)) ;; monicize poly
681 x^p
(gf-pow-sliding-window (list 1 1) p glg
)
682 ggt
(gf-gcd (gf-plus x^p
(list 1 (1- p
))) glg
) )
683 (ec-extract-roots (gf-equal-degree-factors (list ggt
1) p
1) p
) ))
685 ;; -------------------------------------------------------------------------- ;;
687 ;; division polynomials ----------------------------------------------------- ;;
689 ;; Mueller, definition 4.11, page 39
691 (defun ec-set-div-poly-mod (cap n red a b p
)
692 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
693 (when (< n
4) (setq n
4))
695 (cub (cond ((= 0 a
) (list 3 1 0 b
))
696 ((= 0 b
) (list 3 1 1 a
))
697 (t (list 3 1 1 a
0 b
)) ))
698 (psi (setf *ec-psi
* (make-array (+ cap
3) :element-type
'list
:initial-element nil
)))
699 (psi2 (setf *ec-psi2
* (make-array (+ cap
3) :element-type
'list
:initial-element nil
)))
700 (psi3 (setf *ec-psi3
* (make-array (+ cap
3) :element-type
'list
:initial-element nil
))) )
701 (setf *ec-poly
* (gf-nred cub red
)
702 *ec-poly2
* (gf-sq *ec-poly
* red
)
704 ;; (svref psi 0) nil ;; 0
705 (svref psi
1) (list 0 1) ;; 1
706 (svref psi
2) (list 0 2) ;; 2
707 (svref psi
3) ;; 3*x^4+6*a*x^2+12*b*x-a^2
708 (gf-nred (gf-mod (list 4 3 2 (* 6 a
) 1 (* 12 b
) 0 (- aa
))) red
)
709 (svref psi2
1) (list 0 1)
710 (svref psi2
2) (list 0 (mod 4 p
))
711 (svref psi3
1) (list 0 1)
712 (svref psi3
2) (list 0 (mod 8 p
))
713 (svref psi
4) ;; 4*x^6+20*a*x^4+80*b*x^3-20*a^2*x^2-16*a*b*x-4*a^3-32*b^2
714 (gf-nred (gf-mod (list 6 4 4 (* 20 a
) 3 (* 80 b
) 2 (- (* 20 aa
)) 1 (- (* 16 a b
)) 0 (- (+ (* 32 b b
) (* 4 a aa
))))) red
)
715 (svref psi2
3) (gf-sq (svref psi
3) red
)
716 (svref psi3
3) (gf-times (svref psi
3) (svref psi2
3) red
) )
718 (ec-set-div-poly-mod1 n cap
) ))
720 (defun ec-set-div-poly-mod1 (n cap
)
721 (do ((i (1+ *ec-psi-i
*) (1+ i
)))
722 ((> i n
) (when (> n
*ec-psi-i
*) (setq *ec-psi-i
* n
)))
723 (ec-set-psi i cap
) ))
725 (defun ec-set-psi (i cap
)
726 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
737 (setf (svref psi3
(1+ j
)) (gf-ktimes (svref psi
(1+ j
)) (svref psi2
(1+ j
)) red
)) )
738 ;; f[j] * (f[j+2]*f[j-1]^2 - f[j-2]*f[j+1]^2) / 2
742 (gf-plus (gf-ktimes (svref psi
(+ j
2)) (svref psi2
(1- j
)) red
)
743 (gf-nminus (gf-ktimes (svref psi
(- j
2)) (svref psi2
(1+ j
)) red
)) ) red
)
747 (setf (svref psi2
(+ j
2)) (gf-ksq (svref psi
(+ j
2)) red
)) )
749 ;; cub^2*f[j+2]*f[j]^3 - f[j-1]*f[j+1]^3
751 (gf-ktimes (svref psi
(+ j
2)) (svref psi3 j
) red
)
753 (gf-nminus (gf-ktimes (svref psi
(1- j
)) (svref psi3
(1+ j
)) red
)) )
754 ;; f[j+2]*f[j]^3 - cub^2*f[j-1]*f[j+1]^3
755 (gf-plus (gf-ktimes (svref psi
(+ j
2)) (svref psi3 j
) red
)
756 (gf-nminus (gf-ktimes
757 (gf-ktimes (svref psi
(1- j
)) (svref psi3
(1+ j
)) red
)
760 ;; Karatsuba splitting:
762 ;; x*y = (x1*b^(n/2) + x0) * (y1*b^(n/2) + y0) =
764 ;; x1*y1*(b^n - b^(n/2)) + (x0+x1)*(y0+y1)*b^(n/2) + x0*y0*(1 - b^(n/2))
766 (defun gf-ktimes (x y red
)
767 (declare (optimize (speed 3) (safety 0)))
768 (unless (or (null x
) (null y
))
769 (let ((n (max (car x
) (car y
))))
772 ((< n
24) (gf-times x y red
))
774 (when (logbitp 0 n
) (incf n
))
775 (gf-nktimes (copy-list x
) (copy-list y
) n red
) )))))
777 (defun gf-nktimes (x y n red
) ;; modify x
778 (declare (optimize (speed 3) (safety 0)))
781 ((< n
24) (gf-times x y red
))
783 (when (logbitp 0 n
) (incf n
))
784 (let (x1 x0 y1 y0 z1 z0 zz
(n/2 (ash n -
1)))
785 (multiple-value-setq (x1 x0
) (gf-nsplit x n
/2))
786 (multiple-value-setq (y1 y0
) (gf-nsplit y n
/2))
787 (setq z1
(gf-times x1 y1 red
)
788 z1
(gf-nplus (gf-nxetimes (copy-list z1
) n
) (gf-nminus (gf-nxetimes z1 n
/2)))
789 z0
(gf-times x0 y0 red
)
790 z0
(gf-nplus (copy-list z0
) (gf-nminus (gf-nxetimes z0 n
/2)))
791 zz
(gf-nxetimes (gf-times (gf-nplus x0 x1
) (gf-nplus y0 y1
) red
) n
/2) )
792 (gf-nred (gf-nplus (gf-nplus z0 z1
) zz
) red
) ))))
794 ;; x^2 = (z1*b^(n/2) + z0)^2 = b^n*z1^2 + 2*b^(n/2)*z0*z1 + z0^2
796 ;; where the characteristic is assumed to be odd
798 (defun gf-ksq (x red
)
799 (declare (optimize (speed 3) (safety 0)))
804 ((< n
16) (gf-sq x red
))
806 (when (logbitp 0 n
) (incf n
))
807 (gf-nksq (copy-list x
) n red
) )))))
809 (defun gf-nksq (x n red
) ;; modify x
810 (declare (optimize (speed 3) (safety 0)))
813 ((< n
16) (gf-sq x red
))
815 (when (logbitp 0 n
) (incf n
))
816 (let (z1 z0 zz
(n/2 (ash n -
1)))
817 (multiple-value-setq (z1 z0
) (gf-nsplit x n
/2))
820 (gf-nred (gf-nksq z0 n
/2 red
) red
) )
822 (gf-nred (gf-nxetimes (gf-nksq z1 n
/2 red
) n
) red
) )
824 (setq zz
(gf-xectimes (gf-times z1 z0 red
) n
/2 2)
825 z0
(gf-nksq z0 n
/2 red
)
826 z1
(gf-nxetimes (gf-nksq z1 n
/2 red
) n
))
827 (gf-nred (gf-nplus (gf-nplus z0 z1
) zz
) red
) ))))))
829 (defun gf-nsplit (x n
) ;; modify x
830 (declare (optimize (speed 3) (safety 0)))
836 (when (< (the fixnum
(car x
)) n
) (return (values nil x
)))
837 (rplaca x
(- (the fixnum
(car x
)) n
))
840 (when (null (cdr r
)) (return (values x nil
)))
841 (when (< (the fixnum
(cadr r
)) n
)
844 (return (values x r0
)) )
846 (rplaca r
(- (the fixnum
(car r
)) n
))
850 ;; -------------------------------------------------------------------------- ;;
852 ;; -------------------------------------------------------------------------- ;;
854 ;; Mueller 7.8 [Computation of f_C]
856 (defmfun $ec_mueller_7_8
(l at bt p1
) ;; test function
857 (ec-set?
"ec_mueller_7_8")
858 (let ((*gf-char
* *ec-p
*)
860 (gf-x2p (ec-mueller-7-8 l at bt p1 nil nil
*ec-a
* *ec-b
* *ec-p
*)) ))
862 (defun ec-mueller-7-8 (l at bt p1 ck wpv a b p
)
863 (let* ((d (ash (- l
1) -
1))
864 (d1 (1+ d
)) ;; step 1
865 (l3 (1+ (ash (- l
3) -
1)))
868 ;; ck,wp do not depend on at,bt,p1 and can be reused in a second run
869 (setq ck
(ec-ck l3 a b p
) ;; 2,3
870 wpv
(ec-wpv d1 l3 ck
) )) ;; 4-6
871 (setq ctk
(ec-ck l3 at bt p
) ;; 8,9
872 hlp
(ec-hlp l l3 ck ctk p1 p
) ;; 10, second sum
873 h
(ec-h-init d1 hlp p
) ;; 10
874 fc
(ec-fc d h wpv p
) ) ;; 11-14
875 (values fc ck wpv
) ))
877 ;; Lemma 6.2, Mueller, page 90:
879 (defun ec-ck (ll a b p
)
880 (let ((ck (make-array (1+ ll
) :element-type
'integer
)))
881 (when (> ll
0) (setf (svref ck
1) (zn-quo (- p a
) 5 p
)))
882 (when (> ll
1) (setf (svref ck
2) (zn-quo (- p b
) 7 p
)))
886 (setf (svref ck k
) 0)
887 (do ((i 1 (1+ i
)) (k1 (1- k
)))
890 (+ (svref ck k
) (* (svref ck i
) (svref ck
(- k
1 i
)))) ))
892 (zn-quo (* 3 (svref ck k
)) (* (- k
2) (+ (* 2 k
) 3)) p
) )))
897 (defun ec-wpv (d1 l3 ck
)
898 (let ((wp (make-array d1
:element-type
'list
:initial-element nil
))
899 (red (list d1
1)) ;; reduce by x^(d+1), remainder has necessary precision
900 (wp1 (ec-weierstrass l3 ck
)) ) ;; wp1(z), where z^2 is replaced by x
901 (setq wp1
(gf-nxetimes wp1
1)) ;; adjust exponents by z^2
902 (setf (svref wp
1) wp1
)
903 ;; store wpv(z) (with exponents adjusted)
907 (gf-times (svref wp
(1- v
)) wp1 red
) )) ))
909 (defun ec-weierstrass (l ck
)
910 (let ((wp (list -
1 1))) ;; contains 1/x
913 (push (svref ck k
) wp
)
917 ;; step 10: return sum(coeffs*x^k , k,1,(l-3)/2) - p1, where x = z^2
919 (defun ec-hlp (l l3 ck ctk p1 p
)
920 (let ((hlp (if (= p1
0) nil
(list 1 (- p p1
)))))
924 (setq tmp
(zn-quo (- (* l
(svref ck k
)) (svref ctk k
))
925 (* (+ twok
1) (+ twok
2)) p
) )
926 (when (/= tmp
0) (push tmp hlp
))
928 (when (/= tmp
0) (push k hlp
)) )))
930 ;; step 10: return h * x^d
932 (defun ec-h-init (d1 hlp p
)
933 (let ((red (list d1
1)) ;; reduce by x^(d+1)
940 hlp^r
(gf-times hlp^r hlp red
)
941 h
(gf-nplus h
(gf-xctimes hlp^r
(inv-mod r
! p
))) ))))
945 (defun ec-fc (d h wpv p
)
948 (do ((v (1- d
) (1- v
)))
950 (setq h
(gf-nplus h
(gf-xctimes (svref wpv
(1+ v
)) (- p av
)))
951 h
(gf-nxetimes h -
1) ;; h/x
953 fc
(nconc fc
(list v av
)) ))))
955 ;; -------------------------------------------------------------------------- ;;
957 ;; -------------------------------------------------------------------------- ;;
959 ;; Mueller 7.9 [Computation of c mod l]
961 (defmfun $ec_mueller_7_9
(l fc
) ;; test function
962 (ec-set?
"ec_mueller_7_9")
966 (ec-set-div-poly-mod l l fc
*ec-a
* *ec-b
* p
)
967 (multiple-value-bind (c alpha
) (ec-mueller-7-9 l
(gf-p2x fc
) p
)
968 (list '(mlist simp
) c alpha
) )))
970 (defun ec-mueller-7-9 (l fc p
)
971 (let* (;; steps 1,2: (ec-set-div-poly-mod called within ec-elkies)
975 (lx (gf-pow-sliding-window (list 1 1) p fc
))
978 (ly (gf-times (gf-xctimes cub
4)
979 (gf-pow-sliding-window cub
(ash (1- p
) -
1) fc
)
983 (do ((alpha 1 (1+ alpha
))
984 (l1 (1+ (ash (- l
1) -
1)))
986 ((= alpha l1
) (values))
988 (setq lhs
(gf-ktimes lx
(svref psi2 alpha
) fc
))
989 (when (evenp alpha
) (setq lhs
(gf-times cub lhs fc
)))
990 (when (equal lhs
(ec-rx alpha cub fc
))
992 (setq lhs
(gf-ktimes ly
(svref psi3 alpha
) fc
))
993 (when (evenp alpha
) (setq lhs
(gf-times cub lhs fc
)))
994 (setq ry
(ec-ry alpha cub fc
))
995 (when (or (equal lhs ry
)
996 (and (equal lhs
(gf-minus ry
)) (setq alpha
(- l alpha
))) )
997 (setq c
(+ alpha
(zn-quo p alpha l
)))
998 (return (values (mod c l
) alpha
)) )))))
1002 (defun ec-rx (n cub fc
) ;; n >= 1
1003 (let* ((psi *ec-psi
*)
1004 (r1 (gf-times (list 1 1) (svref *ec-psi2
* n
) fc
))
1005 (r2 (gf-nminus (gf-ktimes (svref psi
(1- n
)) (svref psi
(1+ n
)) fc
))) )
1007 (setq r1
(gf-times cub r1 fc
))
1008 (setq r2
(gf-times cub r2 fc
)) )
1013 (defun ec-ry (n cub fc
) ;; n >= 1
1014 (let* ((psi *ec-psi
*)
1016 (r1 (gf-ktimes (svref psi
(+ n
2)) (svref psi2
(1- n
)) fc
))
1017 (r2 (svref psi2
(1+ n
)))
1020 (setq r2
(gf-nminus (gf-ktimes (svref psi
(- n
2)) r2 fc
))) )
1021 (setq ry
(gf-nplus r1 r2
))
1022 (when (oddp n
) (setq ry
(gf-times cub ry fc
)))
1025 ;; sliding-window polynomial exponentiation using Karatsuba multiplication
1027 (defun gf-pow-sliding-window (x e red
)
1028 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
1029 (let* ((l (integer-length e
))
1030 (k (cond ((<= l
64) 3)
1035 (tab (gf-pow-sliding-window-table x k red
))
1036 (res (list 0 1)) s u tmp
)
1041 (setq s
(max (1+ (- i k
)) 0))
1042 (do () ((logbitp s e
)) (incf s
))
1043 (setq tmp
(1+ (- i s
)))
1044 (dotimes (h tmp
) (setq res
(gf-sq res red
)))
1045 (setq u
(ldb (byte tmp s
) e
))
1046 (unless (= u
0) (setq res
(gf-ktimes res
(svref tab
(ash u -
1)) red
)))
1049 (setq res
(gf-sq res red
))
1052 (defun gf-pow-sliding-window-table (x k red
)
1053 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
1054 (let* ((l (ash 1 (1- k
)))
1055 (tab (make-array l
:element-type
'list
:initial-element nil
))
1057 (x2 (gf-sq x red
)) )
1058 (setf (svref tab
0) x
)
1061 (setq xi
(gf-ktimes xi x2 red
))
1062 (setf (svref tab i
) xi
) )))
1064 ;; -------------------------------------------------------------------------- ;;
1066 ;; -------------------------------------------------------------------------- ;;
1068 ;; Mueller 8.4 [Computation of c mod l^i in the Elkies case]
1070 (defun ec-elkies-l^i
(i n l l1 gl tau1 i1_m iso1 a0 b0 a1 b1 a b p
)
1071 ;; E = [a0,b0] (passed through to ec-set-div-poly-mod),
1072 ;; the postfix 1 indicates the corresponding value of the last round.
1074 ;; Different from the steps 1-3 in Mueller 8.4 the polynomial gt is not
1075 ;; computed by Lemma 8.1. These steps are replaced by an algorithm from
1077 ;; Couveignes, Dewaghe, Morain - Isogeny cycles and the Schoof-Elkies-Atkin algorithm
1079 ;; 4.1 procedure ComputeTModLn
1081 ;; steps 1-2b done in ec-elkies
1084 ;; i) find next curve E11:
1085 (let* ((j (ec-j-invariant a b p
))
1086 (rts (ec-glj-roots l j p
))
1087 at bt p1 h11 ck wpv h11_m num iso11 h c tau11 l^i res
)
1089 (multiple-value-setq (at bt p1
) (ec-mueller-7-3 l gl g j a b p
))
1090 (unless (or (= at
0) (= bt
0))
1092 ;; ii) compute the isogeny, the factor h11 of psi_l(E11) and
1093 ;; iii) the new factor h of psi_l^(i+1)(E):
1094 (multiple-value-setq (h11 ck wpv
) (ec-mueller-7-8 l at bt p1 ck wpv a b p
))
1095 (setq h11_m
(gf-x2p h11
)
1096 num
(gf-p2x (meval `(($num
) (($substitute
) ,i1_m
'$x
,h11_m
)))))
1097 (ec-set-div-poly-mod l l num a1 b1 p
)
1098 (unless (null (svref *ec-psi
* l
))
1102 (setq iso11
(meval `(($substitute
) ,iso1
'$x
,i1_m
))
1103 h
(gf-p2x (meval `(($num
) (($substitute
) ,iso11
'$x
,h11_m
)))) ))
1105 ;; iv) find eigenvalue mod l^(i+1) by Mueller 8.4, steps 4-10:
1106 (multiple-value-setq (c tau11
) (ec-c-mod-l^i l1 l tau1 h a0 b0 p
))
1110 ((and (setq res
`(,l^i
(,c
)))
1114 (let* ((k11_m (gf-x2p (ec-k1 l a b at bt h11 p
)))
1115 (h11^
2_m
(gf-x2p (gf-sq h11 nil
)))
1116 (i11_m (meval `((mquotient) ,k11_m
,h11^
2_m
)))
1117 (lc (ec-elkies-l^i
(1+ i
) n l l^i gl tau11 i11_m iso11 a0 b0 a b at bt p
)) )
1118 (when lc
(setq res lc
) (return)) ))))))
1121 ;; 4.2. computing h1 and i1
1125 (defun ec-k1 (l a b at bt h1 p
)
1126 (let* ((ck (ec-ck l a b p
))
1127 (w (ec-weierstrass l ck
))
1128 (ckt (ec-ck l at bt p
))
1129 (w1 (ec-weierstrass l ckt
))
1131 (h1w^
2 (gf-sq (gf-compose w h1 red
) red
)) ;; reduce by x^l (x = z^2)
1132 (k1w (gf-times w1 h1w^
2 (list 1 1))) ;; reduce by x^1
1133 ;; now we know k1(w) = w1*h1(w)^2, but we want to know k1(x)
1135 ;; adjusting exponents:
1136 (val (gf-nxetimes k1w l
)) ;; x^l*k1w
1137 (arg (gf-nxetimes w
1)) ;; x*w
1139 ;; given two power series arg = w and val = k1(w)
1140 ;; we want to find a poly k1(x) such that val = k1(arg):
1143 (setq c
(car (last val
)) ;; c = coeff(val,x,0)
1144 k1x
(nconc k1x
(list i c
)) ) ;; k1x = k1x + c*x^i
1145 (when (= i
0) (return k1x
))
1146 (setq y
(gf-xctimes (gf-pow arg i
(list (1+ i
) 1)) (- p c
)) ;; y = - c*arg^i mod x^(i+1)
1147 val
(gf-nxetimes (gf-nplus val y
) -
1) )))) ;; val = (val + y)/x
1150 ;; Mueller 8.4, steps 4-10:
1152 (defun ec-c-mod-l^i
(l^i l alpha gt a0 b0 p
)
1153 ;; compute *ec-poly* and the division polynomials psi_0 to psi_l ...
1154 (ec-set-div-poly-mod (* l^i l
) l gt a0 b0 p
)
1155 (let ((psi *ec-psi
*)
1158 (x^p
(gf-pow-sliding-window (list 1 1) p gt
))
1162 (alphat alpha
(+ alphat l^i
)) )
1164 ;; ... and up to psi_{alphat+1} if necessary:
1165 (ec-set-div-poly-mod1 (1+ alphat
) (* l^i l
))
1167 (setq tmp
(gf-ksq (svref psi alphat
) gt
)
1168 rhs1
(gf-times (list 1 1) tmp gt
)
1169 rhs2
(gf-ktimes (svref psi
(1- alphat
)) (svref psi
(1+ alphat
)) gt
)
1170 lhs
(gf-ktimes x^p tmp gt
) )
1172 (setq lhs
(gf-times cub lhs gt
)
1173 rhs1
(gf-times cub rhs1 gt
) )
1174 (setq rhs2
(gf-times cub rhs2 gt
)) )
1175 (setq lhs
(gf-nplus lhs rhs2
)
1176 lhs
(gf-nplus lhs
(gf-nminus rhs1
)) )
1178 (when (> (car (gf-gcd lhs gt
)) 0)
1179 (setq l^i
(* l l^i
))
1180 (return (values (mod (+ alphat
(zn-quo p alphat l^i
)) l^i
) alphat
)) ))))
1182 ;; -------------------------------------------------------------------------- ;;
1184 ;; -------------------------------------------------------------------------- ;;
1186 ;; Mueller 9.2 [supersingularity]
1188 (defun ec-mueller-9-2 (p) ;; assume p > 3
1189 (ec-check-trace 0 p
) ) ;; prime fields: d = 1, m = p+1
1191 ;; Mueller 9.5 [j-invariants 0 and 1728]
1193 (defun ec-mueller-9-5 (b p
) ;; use only: d = 1
1195 (if (= b
0) ;; j = 1728 (mod p)
1196 (let ((x (* 2 (car (cornacchia 4 p
)))) ;; cornacchia replaces Mueller 9.4
1197 (i2 (cons 1 (cdr (zn-nrt -
1 2 p
)))) ;; 1,i
1199 (mapcar #'(lambda (n) (cmod (* x n
))) i2
) ) ;; symmetric mod
1201 (let ((x (* 2 (car (cornacchia 3 p
))))
1202 (om3 (zn-nrt 1 3 p
)) ;; 1,om,om^2
1204 (mapcar #'(lambda (n) (cmod (* x n
))) om3
) ))))
1205 (dolist (tr (nconc trs
(mapcar #'neg trs
)))
1206 ;; steps 8,15: check trace for "some" random points:
1207 (when (ec-check-trace tr p
) (return tr
)) )))
1209 ;; Blake,Seroussi,Smart - Elliptic Curves in Cryptography, Algorithm 8.1
1211 ;; compute a solution to x^2+d*y^2 mod p
1213 (defmfun $cornacchia
(d p
) ;; test function
1214 (let ((xy (cornacchia d p
)))
1215 (when xy
`((mlist simp
) ,@xy
)) ))
1217 (defun cornacchia (d p
)
1218 (let ((rts (zn-nrt (- p d
) 2 p
)))
1220 (let* ((rt (car rts
))
1221 (x (if (> (* 2 rt
) p
) (- p rt
) rt
))
1224 (do ((bound (isqrt p
)))
1226 (psetq h x x
(mod h x
)) )
1227 (setq h
(- p
(* x x
)))
1228 (multiple-value-bind (q r
) (truncate h d
)
1229 (when (or (/= r
0) (and (setq y
(isqrt q
)) (/= (* y y
) q
)))
1230 (return-from cornacchia nil
) ))
1233 ;; check trace for "some" random points:
1235 (defun ec-check-trace (tr p
)
1236 (let ((ord (- (1+ p
) tr
)))
1237 (dotimes (i 3 t
) ;; "some" = 3 (?)
1238 (unless (= (caddr (ec-pmult ord
(ec-projectify (ec-random)))) 0)
1241 ;; -------------------------------------------------------------------------- ;;
1243 ;; -------------------------------------------------------------------------- ;;
1245 ;; Mueller 10.1 [information about c mod l]
1248 ;; Compute the splitting type of gl(x,j) and call the appropriate subroutines.
1250 ;; Assume j # 0, j # 1728 and l < odd prime p.
1252 (defmfun $ec_mueller_10_1
(l) ;; l < p, test function
1253 (ec-set?
"ec_mueller_10_1")
1255 (let* ((p *ec-p
*) (a *ec-a
*) (b *ec-b
*)
1258 (j (ec-j-invariant a b p
))
1259 (res (ec-mueller-10-1 l j a b p
)) )
1260 `((mlist simp
) ,(car res
) ((mlist simp
) ,@(cadr res
))) ))
1262 (defun ec-mueller-10-1 (l j a b p
) ;; l < p
1263 (let (nr one-rt elkies len k
)
1265 (multiple-value-bind (rts gl glj x^p
) (ec-glj-roots l j p
)
1269 (when $ec_sea_verbose
(format t
"atkin : "))
1270 (ec-atkin l glj x^p p
) )
1271 ((= (setq nr
(length rts
)) 1)
1272 (when $ec_sea_verbose
(format t
"1 root: "))
1273 (setq one-rt
(ec-one-root l p
)
1274 elkies
(ec-elkies 1 l gl rts j a b p
) ) ;; ec-elkies might fail
1275 (if elkies elkies one-rt
) )
1277 (when $ec_sea_verbose
(format t
"~d roots: " (1+ l
)))
1278 (ec-lp1-roots l p
) )
1281 (when $ec_sea_verbose
(format t
"elkies: "))
1282 (setq len
(integer-length p
)
1285 ((= l
3) (if (< len
128) 3 4))
1286 ((= l
5) (if (< len
192) 2 3))
1288 ((= l
11) (if (< len
160) 1 2))
1289 ((= l
13) (if (< len
192) 1 2))
1291 (ec-elkies k l gl rts j a b p
) )))))
1294 (defmfun $ec_glj_roots
(l) ;; test function
1295 (ec-set?
"ec_glj_roots")
1300 (j (ec-j-invariant *ec-a
* *ec-b
* p
))
1301 (rts (ec-glj-roots l j p
)) )
1302 (when rts
(cons '(mlist simp
) rts
)) ))
1305 ;; Compute the splitting type of gl(x,j) and roots if there are any.
1307 (defun ec-glj-roots (l j p
)
1308 (let* (;; steps 1-3: use pre-computed polynomials instead
1309 (gl (ec-gl-mod-p (if (svref *ec-g
* l
)
1310 (svref *ec-g
* l
) ;; Mueller modular poly
1311 (svref *ec-g1
* l
) ) ;; Atkin modular poly
1314 (glj (ec-at-y gl t j
))
1315 (x^p
(gf-pow-sliding-window (list 1 1) p glj
))
1317 (ggt (gf-gcd (gf-plus x^p
(list 1 (1- p
))) glj
))
1320 (unless (= 0 (car ggt
))
1321 (setq rts
(ec-extract-roots (gf-equal-degree-factors (list ggt
1) p
1) p
)) )
1322 (values rts gl glj x^p
) ))
1324 (defun ec-gl-mod-p (gl p
) ;; gl = gl(x,y)
1325 (do ((itr gl
(cddr itr
)) res cy
)
1328 cy
(if (consp cy
) (gf-mod cy
) (mod cy p
)) )
1329 (setq res
(nconc res
(list (car itr
) cy
))) ))
1331 (defun ec-extract-roots (factors p
)
1332 (do ((fs factors
(cddr fs
)) fs1 len roots
)
1333 ((null fs
) (sort roots
#'<))
1337 ((= 4 len
) (push (- p
(car (last fs1
))) roots
))
1338 ((= 2 len
) (push 0 roots
)) )))
1340 ;; 10.1, steps 8-11 (the Elkies case)
1342 (defun ec-elkies (k l gl rts j a b p
)
1343 (let (at bt p1 fc ck wpv found res
)
1346 ((null (svref *ec-g
* l
)) ;; using Atkin modular poly:
1348 (multiple-value-setq (at bt fc
) (ec-isogenous-from-atkin l gl g j a b p
))
1349 (when at
(setq found t
)) )
1350 (t ;; using Mueller modular poly:
1352 (multiple-value-setq (at bt p1
) (ec-mueller-7-3 l gl g j a b p
))
1353 (unless (or (= at
0) (= bt
0)) ;; see example in ec-mueller-7-3
1355 (multiple-value-setq (fc ck wpv
) (ec-mueller-7-8 l at bt p1 ck wpv a b p
))
1356 (ec-set-div-poly-mod l l fc a b p
)
1357 (when (null (svref *ec-psi
* l
)) (setq found t
)) )))
1360 (multiple-value-bind (c alpha
) (ec-mueller-7-9 l fc p
)
1363 ((and (setq res
`(,l
(,c
)))
1367 (let* ((k1_m (gf-x2p (ec-k1 l a b at bt fc p
)))
1368 (h1^
2_m
(gf-x2p (gf-sq fc nil
)))
1369 (i1_m (meval `((mquotient) ,k1_m
,h1^
2_m
)))
1370 (iso (let ((modulus p
)) ($rat i1_m
)))
1371 (lc (ec-elkies-l^i
2 k l l gl alpha i1_m iso a b a b at bt p
)) )
1372 (when lc
(setq res lc
) (return)) ))))))
1375 ;; -------------------------------------------------------------------------- ;;
1377 ;; -------------------------------------------------------------------------- ;;
1379 ;; Mueller 10.2 [partial information] (the non-Elkies-case)
1383 (defun ec-one-root (l p
)
1384 (let ((rt (car (zn-nrt p
2 l
`((,l
1)))))
1386 (when rt
;; e.g. [a,b,p,l]:[233,38,9743,11] fails
1387 (setq h
(mod (* 2 rt
) l
))
1388 `(,l
(,h
,(- l h
))) )))
1392 (defun ec-lp1-roots (l p
)
1395 (setq ;; p (mod p ll)
1396 alpha
(car (zn-nrt p
2 ll
`((,l
2)))) )
1398 (setq h
(mod (+ alpha
(zn-quo p alpha ll
)) ll
))
1399 `(,ll
(,h
,(- ll h
))) )))
1401 ;; 10.2, steps 6-19 (the Atkin case) (l < p only):
1403 (defun ec-atkin (l glj x^p p
)
1407 (odd-inc (if (= ($jacobi p l
) 1) 0 1))
1408 ;; prepare computation in F_l^2:
1409 (n (do ((i 2 (1+ i
))) ((= ($jacobi i l
) -
1) i
))) ;; non-square mod l
1410 (ord (1- (* l l
))) ;; order of F_l^2
1412 (fs (get-factor-list ord
))
1413 (fs-ord (sort fs
#'< :key
#'car
))
1416 (dolist (d (nreverse (cddr (meval `(($divisors
) ,d-rest
)))))
1417 (when (evenp (+ (* (1- d
) (truncate d-rest d
)) odd-inc
))
1418 ;; evenp is effectively oddp when odd-inc is 1 resp. jacobi(p,l) # 1
1421 (if (= (length ds
) 1) ;; shortcut: just one possible d
1423 ;; here we compute d different from steps 9,15 in Mueller and use the
1424 ;; approach of pari-gp in src/modules/ellsea.c/study_modular_eqn (license GPL):
1425 (ec-comp-d l glj x^p p
) ))
1427 ;; steps 12,13, 18,19:
1430 (let ((*gf-char
* l
) ;; locally compute in F_l^2
1431 (red (list 2 1 0 (- l n
))) ;; reduction poly x^2 - n, n is non-square mod l
1432 (phi ($totient d
)) ;; number of possible traces
1433 gen gam gam^i g1 z rts
)
1434 (do ((i 1 (1+ i
))) (())
1435 (setq gen
(list 1 1 0 i
))
1436 (when (*f-prim-p-1 gen red ord fs-ord
) (return)) ) ;; gen is primitive element
1437 (setq gam
(gf-pow gen
(truncate ord d
) red
) ;; gam is d-th root of unity
1439 ;; compute the set of possible traces:
1440 (do ((i 1 (1+ i
)) (old-i 1) (nr 0))
1442 (when (= (gcd i d
) 1) ;; ord(gam^i) = d
1443 (setq gam^i
(gf-times gam^i
(gf-pow gam
(- i old-i
) red
) red
)
1445 g1
(if (= (length gam^i
) 4) (car (last gam^i
)) 0)
1446 z
(zn-quo (* p
(1+ g1
)) 2 l
) )
1447 (when (= ($jacobi z l
) 1)
1448 (setq rts
(zn-nrt z
2 l
`((,l
1))))
1450 (setq rt
(mod (* 2 rt
) l
))
1451 (unless (member rt cs
) (incf nr
) (push rt cs
)) ))))))
1452 (list l
(sort cs
#'<)) ))
1454 (defun ec-comp-d (l glj x^p p
)
1456 (cs (nreverse (gf-x2l (copy-list x^p
) lp1
)))
1459 (setf (nth 1 cs
) (if (= c
0) (1- p
) (1- c
)))
1460 (setq x^p^i
(mapcar #'list cs
))
1461 (do ((i 2 (1+ i
)) (acc x^p
))
1463 (setq acc
(gf-times acc x^p glj
)
1464 cs
(nreverse (gf-x2l acc lp1
))
1466 (setf (nth i cs
) (if (= c
0) (1- p
) (1- c
)))
1467 (mapcar #'nconc x^p^i
(mapcar #'list cs
)) )
1468 ;; now x^p^i is a coefficient-matrix of powers of x^p as columns, where the
1469 ;; (l+1)-identity-matrix is already subtracted and the first (zero) column omitted:
1470 (setq r
(zn-nrank x^p^i p
))
1471 (truncate lp1
(- lp1 r
)) ))
1473 (defun zn-nrank (m p
) ;; nulls m
1474 (do ((r 0) m1 row piv? piv inv c1
)
1476 (setq m1 nil piv? nil
)
1478 (setq row
(car m
) m
(cdr m
)
1483 (unless (every #'zerop row
) (push row m1
)) )
1485 (zn-naddrows row
(- p c1
) piv p
) ;; modify row
1486 (unless (null row
) (push row m1
)) )
1489 (setq piv row piv? t
1490 inv
(inv-mod c1 p
) )
1491 (zn-ncrow piv inv p
) ))) ;; modify piv
1494 (defun zn-ncrow (row c p
) ;; c*row mod p, modifies row
1495 (do ((itr row
(cdr itr
)))
1497 (rplaca itr
(mod (* c
(car itr
)) p
)) ))
1499 (defun zn-naddrows (row c piv p
) ;; row + c*piv mod p, modifies row, assumes len(row) = len(piv)
1500 (do ((itr row
(cdr itr
)))
1502 (rplaca itr
(mod (+ (car itr
) (* c
(car piv
))) p
))
1503 (setq piv
(cdr piv
)) ))
1505 ;; -------------------------------------------------------------------------- ;;
1507 ;; -------------------------------------------------------------------------- ;;
1509 ;; Mueller 10.4 [combination of the partial information]
1512 ;; Preprocessing: Computation of the two sets C_i with possible traces c mod m_i:
1515 ;; Algorithme de Nicolas pour le calcul de champions
1517 ;; This algorithm reduces the work of the baby-step-giant-step-phase to a minimum
1518 ;; by computing the optimal combination of given results from ec-atkin.
1519 ;; The return value is a list containing the number of remaining possible traces
1520 ;; and a binary pattern from which the combination can be recovered.
1522 ;; (see Reynald Lercier,
1523 ;; ALGORITHMIQUE DES COURBES ELLIPTIQUES DANS LES CORPS FINIS, 11.2.1)
1525 (defun ec-champions (cost profit atkin-bound
)
1527 ((= atkin-bound
0) nil
)
1528 ((= (length profit
) 1)
1529 (when (> (car profit
) atkin-bound
) (list 1 (car profit
))) )
1531 (setq cost
(coerce cost
'vector
)
1532 profit
(coerce profit
'vector
) )
1533 (let* ((k (array-dimension cost
0))
1534 (s (max 256 (ash 1 k
)))
1535 (a (make-array s
:element-type
'integer
:initial-element
0))
1536 (aq (make-array s
:element-type
'integer
:initial-element
0))
1538 (setf (svref aq
2) 1)
1540 (i 1 1) (i1 2 2) (i2 1 1)
1544 (setq b1
(svref aq i1
)
1545 b2
(logior (svref aq i2
) (ash 1 (1- j
))) )
1547 ((< (ec-pattern2val b1 profit k
) (ec-pattern2val b2 profit k
))
1553 (setq cst
(ec-pattern2val b cost k
))
1554 (while (< cst
(ec-pattern2val (svref a i
) cost k
)) (decf i
))
1556 (setf (svref a i
) b
) )
1558 (setq b
(logior (svref aq i2
) (ash 1 (1- j
)))
1559 cst
(ec-pattern2val b cost k
) )
1560 (while (< cst
(ec-pattern2val (svref a i
) cost k
)) (decf i
))
1562 (setf (svref a i
) b
)
1567 (setf (svref aq c
) (svref a c
)) ))
1568 (do ((i 1 (1+ i
)) res
)
1570 (when (/= 0 (svref a i
))
1571 (setq pro
(ec-pattern2val (svref a i
) profit k
))
1572 (when (>= pro atkin-bound
)
1573 (setq cst
(ec-pattern2val (svref a i
) cost k
))
1574 (when (or (null res
) (< cst
(cadr res
)))
1575 (setq res
(list (svref a i
) cst
)) )))) ))))
1577 (defun ec-pattern2val (pattern vec k
)
1578 (do ((i 0 (1+ i
)) (val 1))
1580 (when (logbitp i pattern
)
1581 (setq val
(* val
(svref vec i
))) )))
1583 ;; Lercier notes that the size of the two sets C_i should have a quotient of
1584 ;; about #C_babies = 3/4 #C_giants. Here 0.4 seems to be a better value.
1586 ;; ec-cm12 tries to split atkin accordingly.
1588 (defun ec-cm12 (atkin)
1589 (let* ((cost (mapcar #'length
(mapcar #'cadr atkin
)))
1590 (prod (apply #'* cost
)) ;; nb*ng = prod
1591 (p4 (* 0.45 prod
)) ;; nb = 0.45*ng => nb^2 = p4
1592 (delta prod
) ;; start value
1593 (clen (length cost
))
1594 (pattern 0) ;; baby set pattern
1596 h1 h2 l1 l2 m1 m2 c1 c2
)
1597 (setq cost
(coerce cost
'vector
))
1598 ;; find the pattern:
1599 (do ((i 1 (1+ i
)) (imax (ash 1 clen
)))
1601 (setq ilen
(integer-length i
)
1606 (setq nb
(* nb
(svref cost k
))
1607 d
(abs (- (* nb nb
) p4
)) ) ;; search for min(|nb^2 - p4|)
1611 pattern
(ldb (byte (1+ k
) 0) i
) )))))
1612 (setq n2
(truncate prod n1
))
1613 ;; recover the combination from the pattern:
1614 (do ((k 0 (1+ k
)) (itr atkin
(cdr itr
)))
1616 (if (logbitp k pattern
) (push (car itr
) h1
) (push (car itr
) h2
)) )
1617 ;; compute possible traces using CRT:
1618 (setq l1
(ec-combine-init (car h1
))
1620 l2
(ec-combine-init (car h2
))
1622 (dolist (h h1
) (setq l1
(ec-combine h l1
)))
1623 (dolist (h h2
) (setq l2
(ec-combine h l2
)))
1624 (setq m1
(apply #'* (car l1
))
1625 m2
(apply #'* (car l2
))
1626 c1
(mapcar #'(lambda (l) (car (chinese l
(car l1
)))) (cadr l1
))
1627 c2
(mapcar #'(lambda (l) (car (chinese l
(car l2
)))) (cadr l2
)) )
1628 (values c1 n1 m1 c2 n2 m2
) ))
1630 (defun ec-combine-init (l)
1631 `((,(car l
)) ,(mapcar #'list
(cadr l
))))
1633 (defun ec-combine (l1 l2
)
1634 (let ((mods (cons (car l1
) (car l2
))) res
)
1635 (dolist (r (cadr l1
) (list mods res
))
1636 (dolist (rs (cadr l2
))
1637 (push (cons r rs
) res
) ))))
1641 (defun ec-mueller-10-4 (elkies atkin p
)
1642 (let* ((cm3 (if elkies
;; elkies should always be non-null: (trace mod 2) is an elkies
1643 (chinese (mapcar #'caadr elkies
) (mapcar #'car elkies
))
1648 (bound (floor (* 4 (sqrt (coerce p
'double-float
)))))
1650 h mc1 c1 m1 inv-m3 c2 m2 c1-len c2-len inv-m2m3 inv-m1m3 m1
/2 )
1651 (dotimes (i 3 nil
) ;; step 19: if we fail after 3 tries we exit and change c3,m3
1652 (setq h
0) ;; step 2
1655 (setq h
(- c3
(* i m3
))) )
1658 (setq mc1
(car atkin
)
1661 inv-m3
(inv-mod m3 m1
)
1663 (let* ((pt (ec-random))
1664 (ptp (ec-projectify pt
))
1665 (q0 (ec-affinify (ec-pmult (- (1+ p
) c3
) ptp
)))
1666 (q1p (ec-pmult m3 ptp
))
1667 (q1 (ec-affinify q1p
))
1668 (q3 (ec-affinify (ec-pmult m1 q1p
)))
1671 ((null q0
) (setq h c3
))
1673 (setq q1
*2i
(ec-mult-table q1 m1
))
1675 (setq r1q
(- (mod (* (- x c3
) inv-m3
) m1
) m1
))
1676 (when (and (= x
0) ;; r1q = - m1
1677 (equal q0
(ec-neg q3
)) )
1678 (setq h
(- c3
(* m1 m3
)))
1680 (setq pt1
(ec-mult-by-table r1q q1 q1
*2i
))
1681 (when (equal q0 pt1
)
1682 (setq h
(- (+ c3
(* (+ r1q m1
) m3
)) (* m1 m3
)))
1684 (setq pt1
(ec-add pt1 q3
))
1685 (when (equal q0 pt1
)
1686 (setq h
(+ c3
(* (+ r1q m1
) m3
)))
1690 (multiple-value-setq (c1 c1-len m1 c2 c2-len m2
) (ec-cm12 atkin
))
1691 (setq inv-m2m3
(inv-mod (* m2 m3
) m1
)
1692 inv-m1m3
(inv-mod (* m1 m3
) m2
)
1697 (ptp (ec-projectify pt
))
1699 (q0 (ec-affinify (ec-pmult (- (1+ p
) c3
) ptp
)))
1700 (qhp (ec-pmult m3 ptp
))
1701 (q1p (ec-pmult m2 qhp
))
1702 (q1 (ec-affinify q1p
))
1703 (q2 (ec-affinify (ec-pmult m1 qhp
)))
1704 (q3 (ec-affinify (ec-pmult m1 q1p
)))
1707 r1q r1q-tab r1q0 dr1q pt1 q1
*2i
1708 r2q r2q-tab r2q0 dr2q pt2 q2
*2i
)
1709 (when (null q0
) (setq h c3 done t
))
1712 (setf r1q-tab
(make-array c1-len
:element-type
'integer
:initial-element
0)
1713 babies
(make-array c1-len
:element-type
'list
:initial-element nil
) )
1715 (setq r1q
(mod (* (- x c3
) inv-m2m3
) m1
))
1716 (setf (svref r1q-tab k
) (if (> r1q m1
/2) (- r1q m1
) r1q
))
1719 (setq q1
*2i
(ec-mult-table q1 m1
)
1720 r1q0
(svref r1q-tab
0)
1721 pt1
(ec-add q0
(ec-neg (ec-mult-by-table r1q0 q1 q1
*2i
)))
1723 (when (null pt1
) (setq h
(+ c3
(* r1q0 m2 m3
)) done t
))
1725 (setf (svref babies
0) (nconc pt1
(list r1q0
)))
1726 (do () ((= k c1-len
))
1727 (setq r1q
(svref r1q-tab k
)
1730 (setq pt1
(ec-add pt1
(ec-neg (ec-mult-by-table dr1q q1 q1
*2i
))))
1731 (when (null pt1
) (setq h
(+ c3
(* r1q0 m2 m3
)) done t
) (return))
1732 (setf (svref babies k
) (nconc pt1
(list r1q0
)))
1736 #'(lambda (a b
) (or (< (car a
)(car b
))
1737 (and (= (car a
)(car b
)) (< (cadr a
)(cadr b
))) ))))
1740 (setf r2q-tab
(make-array c2-len
:element-type
'integer
:initial-element
0))
1744 (setq r2q
(- (mod (* (- y c3
) inv-m1m3
) m2
) m2
))
1745 (when (= r2q
(- m2
))
1746 (when (and q3
(setq r1q
(ec-binary-pt-search q3 babies
)))
1747 (setq h
(- (+ c3
(* r1q m2 m3
)) (* m1 m2 m3
))
1750 (setf (svref r2q-tab k
) r2q
)
1755 (setq q2
*2i
(ec-mult-table q2 m2
)
1756 r2q0
(svref r2q-tab
0)
1757 pt2
(ec-mult-by-table r2q0 q2 q2
*2i
) )
1759 ((and pt2
(setq r1q
(ec-binary-pt-search pt2 babies
)))
1760 (setq h
(+ c3
(* r1q m2 m3
) (* r2q0 m1 m3
))) )
1761 ((and (setq tmp
(ec-add pt2 q3
))
1762 (setq r1q
(ec-binary-pt-search tmp babies
)) )
1763 (setq h
(+ c3
(* r1q m2 m3
) (* (+ r2q0 m2
) m1 m3
))) )
1767 (setq r2q
(svref r2q-tab k
)
1770 pt2
(ec-add pt2
(ec-mult-by-table dr2q q2 q2
*2i
)) )
1771 (when (and pt2
(setq r1q
(ec-binary-pt-search pt2 babies
)))
1772 (setq h
(+ c3
(* r1q m2 m3
) (* r2q m1 m3
)))
1774 (when (and (setq tmp
(ec-add pt2 q3
))
1775 (setq r1q
(ec-binary-pt-search tmp babies
)) )
1776 (setq h
(+ c3
(* r1q m2 m3
) (* (+ r2q m2
) m1 m3
)))
1780 ((> (abs h
) (ash bound -
1)) nil
)
1782 ((ec-check-trace h p
) h
)
1784 (t (let ((divs (cdr (meval `(($divisors
) ,h
)))))
1785 (setq divs
(delete h
(nconc divs
(mapcar #'neg divs
))))
1786 (dolist (d divs nil
)
1787 (when (ec-check-trace d p
) (return d
)) )))))
1788 (when h
(return h
)) )))
1789 ;; step 19: else return nil and change c3,m3
1792 (defun ec-binary-pt-search (pt a
)
1793 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
1794 (let ((px (car pt
)) (py (cadr pt
))
1796 (declare (fixnum m
))
1797 (do ((lo 0) (hi (1- (array-dimension a
0))))
1799 (declare (fixnum lo hi
))
1800 (setq m
(ash (+ lo hi
) -
1)
1804 ((< px x
) (setq hi
(1- m
)))
1805 ((> px x
) (setq lo
(1+ m
)))
1809 ((< py y
) (setq hi
(1- m
)))
1810 ((> py y
) (setq lo
(1+ m
)))
1812 (return (caddr am
)) )))))))
1815 (defun ec-mult-by-table (n pt pt
*2i
)
1817 ((or (= 0 n
) (null pt
)) nil
)
1818 ((< n
0) (ec-neg (ec-mult-by-table (- n
) pt pt
*2i
)))
1820 (do ((i 1 (1+ i
)) res
)
1823 (setq res
(ec-add pt res
))
1824 (when (= 1 n
) (return res
)) )
1826 pt
(svref pt
*2i i
) )))))
1828 (defun ec-mult-table (pt range
)
1829 (let* ((ilen (integer-length range
))
1830 (pt*2i
(make-array ilen
:element-type
'list
:initial-element nil
)) )
1833 (setq pt
(ec-add pt pt
))
1834 (setf (svref pt
*2i i
) pt
) )))
1836 ;; -------------------------------------------------------------------------- ;;
1838 ;; -------------------------------------------------------------------------- ;;
1840 ;; Mueller 10.5 [complete algorithm]
1844 (defmfun $ec_mueller_10_5
() ;; test function
1845 (ec-set?
"ec_mueller_10_5")
1846 (let ((*gf-char
* *ec-p
*)
1848 (ec-mueller-10-5 *ec-a
* *ec-b
* *ec-p
*) ))
1850 (defun ec-mueller-10-5 (a b p
)
1854 ((or (and (= a
0) (= (mod p
3) 2)) ;; see 9.2.1, case 1
1855 (and (= b
0) (= (mod p
4) 3)) ;; see 9.2.2, case 1
1856 (ec-mueller-9-2 p
) )
1857 (when $ec_sea_verbose
(format t
"supersingular~%"))
1860 ((and (or (= a
0) (= b
0)) ;; j = 0 or 1728 (mod p)
1861 (setq tr
(ec-mueller-9-5 b p
)))
1862 (when $ec_sea_verbose
(format t
"j = 0 or 1728~%"))
1864 ;; use naive algorithm or Shanks-Mestre for small primes:
1866 (ec-trace-naive a b p
) )
1867 ((< p
4503599627370496) ;; 2^52
1868 (ec-shanks-mestre a b p
) )
1871 (let ((bound (floor (* 4 (sqrt (coerce p
'double-float
)))))
1872 (ilen (integer-length p
))
1876 bound-bsgs ls j tr2 lc l^i cs nrcs cost profit
1877 elkies elkies1 atkin atkin1 champ pattern
)
1878 (setq bound-bsgs
;; max. number of possible traces in 10.4
1880 ((>= ilen
256) 400000000)
1881 ((>= ilen
160) 300000000)
1883 (setf elkies
(make-array (1+ lmax
) :element-type
'list
:initial-element nil
))
1884 ;; include trace mod 2:
1885 (setq tr2
(ec-trace-mod-2 a b p
))
1886 (setf (svref elkies
2) tr2
) ;; process l = 2 as Elkies
1887 (when $ec_sea_verbose
(format t
"mod 2 : [2, [~d]]~%" (caadr tr2
)))
1889 (setq ls
(cdr ($primes
3 lmax
))
1890 j
(ec-j-invariant a b p
) ) ;; Mueller 10.1, step 4
1891 (dolist (l ls
(gf-merror (intl:gettext
"`ec_trace': Not enough modular polynomials.")))
1892 (setq lc
(ec-mueller-10-1 l j a b p
))
1893 (unless lc
(when $ec_sea_verbose
(format t
"failure~%")))
1898 (when $ec_sea_verbose
(format t
"[~d, [~{~d~^,~}]]~%" l^i cs
))
1901 (setf (svref elkies l
) lc
) ;; process Atkin with c = 0 as Elkies
1902 (setq m3
(* l^i m3
)) )
1906 (push lc atkin
) ;; process Elkies with nrcs > 1 as Atkin
1907 (setq m-atkin
(* l^i m-atkin
)) ))
1909 (when (>= (* m3 m-atkin
) bound
)
1910 (setq elkies1
(list tr2
))
1912 (when (setq lc
(svref elkies l
)) (push lc elkies1
)) )
1915 (setq tr
(ec-mueller-10-4 elkies1 nil p
))
1918 (ec-elkies-fallback elkies j a b p
) ))
1920 (setq champ
(ec-champions cost profit
(floor bound m3
))
1921 pattern
(if champ
(car champ
) 0)
1922 nrcs
(if champ
(cadr champ
) 0) )
1923 (when (< nrcs bound-bsgs
)
1926 (when (oddp pattern
) (push lc atkin1
))
1927 (setq pattern
(ash pattern -
1)) )
1930 (sort atkin1
#'(lambda (a b
) (< (length (cadr a
)) (length (cadr b
))))) ))
1931 (setq tr
(ec-mueller-10-4 elkies1 atkin1 p
))
1934 (ec-elkies-fallback elkies j a b p
) ))))))))))))
1936 (defun ec-elkies-fallback (elkies j a b p
)
1938 (dolist (l '(3 5 7 11 13))
1939 (when (and (setq lc
(svref elkies l
))
1941 (multiple-value-bind (rts gl
) (ec-glj-roots l j p
)
1942 (setq lc
(ec-elkies 1 l gl rts j a b p
))
1943 (when $ec_sea_verbose
(format t
"fallback: [~d, [~{~d~^,~}]]~%" (car lc
) (cadr lc
)))
1944 (setf (svref elkies l
) lc
) )))))
1946 ;; tr = 1 mod 2 if and only if x^3+a*x+b is irreducible over Fp
1948 (defun ec-trace-mod-2 (a b p
)
1950 ((= 0 a
) (list 3 1 0 b
))
1951 ((= 0 b
) (list 3 1 1 a
))
1952 (t (list 3 1 1 a
0 b
)) ))
1953 (x^p
(gf-pow-sliding-window (list 1 1) p cub
))
1954 (x^p-x
(gf-nplus x^p
(list 1 (1- p
)))) )
1955 `(2 (,(if (= 0 (car (gf-gcd cub x^p-x
))) 1 0))) ))
1957 (defun ec-trace-naive (a b p
)
1958 (do ((s 0) (x 0 (1+ x
)) y
)
1960 (setq y
(mod (+ (power-mod x
3 p
) (* a x
) b
) p
)
1961 s
(- s
($jacobi y p
)) )))
1963 ;; ************************************************************************** ;;
1965 ;; *** SHANKS-MESTRE ******************************************************** ;;
1967 ;; This version of the Shanks-Mestre-Algorithm follows
1969 ;; Algorithm 7.4.12, Cohen - A Course in Computational Algebraic Number Theory
1971 (defmfun $ec_shanks_mestre
() ;; test function
1972 (ec-set?
"ec_shanks_mestre")
1973 (let ((*gf-char
* *ec-p
*)
1975 (ec-shanks-mestre *ec-a
* *ec-b
* *ec-p
*) ))
1977 (defun ec-shanks-mestre (a b p
)
1978 (let* ((delta (floor (* 2 (sqrt (coerce p
'double-float
)))))
1982 (aa 0) aa1
(bb 1) ;; big-a, big-a1, big-b in Cohen
1984 d pt r m n fs-n h h1
1988 (gf-merror (intl:gettext
"`ec_trace': unexpected failure")) )
1990 (setq d
(mod (+ (power-mod x
3 p
) (* a x
) b
) p
)
1992 (when (and (/= k
0) (/= k k-old
)) (return))
1995 aa1
(if (= k
1) aa
(mod (- (* 2 p
+1) aa
) bb
)) )
1996 (setq r
(mod (- lo aa1
) bb
)
1997 m
(if (= r
0) lo
(+ lo
(- bb r
))) )
1998 (let* ((xd (mod (* x d
) p
))
1999 (dd (mod (* d d
) p
))
2000 (*ec-a
* (mod (* dd
*ec-a
*) p
)) ) ;; twist curve locally
2001 (setq pt
(list xd dd
) ;; point on twisted curve
2002 n
(ec-baby-giant pt m bb p
)
2003 fs-n
(let (($intfaclim
)) (get-factor-list n
))
2004 h
(ec-point-order pt n fs-n
)
2006 ;; assume aa1 = 0 mod gcd(bb,h)
2007 (let* ((gc (zn-gcdex2 h bb
)) ;; third and first entry of $gcdex
2010 (h/g
(truncate h g
))
2011 (lcm-hb (* h
/g bb
)) )
2012 (setq h1
(if (= 0 aa1
) lcm-hb
(mod (* c h
/g aa1
) lcm-hb
))) )
2013 (when (and (< (- n h
) lo
) (> (+ n h
) hi
)) (return))
2015 aa
(if (= 1 k
) (mod h1 bb
) (mod (- (* 2 p
+1) h1
) bb
)) ))
2018 (defun ec-baby-giant (pt m bb p
)
2019 (let* ((w (ceiling (* 2 (expt (/ (coerce p
'double-float
) (* bb bb
)) 0.25))))
2020 (s (ceiling (* 1.3 w
)))
2021 (ptp (ec-projectify pt
))
2022 (m*pt
(ec-affinify (ec-pmult m ptp
)))
2023 (bb*pt
(ec-affinify (ec-pmult bb ptp
)))
2026 (make-hash-table :size s
:test
#'equal
:rehash-threshold
0.9) )
2027 (do ((r 0) (qt m
*pt
)) (())
2030 (return-from ec-baby-giant
(+ m
(* bb r
))) )
2031 (setf (gethash qt babies
) r
)
2033 (when (= r w
) (return))
2034 (setq qt
(ec-add bb
*pt qt
)) )
2035 (setq w
*bb
*pt
(ec-affinify (ec-pmult w
(ec-projectify (ec-neg bb
*pt
)))))
2036 (do ((rr 1) r
(qt w
*bb
*pt
)) (())
2037 (when (setq r
(gethash qt babies
))
2039 (return-from ec-baby-giant
(+ m
(* bb r
) (* w bb rr
))) )
2042 (gf-merror (intl:gettext
"`ec_trace': unexpected failure")) )
2043 (setq qt
(ec-add w
*bb
*pt qt
)) )))
2045 ;; ************************************************************************** ;;