Improved Standard Continuation

November 8, 2011

Here is our version of the elliptic curve factorization function:

(define ec-factor ; Crandall/Pomerance Algorithm 7.4.4
  (let* ((b1-saved 0) (b2-saved 0) (ps '()) (as '()) (ds '()) (d 210)
         (sv (make-vector (+ d 1) #f)) (bv (make-vector (+ d 1) #f)))
    (lambda (n b1 b2 s)
      (when (not (and (= b1 b1-saved) (= b2 b2-saved)))
        (set! b1-saved b1) (set! b2-saved b2) (set! ps (primes b2))
        (set! as (let loop ((ps ps) (as (list)))
                   (let ((a (ilog (car ps) b1)))
                     (if (= a 1) (append (reverse as) (cycle 1))
                       (loop (cdr ps) (cons a as))))))
        (set! ds (cons 0 (map (lambda (x) (/ x 2))
                   (map - (cdr ps) (reverse (cdr (reverse ps))))))))
      (let-values (((an ad q) (curve12 n s)))
        (let stage1 ((ps ps) (as as) (ds ds) (q q))
          (if (< (car ps) b1)
              (stage1 (cdr ps) (cdr as) (cdr ds)
                      (multiply (expt (car ps) (car as)) q an ad n))
              (let ((g (gcd (cdr q) n))) (if (< 1 g n) (list 1 g)
                (let* ((v (- b1 1)) (r (multiply v q an ad n))
                       (t (multiply (- b1 1 d d) q an ad n))
                       (alpha (modulo (* (car r) (cdr r)) n)))
                  (vector-set! sv 1 (double q an ad n))
                  (vector-set! sv 2 (double (vector-ref sv 1) an ad n))
                  (do ((i 3 (+ i 1))) ((< d i))
                    (vector-set! sv i
                      (add (vector-ref sv (- i 1))
                           (vector-ref sv 1)
                           (vector-ref sv (- i 2)) n)))
                  (do ((i 1 (+ i 1))) ((< d i))
                    (vector-set! bv i
                      (modulo (* (car (vector-ref sv i))
                                 (cdr (vector-ref sv i))) n)))
                  (let stage2 ((v v) (ps ps) (ds ds) (r r) (t t) (g 1))
                    (if (null? ps) (let ((g (gcd g n))) (if (< 1 g n) (list 2 g) #f))
                      (let ((v2d (+ v d d)) (alpha (modulo (* (car r) (cdr r)) n)))
                        (let loop ((ps ps) (ds ds) (g g))
                          (if (and (pair? ps) (< (car ps) v2d))
                              (loop (cdr ps) (cdr ds) (modulo (* g (+ (*
                                    (- (car r) (car (vector-ref sv (car ds))))
                                    (+ (cdr r) (cdr (vector-ref sv (car ds)))))
                                    (- alpha) (vector-ref bv (car ds)))) n))
                              (let* ((old-r r) (r (add r (vector-ref sv d) t n)))
                              (let ((g (gcd g n))) (if (< 1 g n) (list 2 g)
                                  (stage2 v2d ps ds r old-r g))))))))))))))))))

The only change we made was to replace variable d with i and variable r with v; since some implementations of Scheme don’t recognize differences in case, we couldn’t retain the original variable names. We reused the elliptic arithmetic functions add, double and multiply from the previous exercises.

Our ec-factor function is a drop-in replacement for the earlier factors function. An updated version of the function, with improved Pollard rho (the Brent variation) and Pollard p−1 (the two-stage improved standard continuation) functions, is shown on the next page. In this form, complicated factorizations are ten to fifty times faster than the old function.

The complete factors function is shown on the next page and at http://programmingpraxis.codepad.org/SdrzlWbh. Two sample factorizations are shown below:

> (factors (repunit 66))
Trial division: bound=1000
  Found factors (3 7 11 11 13 23 37 67)
  Remaining co-factor 58993628694531296147719957524688808978821367471004660551
Pollard rho: bound=500000, constant=1
  Found factor 4093, remaining co-factor 144132979952434146464011623563862225699
53913381628307
Pollard rho: bound=500000, constant=2
  Found non-prime factor 190056571
Trial division: bound=1000
Pollard rho: bound=500000, constant=1
  Found factor 21649, remaining co-factor 8779
  Factorization complete
Pollard rho: bound=500000, constant=3
  Found factor 513239, remaining co-factor 147761341791192537461208953746267179103
Pollard rho: bound=500000, constant=4
  Found factor 599144041, remaining co-factor 246620731710144034397913595783
Pollard rho: bound=500000, constant=5
Pollard p-1: b1=100000, b2=5000000
Elliptic curve 1: b1=50000, b2=2500000, s=1325338914
Elliptic curve 2: b1=50000, b2=2500000, s=1196705985
  In stage 2, found factor 183411838171, remaining co-factor 1344628210313298373
  Factorization complete
(3 7 11 11 13 23 37 67 4093 8779 21649 513239 599144041 183411838171 1344628210313298373)
> (factors (repunit 69))
Trial division: bound=1000
  Found factors (3 37 277)
  Remaining co-factor 3613722025274371844768956682314083036104696754516249101086646213
Pollard rho: bound=500000, constant=1
Pollard p-1: b1=100000, b2=5000000
  Found factor 203864078068831, remaining co-factor 17726134292546940492766254883101518975039516780123
Pollard p-1: b1=100000, b2=5000000
  Found factor 11111111111111111111111, remaining co-factor 1595352086329224644348978893
  Factorization complete
(3 37 277 203864078068831 11111111111111111111111 1595352086329224644348978893)

Pages: 1 2 3

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 621 other followers

%d bloggers like this: