Remove references to the obsolete srrat function
[maxima.git] / share / contrib / elliptic_curves / elliptic_curves.lisp
blobd59224244d2ce03fa39038121c76246b71a8c5b4
1 #|
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,
15 MA 02110-1301, USA.
18 *** Elliptic Curves *********************************************************
20 Copyright Volker van Nek, 2015
22 This file contains some algorithms for elliptic curves over prime fields.
24 Maxima functions:
25 ec_set_curve, ec_add, ec_mult, ec_random, ec_point_p, ec_point_order,
26 ec_log, ec_twist_curve, ec_trace
28 Option variables:
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.
38 Example session:
40 (%i1) load("elliptic_curves")$
42 (%i2) p : 4451685225093714772084598273548427$
43 (%i3) a : -3$
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
51 (%i7) primep(ord);
52 (%o7) true
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);
58 (%o9) true
60 The point at infinity is ec_inf.
62 (%i10) ec_mult(ord, pt);
63 (%o10) ec_inf
67 (declare-top (special
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*
71 *ec-poly* *ec-poly2*
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))
89 (setq *ec-set?* nil)
90 (setq *ec-p* p
91 *ec-a* (mod a p)
92 *ec-b* (mod b p)
93 *ec-inv2* (inv-mod 2 p)
94 *ec-set?* t ))))
96 (defun ec-set? (fun)
97 (if *ec-set?* t
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)
104 (let (pt)
105 (cond
106 ((equal pt_m '$ec_inf) nil) ;; neutral element, point of infinity (nil at Lisp level)
107 ((not (and ($listp pt_m)
108 (setq pt (cdr 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) ))))
114 (defun ec-l2m (pt)
115 (if pt
116 (cons '(mlist simp) (ec-balance pt))
117 '$ec_inf ))
119 (defun ec-balance (pt)
120 (if $ec_balanced
121 (mapcar #'(lambda (n) (if (< (ash *ec-p* -1) n) (- n *ec-p*) n)) pt)
122 pt ))
125 ;; point addition (use affine coords at Maxima level, projective at Lisp level)
127 (defmfun $ec_add (pt qt)
128 (let ((fn "ec_add"))
129 (ec-set? fn)
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"))
139 (ec-set? fn)
140 (unless (integerp n)
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)
151 (cond
152 ((null pt) qt)
153 ((null qt) pt)
154 ((equal pt qt) (ec-double pt))
155 ((eql (car pt) (car qt)) nil) ;; erroneous if pt or qt is not on the curve
156 (t (let* ((p *ec-p*)
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)) )
162 (list xx yy) ))))
164 (defun ec-double (pt)
165 (cond
166 ((null pt) nil)
167 ((= 0 (cadr pt)) nil)
168 (t (let* ((p *ec-p*)
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)) )
173 (list xx yy) ))))
175 (defun ec-mult (n pt)
176 (cond
177 ((or (= 0 n) (null pt)) nil)
178 ((and (< n 0)
179 (setq n (- n) pt (ec-neg pt))
180 nil ))
182 (do ((res)) (())
183 (when (oddp n)
184 (setq res (ec-add pt res))
185 (when (= 1 n) (return res)) )
186 (setq n (ash n -1)
187 pt (ec-double pt) )) )))
189 (defun ec-neg (pt)
190 (when pt (list (car pt) (- *ec-p* (cadr pt)))) )
193 ;; arithmetic in projective coordinates ------------------------------------- ;;
195 (defun ec-projectify (pt)
196 (if pt
197 (nconc pt (list 1))
198 (list 1 1 0) ))
200 (defun ec-affinify (pt)
201 (unless (= (caddr pt) 0)
202 (let* ((p *ec-p*)
203 (i (inv-mod (caddr pt) p))
204 (ii (* i i))
205 (x (mod (* ii (car pt)) p))
206 (y (mod (* ii i (cadr pt)) p)) )
207 (list x y) )))
209 (defun ec-pdouble (pt)
210 (cond
211 ((= (caddr pt) 0) pt)
212 (t (let* ((p *ec-p*)
213 (a *ec-a*)
214 (x1 (car pt)) (y1 (cadr pt)) (z1 (caddr pt))
215 (y11 (* y1 y1))
216 (z11 (* z1 z1))
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)
228 (cond
229 ((= (caddr pt) 0) qt)
230 ((= (caddr qt) 0) pt)
231 (t (let* ((p *ec-p*)
232 (x1 (car pt)) (y1 (cadr pt)) (z1 (caddr pt))
233 (x2 (car qt)) (y2 (cadr qt)) (z2 (caddr qt))
234 (z11 (* z1 z1))
235 (z22 (* z2 z2))
236 (l1 (* x1 z22))
237 (l2 (* x2 z11))
238 (l3 (mod (- l1 l2) p))
239 (l4 (* y1 z22 z2))
240 (l5 (* y2 z11 z1))
241 (l6 (mod (- l4 l5) p)) )
242 (if (= l3 0)
243 (if (= l6 0)
244 (ec-pdouble pt)
245 (list 1 1 0) )
246 (let* ((l7 (+ l1 l2))
247 (l8 (+ l4 l5))
248 (z3 (mod (* z1 z2 l3) p))
249 (l33 (* l3 l3))
250 (l733 (* l7 l33))
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)
257 (cond
258 ((or (= 0 n) (= (caddr pt) 0)) (list 1 1 0))
259 ((and (< n 0)
260 (setq n (- n) pt (ec-pneg pt))
261 nil ))
262 ((typep n 'fixnum)
263 (do ((res (list 1 1 0))) (())
264 (when (oddp n)
265 (setq res (ec-padd pt res))
266 (when (= 1 n) (return res)) )
267 (setq n (ash n -1)
268 pt (ec-pdouble pt) )) )
270 (ec-pmult-sliding-window n pt) )))
272 (defun ec-pneg (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)
278 ((<= l 160) 4)
279 ((<= l 384) 5)
280 ((<= l 896) 6)
281 (t 7) ))
282 (tab (ec-pmult-table pt k))
283 (i (1- l)) (s 0) (h 0)
284 (res (list 1 1 0))
286 (do () ((< i 0) res)
287 (cond
288 ((logbitp i n)
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)))))
295 (setq i (1- s)) )
297 (setq res (ec-pdouble res))
298 (decf i) )))))
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))
303 (pti pt)
304 (pt2 (ec-pdouble pt))
305 (i 1) )
306 (setf (svref tab 0) pt)
307 (do () ((= i l) tab)
308 (setq pti (ec-padd pti pt2))
309 (setf (svref tab i) pti)
310 (incf i) )))
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*)
323 x y rts )
324 (())
325 (setq x ($random p) ;; $random is set by set_random_state
326 y (mod (+ (power-mod x 3 p) (* a x) b) p) )
327 (when (or (= y 0)
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"))
338 (ec-set? fn)
339 (cond
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
344 (let ((p *ec-p*)
345 (x (car pt)) (y (cadr pt)) )
346 (= (power-mod y 2 p)
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"))
354 (ec-set? fn)
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) )
362 (if fs-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)
374 (dolist (f fs-ord s)
375 (setq fp (car f)
376 fe (cadr f)
377 s (truncate s (expt fp fe)) )
378 (do () (())
379 (setq qt (ec-pmult s pt))
380 (when (= (caddr qt) 0) (return))
381 (setq qt (ec-pmult fp qt)
382 s (* fp s) )))))
385 ;; discrete logarithm (simple baby-giant-variant, p < 2^36)
387 (defmfun $ec_log (pt gen)
388 (let ((fn "ec_log"))
389 (ec-set? fn)
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))))
399 (m (1+ (isqrt lim)))
400 (s (floor (* 1.3 m)))
401 (gi (ec-neg gen)) ;; additive inverse
402 babies mg )
403 (setf babies
404 (make-hash-table :size s :test #'equal :rehash-threshold 0.9) )
405 (do ((r 0) b acc)
406 (())
407 (setq b (ec-add pt acc))
408 (when (null b) ;; point of infinity
409 (clrhash babies)
410 (return-from ec-dlog-baby-giant r) )
411 (setf (gethash b babies) r)
412 (incf 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)
417 ((> rr m) nil)
418 (when (setq r (gethash bb babies)) ;; points don't match if we would use projective coords
419 (clrhash babies)
420 (return-from ec-dlog-baby-giant (+ (* rr m) r)) )
421 (incf rr)
422 (setq bb (ec-add mg bb)) )))
425 ;; curve twist
427 (defmfun $ec_twist_curve ()
428 (ec-set? "ec_twist_curve")
429 (cons '(mlist simp) (ec-twist-curve)) )
431 (defun ec-twist-curve ()
432 (let ((p *ec-p*)
433 (n 2) nn a b )
434 (do () ((= ($jacobi n p) -1))
435 (incf n) )
436 (setq nn (* n n)
437 a (mod (* nn *ec-a*) p)
438 b (mod (* n nn *ec-b*) p) )
439 (list n a b) ))
442 ;; trace of Frobenius (ord = #E = p+1 - trace)
444 (defmfun $ec_trace ()
445 (ec-set? "ec_trace")
446 (let ((*gf-char* *ec-p*)
447 (*ef-arith?*) )
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 ;; -------------------------------------------------------------------------- ;;
460 ;; Mueller 2.22
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")
488 (ec-sea-data?)
489 (let* ((p *ec-p*)
490 (*gf-char* p)
491 (*ef-arith?*)
492 (j (ec-j-invariant *ec-a* *ec-b* p))
493 gl f )
494 (if (svref *ec-g* l)
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
497 (cons '(mlist simp)
498 (multiple-value-list
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))
503 (gly (ec-dy 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))
513 ;; step 1:
514 (e4 (zn-quo a -3 p))
515 (e6 (zn-quo b -2 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))
518 ;; step 2:
519 (dg (mod (* g glxgj) p)) ;; DF in Mueller 7.3
520 (dj (mod (* j glygj) p)) )
521 (cond
522 ((= 0 dj)
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
526 ;; steps 3-6:
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))
535 (p1 0) )
536 (values at bt p1) ))
537 (t ;; dj # 0:
538 ;; steps 7-9:
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))
543 ;; step 10:
544 (dgq (mod (+ (* gq glxgj) (* g (+ (* gq glxxgj) (* jq glxygj)))) p))
545 (djq (mod (+ (* jq glygj) (* j (+ (* jq glyygj) (* gq glxygj)))) p))
546 ;; steps 11-14:
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))
553 ;; step 15:
554 (dg2 (ec-at-xy glx ff jl))
555 (dj2 (ec-at-xy gly ff jl))
556 ;; steps 16-17:
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)
561 ;; step 18:
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) )))))
567 ;; f = f(x,y) mod p
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)
575 (cond
576 ((null f) 0)
577 (x? (do ((itr f (cddr itr)) res cy)
578 ((null itr) res)
579 (setq cy (cadr itr))
580 (when (consp cy) (setq cy (gf-at cy y)))
581 (setq res (nconc res (list (car itr) cy))) ))
582 (t (gf-at f y)) ))
584 (defun ec-at-x (f x y?)
585 (cond
586 ((null f) 0)
587 (y? (do ((res nil) cy xx) (())
588 (setq cy (cadr f))
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)
596 f (cddr f) )))
597 (t (gf-at f x)) ))
599 (defun ec-at-xy (f x y)
600 (if (null f) 0
601 (ec-at-x (ec-at-y f t y) x nil) ))
603 ;; partial derivatives:
605 (defun ec-dx (f)
606 (do ((itr f (cddr itr)) res e cy)
607 ((null itr) res)
608 (setq e (car itr))
609 (when (= e 0) (return res))
610 (setq cy (cadr itr)
611 cy (if (consp cy) (gf-xctimes cy e) (gf-ctimes e cy)) )
612 (setq res (nconc res (list (1- e) cy))) ))
614 (defun ec-dy (f)
615 (do ((itr f (cddr itr)) res cy)
616 ((null itr) res)
617 (setq cy (cadr itr))
618 (when (consp 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
626 ;; (license GPL).
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))
630 (gly (ec-dy 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))
636 (e4 (zn-quo a -3 p))
637 (e6 (zn-quo b -2 p))
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))
679 x^p ggt )
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))
694 (let ((aa (* a a))
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)
703 *ec-psi-red* 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) )
717 (setq *ec-psi-i* 4)
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)))
727 (let ((j (ash i -1))
728 (cub2 *ec-poly2*)
729 (psi *ec-psi*)
730 (psi2 *ec-psi2*)
731 (psi3 *ec-psi3*)
732 (red *ec-psi-red*) )
733 (setf (svref psi i)
734 (cond
735 ((evenp i)
736 (unless (= i cap)
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
739 (gf-xctimes
740 (gf-ktimes
741 (svref psi j)
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)
744 *ec-inv2* ))
746 (unless (= i cap)
747 (setf (svref psi2 (+ j 2)) (gf-ksq (svref psi (+ j 2)) red)) )
748 (if (evenp j)
749 ;; cub^2*f[j+2]*f[j]^3 - f[j-1]*f[j+1]^3
750 (gf-plus (gf-ktimes
751 (gf-ktimes (svref psi (+ j 2)) (svref psi3 j) red)
752 cub2 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)
758 cub2 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))))
770 (declare (fixnum n))
771 (cond
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)))
779 (declare (fixnum n))
780 (cond
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)))
800 (unless (null x)
801 (let ((n (car x)))
802 (declare (fixnum n))
803 (cond
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)))
811 (declare (fixnum n))
812 (cond
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))
818 (cond
819 ((null z1)
820 (gf-nred (gf-nksq z0 n/2 red) red) )
821 ((null z0)
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)))
831 (declare (fixnum n))
832 (if (null x)
833 (values nil nil)
834 (prog (r r0)
836 (when (< (the fixnum (car x)) n) (return (values nil x)))
837 (rplaca x (- (the fixnum (car x)) n))
838 (setq r (cdr x))
840 (when (null (cdr r)) (return (values x nil)))
841 (when (< (the fixnum (cadr r)) n)
842 (setq r0 (cdr r))
843 (rplacd r nil)
844 (return (values x r0)) )
845 (setq r (cdr r))
846 (rplaca r (- (the fixnum (car r)) n))
847 (setq r (cdr r))
848 (go a) )))
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*)
859 (*ef-arith?*) )
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)))
866 ctk hlp h fc )
867 (unless ck
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)))
883 (when (> ll 2)
884 (do ((k 3 (1+ k)))
885 ((= k ll))
886 (setf (svref ck k) 0)
887 (do ((i 1 (1+ i)) (k1 (1- k)))
888 ((= i k1))
889 (setf (svref ck k)
890 (+ (svref ck k) (* (svref ck i) (svref ck (- k 1 i)))) ))
891 (setf (svref ck k)
892 (zn-quo (* 3 (svref ck k)) (* (- k 2) (+ (* 2 k) 3)) p) )))
893 ck ))
895 ;; steps 4-6:
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)
904 (do ((v 2 (1+ v)))
905 ((= v d1) wp)
906 (setf (svref wp v)
907 (gf-times (svref wp (1- v)) wp1 red) )) ))
909 (defun ec-weierstrass (l ck)
910 (let ((wp (list -1 1))) ;; contains 1/x
911 (do ((k 1 (1+ k)))
912 ((= k l) wp)
913 (push (svref ck k) wp)
914 (push k wp) )
915 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)))))
921 (do ((k 1) twok tmp)
922 ((= k l3) hlp)
923 (setq twok (* 2 k))
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))
927 (incf k)
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)
934 (h (list 0 1))
935 (r! 1)
936 (hlp^r (list 0 1)) )
937 (do ((r 1 (1+ r)))
938 ((= r d1) h)
939 (setq r! (* r! r)
940 hlp^r (gf-times hlp^r hlp red)
941 h (gf-nplus h (gf-xctimes hlp^r (inv-mod r! p))) ))))
943 ;; steps 11-14:
945 (defun ec-fc (d h wpv p)
946 (let ((av 1)
947 (fc (list d 1)) )
948 (do ((v (1- d) (1- v)))
949 ((< v 0) fc)
950 (setq h (gf-nplus h (gf-xctimes (svref wpv (1+ v)) (- p av)))
951 h (gf-nxetimes h -1) ;; h/x
952 av (car (last h))
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")
963 (let* ((p *ec-p*)
964 (*gf-char* p)
965 (*ef-arith?*) )
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)
972 (psi2 *ec-psi2*)
973 (psi3 *ec-psi3*)
974 ;; step 3:
975 (lx (gf-pow-sliding-window (list 1 1) p fc))
976 ;; step 4:
977 (cub *ec-poly*)
978 (ly (gf-times (gf-xctimes cub 4)
979 (gf-pow-sliding-window cub (ash (1- p) -1) fc)
980 fc ))
981 ry c )
982 ;; step 5:
983 (do ((alpha 1 (1+ alpha))
984 (l1 (1+ (ash (- l 1) -1)))
985 lhs )
986 ((= alpha l1) (values))
987 ;; step 7:
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))
991 ;; steps 9-12:
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)) )))))
1000 ;; step 6:
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))) )
1006 (if (evenp n)
1007 (setq r1 (gf-times cub r1 fc))
1008 (setq r2 (gf-times cub r2 fc)) )
1009 (gf-nplus r1 r2) ))
1011 ;; step 8:
1013 (defun ec-ry (n cub fc) ;; n >= 1
1014 (let* ((psi *ec-psi*)
1015 (psi2 *ec-psi2*)
1016 (r1 (gf-ktimes (svref psi (+ n 2)) (svref psi2 (1- n)) fc))
1017 (r2 (svref psi2 (1+ n)))
1018 ry )
1019 (when (> n 1)
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)))
1023 ry ))
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)
1031 ((<= l 160) 4)
1032 ((<= l 384) 5)
1033 ((<= l 896) 6)
1034 (t 7) ))
1035 (tab (gf-pow-sliding-window-table x k red))
1036 (res (list 0 1)) s u tmp )
1037 (do ((i (1- l)))
1038 ((< i 0) res)
1039 (cond
1040 ((logbitp i e)
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)))
1047 (setq i (1- s)) )
1049 (setq res (gf-sq res red))
1050 (decf i) )))))
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))
1056 (xi x)
1057 (x2 (gf-sq x red)) )
1058 (setf (svref tab 0) x)
1059 (do ((i 1 (1+ i)))
1060 ((= i l) tab)
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
1082 ;; step 2c:
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 )
1088 (dolist (g rts)
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))
1099 (if (= i 2)
1100 (setq iso11 iso1
1101 h num )
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))
1107 (setq l^i (* l1 l))
1108 (cond
1109 ((null tau11) nil)
1110 ((and (setq res `(,l^i (,c)))
1111 (= i n) )
1112 (return) )
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)) ))))))
1119 res ))
1121 ;; 4.2. computing h1 and i1
1123 ;; pre-process: k1
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))
1130 (red (list l 1))
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
1138 c y k1x )
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):
1141 (do ((i l (1- i)))
1142 (())
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*)
1156 (cub *ec-poly*)
1157 ;; step 4:
1158 (x^p (gf-pow-sliding-window (list 1 1) p gt))
1159 tmp rhs1 rhs2 lhs )
1160 ;; steps 5,6:
1161 (do* ((k 0 (1+ k))
1162 (alphat alpha (+ alphat l^i)) )
1163 ((= k l) (values))
1164 ;; ... and up to psi_{alphat+1} if necessary:
1165 (ec-set-div-poly-mod1 (1+ alphat) (* l^i l))
1166 ;; steps 7,8:
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) )
1171 (if (evenp alphat)
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)) )
1177 ;; steps 9,10:
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
1194 (let ((trs
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
1198 (modulus p) )
1199 (mapcar #'(lambda (n) (cmod (* x n))) i2) ) ;; symmetric mod
1200 ;; j = 0:
1201 (let ((x (* 2 (car (cornacchia 3 p))))
1202 (om3 (zn-nrt 1 3 p)) ;; 1,om,om^2
1203 (modulus p) )
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)))
1219 (when rts
1220 (let* ((rt (car rts))
1221 (x (if (> (* 2 rt) p) (- p rt) rt))
1222 (h p)
1224 (do ((bound (isqrt p)))
1225 ((<= x bound))
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) ))
1231 (list x y) ))))
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)
1239 (return) ))))
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")
1254 (ec-sea-data?)
1255 (let* ((p *ec-p*) (a *ec-a*) (b *ec-b*)
1256 (*gf-char* p)
1257 (*ef-arith?*)
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)
1264 ;; steps 1-7:
1265 (multiple-value-bind (rts gl glj x^p) (ec-glj-roots l j p)
1266 (cond
1267 ;; step 13:
1268 ((null rts)
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) )
1276 ((= nr (1+ l))
1277 (when $ec_sea_verbose (format t "~d roots: " (1+ l)))
1278 (ec-lp1-roots l p) )
1279 ;; steps 8-11:
1280 (t ;; nr = 2
1281 (when $ec_sea_verbose (format t "elkies: "))
1282 (setq len (integer-length p)
1283 k (cond
1284 ((< len 52) 1)
1285 ((= l 3) (if (< len 128) 3 4))
1286 ((= l 5) (if (< len 192) 2 3))
1287 ((= l 7) 2)
1288 ((= l 11) (if (< len 160) 1 2))
1289 ((= l 13) (if (< len 192) 1 2))
1290 (t 1) ))
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")
1296 (ec-sea-data?)
1297 (let* ((p *ec-p*)
1298 (*gf-char* p)
1299 (*ef-arith?*)
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)) ))
1304 ;; 10.1, steps 1-7:
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
1312 p ))
1313 ;; step 4:
1314 (glj (ec-at-y gl t j))
1315 (x^p (gf-pow-sliding-window (list 1 1) p glj))
1316 ;; step 5:
1317 (ggt (gf-gcd (gf-plus x^p (list 1 (1- p))) glj))
1318 rts )
1319 ;; step 7:
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)
1326 ((null itr) res)
1327 (setq cy (cadr itr)
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 #'<))
1334 (setq fs1 (car fs)
1335 len (length fs1) )
1336 (cond
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 )
1344 (dolist (g rts)
1345 (cond
1346 ((null (svref *ec-g* l)) ;; using Atkin modular poly:
1347 ;; steps 8,9:
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:
1351 ;; step 8:
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
1354 ;; step 9:
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)) )))
1358 (when found
1359 ;; steps 10,11:
1360 (multiple-value-bind (c alpha) (ec-mueller-7-9 l fc p)
1361 (cond
1362 ((null alpha) nil)
1363 ((and (setq res `(,l (,c)))
1364 (= k 1) )
1365 (return) )
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)) ))))))
1373 res ))
1375 ;; -------------------------------------------------------------------------- ;;
1377 ;; -------------------------------------------------------------------------- ;;
1379 ;; Mueller 10.2 [partial information] (the non-Elkies-case)
1381 ;; 10.2, steps 1,2:
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))) )))
1390 ;; 10.2, steps 3-5:
1392 (defun ec-lp1-roots (l p)
1393 (let ((ll (* l l))
1394 alpha h )
1395 (setq ;; p (mod p ll)
1396 alpha (car (zn-nrt p 2 ll `((,l 2)))) )
1397 (when alpha
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)
1404 (let* (;; step 6:
1405 (d-rest (car glj))
1406 ;; step 7:
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
1411 ($intfaclim)
1412 (fs (get-factor-list ord))
1413 (fs-ord (sort fs #'< :key #'car))
1414 ds d cs )
1415 ;; steps 8,14:
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
1419 (push d ds) ))
1420 (setq d
1421 (if (= (length ds) 1) ;; shortcut: just one possible d
1422 (car ds)
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:
1428 (if (= d 2)
1429 (push 0 cs)
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
1438 gam^i gam )
1439 ;; compute the set of possible traces:
1440 (do ((i 1 (1+ i)) (old-i 1) (nr 0))
1441 ((= nr phi))
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)
1444 old-i i
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))))
1449 (dolist (rt rts)
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)
1455 (let* ((lp1 (1+ l))
1456 (cs (nreverse (gf-x2l (copy-list x^p) lp1)))
1457 c x^p^i r )
1458 (setq c (nth 1 cs))
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))
1462 ((= i lp1))
1463 (setq acc (gf-times acc x^p glj)
1464 cs (nreverse (gf-x2l acc lp1))
1465 c (nth i cs) )
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 )
1475 ((null m) r)
1476 (setq m1 nil piv? nil)
1477 (do () ((null m))
1478 (setq row (car m) m (cdr m)
1479 c1 (car row)
1480 row (cdr row) )
1481 (cond
1482 ((= c1 0)
1483 (unless (every #'zerop row) (push row m1)) )
1484 (piv?
1485 (zn-naddrows row (- p c1) piv p) ;; modify row
1486 (unless (null row) (push row m1)) )
1488 (incf r)
1489 (setq piv row piv? t
1490 inv (inv-mod c1 p) )
1491 (zn-ncrow piv inv p) ))) ;; modify piv
1492 (setq m m1) ))
1494 (defun zn-ncrow (row c p) ;; c*row mod p, modifies row
1495 (do ((itr row (cdr itr)))
1496 ((null 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)))
1501 ((null 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)
1526 (cond
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))
1537 (n 2) pro cst )
1538 (setf (svref aq 2) 1)
1539 (do ((j 2 (1+ j))
1540 (i 1 1) (i1 2 2) (i2 1 1)
1541 b b1 b2 )
1542 ((> j k))
1543 (do () ((> i1 n))
1544 (setq b1 (svref aq i1)
1545 b2 (logior (svref aq i2) (ash 1 (1- j))) )
1546 (cond
1547 ((< (ec-pattern2val b1 profit k) (ec-pattern2val b2 profit k))
1548 (setq b b1)
1549 (incf i1) )
1551 (setq b b2)
1552 (incf i2) ))
1553 (setq cst (ec-pattern2val b cost k))
1554 (while (< cst (ec-pattern2val (svref a i) cost k)) (decf i))
1555 (incf i)
1556 (setf (svref a i) b) )
1557 (do () ((> i2 n))
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))
1561 (incf i)
1562 (setf (svref a i) b)
1563 (incf i2) )
1564 (setq n i)
1565 (do ((c 1 (1+ c)))
1566 ((> c n))
1567 (setf (svref aq c) (svref a c)) ))
1568 (do ((i 1 (1+ i)) res)
1569 ((= i s) 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))
1579 ((= i k) val)
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
1595 ilen nb n1 n2 d
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)))
1600 ((= i imax))
1601 (setq ilen (integer-length i)
1602 nb 1 )
1603 (do ((k 0 (1+ k)))
1604 ((= k ilen))
1605 (when (logbitp k i)
1606 (setq nb (* nb (svref cost k))
1607 d (abs (- (* nb nb) p4)) ) ;; search for min(|nb^2 - p4|)
1608 (when (< d delta)
1609 (setq delta d
1610 n1 nb
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)))
1615 ((= k clen))
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))
1619 h1 (rest h1)
1620 l2 (ec-combine-init (car h2))
1621 h2 (rest 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) ))))
1639 ;; Mueller 10.4
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))
1644 (list 0 1) ))
1645 (c3 (car cm3))
1646 (m3 (cadr cm3))
1647 (la (length atkin))
1648 (bound (floor (* 4 (sqrt (coerce p 'double-float)))))
1649 (run1 t)
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
1653 (cond
1654 ((= la 0)
1655 (setq h (- c3 (* i m3))) )
1656 ((= la 1)
1657 (when run1
1658 (setq mc1 (car atkin)
1659 m1 (car mc1)
1660 c1 (cadr mc1)
1661 inv-m3 (inv-mod m3 m1)
1662 run1 nil ))
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)))
1669 r1q pt1 q1*2i )
1670 (cond
1671 ((null q0) (setq h c3))
1673 (setq q1*2i (ec-mult-table q1 m1))
1674 (dolist (x c1)
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)))
1679 (return) )
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)))
1683 (return h) )
1684 (setq pt1 (ec-add pt1 q3))
1685 (when (equal q0 pt1)
1686 (setq h (+ c3 (* (+ r1q m1) m3)))
1687 (return) )) ))))
1689 (when run1
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)
1693 m1/2 (ash m1 -1)
1694 run1 nil )
1695 (let* (;; step 1:
1696 (pt (ec-random))
1697 (ptp (ec-projectify pt))
1698 ;; step 2:
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)))
1705 (k 0)
1706 done babies tmp
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))
1710 ;; steps 3-5:
1711 (unless done
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) )
1714 (dolist (x c1)
1715 (setq r1q (mod (* (- x c3) inv-m2m3) m1))
1716 (setf (svref r1q-tab k) (if (> r1q m1/2) (- r1q m1) r1q))
1717 (incf k) )
1718 (sort r1q-tab #'<)
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)))
1722 k 1 )
1723 (when (null pt1) (setq h (+ c3 (* r1q0 m2 m3)) done t))
1724 (unless done
1725 (setf (svref babies 0) (nconc pt1 (list r1q0)))
1726 (do () ((= k c1-len))
1727 (setq r1q (svref r1q-tab k)
1728 dr1q (- r1q r1q0)
1729 r1q0 r1q )
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)))
1733 (incf k) )))
1734 (unless done
1735 (sort babies
1736 #'(lambda (a b) (or (< (car a)(car b))
1737 (and (= (car a)(car b)) (< (cadr a)(cadr b))) ))))
1738 ;; steps 6-14:
1739 (unless done
1740 (setf r2q-tab (make-array c2-len :element-type 'integer :initial-element 0))
1741 (setq k 0)
1742 (dolist (y c2)
1743 ;; steps 7-9:
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))
1748 done t )
1749 (return) ))
1750 (setf (svref r2q-tab k) r2q)
1751 (incf k) ))
1752 (unless done
1753 (sort r2q-tab #'<)
1754 ;; steps 10-14:
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) )
1758 (cond
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))) )
1765 (do ((k 1 (1+ k)))
1766 ((= k c2-len))
1767 (setq r2q (svref r2q-tab k)
1768 dr2q (- r2q r2q0)
1769 r2q0 r2q
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)))
1773 (return) )
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)))
1777 (return) ))) ))))))
1778 (setq h
1779 (cond
1780 ((> (abs h) (ash bound -1)) nil)
1781 ;; steps 15,16:
1782 ((ec-check-trace h p) h)
1783 ;; steps 17,18:
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))
1795 x y (m 0) am )
1796 (declare (fixnum m))
1797 (do ((lo 0) (hi (1- (array-dimension a 0))))
1798 ((< hi lo))
1799 (declare (fixnum lo hi))
1800 (setq m (ash (+ lo hi) -1)
1801 am (svref a m)
1802 x (car am) )
1803 (cond
1804 ((< px x) (setq hi (1- m)))
1805 ((> px x) (setq lo (1+ m)))
1807 (setq y (cadr am))
1808 (cond
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)
1816 (cond
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)
1821 (())
1822 (when (oddp n)
1823 (setq res (ec-add pt res))
1824 (when (= 1 n) (return res)) )
1825 (setq n (ash n -1)
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)) )
1831 (do ((i 1 (1+ i)))
1832 ((= i ilen) pt*2i)
1833 (setq pt (ec-add pt pt))
1834 (setf (svref pt*2i i) pt) )))
1836 ;; -------------------------------------------------------------------------- ;;
1838 ;; -------------------------------------------------------------------------- ;;
1840 ;; Mueller 10.5 [complete algorithm]
1842 ;; assume p prime
1844 (defmfun $ec_mueller_10_5 () ;; test function
1845 (ec-set? "ec_mueller_10_5")
1846 (let ((*gf-char* *ec-p*)
1847 (*ef-arith?*) )
1848 (ec-mueller-10-5 *ec-a* *ec-b* *ec-p*) ))
1850 (defun ec-mueller-10-5 (a b p)
1851 (let (tr)
1852 (cond
1853 ;; steps 1,2:
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~%"))
1859 ;; steps 3,4:
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~%"))
1863 tr )
1864 ;; use naive algorithm or Shanks-Mestre for small primes:
1865 ((<= p 457)
1866 (ec-trace-naive a b p) )
1867 ((< p 4503599627370496) ;; 2^52
1868 (ec-shanks-mestre a b p) )
1869 (t ;; SEA:
1870 (ec-sea-data?)
1871 (let ((bound (floor (* 4 (sqrt (coerce p 'double-float)))))
1872 (ilen (integer-length p))
1873 (m3 2)
1874 (lmax 151)
1875 (m-atkin 1)
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
1879 (cond
1880 ((>= ilen 256) 400000000)
1881 ((>= ilen 160) 300000000)
1882 (t 100000000) ))
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)))
1888 ;; steps 6-9:
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~%")))
1894 (when lc
1895 (setq l^i (car lc)
1896 cs (cadr lc)
1897 nrcs (length cs) )
1898 (when $ec_sea_verbose (format t "[~d, [~{~d~^,~}]]~%" l^i cs))
1899 (cond
1900 ((= 1 nrcs)
1901 (setf (svref elkies l) lc) ;; process Atkin with c = 0 as Elkies
1902 (setq m3 (* l^i m3)) )
1904 (push nrcs cost)
1905 (push l^i profit)
1906 (push lc atkin) ;; process Elkies with nrcs > 1 as Atkin
1907 (setq m-atkin (* l^i m-atkin)) ))
1908 ;; steps 10-13:
1909 (when (>= (* m3 m-atkin) bound)
1910 (setq elkies1 (list tr2))
1911 (dolist (l ls)
1912 (when (setq lc (svref elkies l)) (push lc elkies1)) )
1913 (cond
1914 ((> m3 bound)
1915 (setq tr (ec-mueller-10-4 elkies1 nil p))
1916 (if tr
1917 (return tr)
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)
1924 (setq atkin1 nil)
1925 (dolist (lc atkin)
1926 (when (oddp pattern) (push lc atkin1))
1927 (setq pattern (ash pattern -1)) )
1928 (when atkin1
1929 (setq atkin1
1930 (sort atkin1 #'(lambda (a b) (< (length (cadr a)) (length (cadr b))))) ))
1931 (setq tr (ec-mueller-10-4 elkies1 atkin1 p))
1932 (if tr
1933 (return tr)
1934 (ec-elkies-fallback elkies j a b p) ))))))))))))
1936 (defun ec-elkies-fallback (elkies j a b p)
1937 (let (lc)
1938 (dolist (l '(3 5 7 11 13))
1939 (when (and (setq lc (svref elkies l))
1940 (/= (car lc) 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)
1949 (let* ((cub (cond
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)
1959 ((= x p) s)
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*)
1974 (*ef-arith?*) )
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)))))
1979 (p+1 (1+ p))
1980 (lo (- p+1 delta))
1981 (hi (+ p+1 delta))
1982 (aa 0) aa1 (bb 1) ;; big-a, big-a1, big-b in Cohen
1983 k (k-old 0)
1984 d pt r m n fs-n h h1
1985 (x 0) )
1986 (do ((i 0 (1+ i)))
1987 ((= i p)
1988 (gf-merror (intl:gettext "`ec_trace': unexpected failure")) )
1989 (do () (())
1990 (setq d (mod (+ (power-mod x 3 p) (* a x) b) p)
1991 k ($jacobi d p) )
1992 (when (and (/= k 0) (/= k k-old)) (return))
1993 (incf x) )
1994 (setq k-old k
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)
2005 h1 h ))
2006 ;; assume aa1 = 0 mod gcd(bb,h)
2007 (let* ((gc (zn-gcdex2 h bb)) ;; third and first entry of $gcdex
2008 (g (car gc))
2009 (c (cadr gc))
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))
2014 (setq bb (lcm bb h)
2015 aa (if (= 1 k) (mod h1 bb) (mod (- (* 2 p+1) h1) bb)) ))
2016 (* k (- p+1 n)) ))
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)))
2024 babies w*bb*pt )
2025 (setf babies
2026 (make-hash-table :size s :test #'equal :rehash-threshold 0.9) )
2027 (do ((r 0) (qt m*pt)) (())
2028 (when (null qt)
2029 (clrhash babies)
2030 (return-from ec-baby-giant (+ m (* bb r))) )
2031 (setf (gethash qt babies) r)
2032 (incf 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))
2038 (clrhash babies)
2039 (return-from ec-baby-giant (+ m (* bb r) (* w bb rr))) )
2040 (incf rr)
2041 (when (> rr w)
2042 (gf-merror (intl:gettext "`ec_trace': unexpected failure")) )
2043 (setq qt (ec-add w*bb*pt qt)) )))
2045 ;; ************************************************************************** ;;