[MLton] Factoring fun

Wesley W. Terpstra terpstra@gkec.tu-darmstadt.de
Thu, 20 Jan 2005 01:13:16 +0100


--vkogqOf2sHV7VnPd
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

In case anyone is interested in benchmarking MLton vs. other SML compilers
with a simple factoring algorithm, attached is factor.sml. This outputs
factored numbers in the same format as the coreutils factor present on every
Linux machine. Of course, that program only supports 64bit integers, the SML
program handles LargeInts.

./factor 85070591730234615865843651857942052865
./factor 98127489127489127498172489172489174987111 # takes some time

Just remember: the time needed is the squareroot of the 2nd largest factor.
So, don't expect it to break 512 bit RSA keys (where the 2nd largest factor
has ~256 bits -> 128 bits to search).

This program is intentionally unoptimized; I wanted to see how well MLton
managed with human-friendly code. Not bad. =)

-- 
Wesley W. Terpstra

--vkogqOf2sHV7VnPd
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="factor.sml"

open LargeInt

fun gcd (a, b) = if a = 0 then b else gcd (b mod a, a)

fun exp (x, 0, n) = 1
  | exp (x, 1, n) = x
  | exp (x, e, n) = exp (x*x mod n, e div 2, n) * exp (x, e mod 2, n) mod n

fun sort nil = nil
  | sort (p :: r) = 
    let val (s, b) = List.partition (fn x => x < p) r
    in sort s @ p :: sort b end

fun isPrime n = 
  let
    fun chomp (c, e) =
      if c mod 2 = 0 then chomp (c div 2, e+1) else (c, e)
    val (c, e) = chomp (n-1, 0)
    
    fun checkPow (w, e) =
      e > 0 andalso (w+1 = n orelse checkPow (w*w mod n, e-1))
    fun millerTest w = 
      let val v = exp (w, c, n)
      in v = 1 orelse checkPow (v, e) end
  in
    List.foldl (fn (w, a) => a andalso millerTest (1 + w mod (n-1))) true
      [ 2, 3, 5, 7, 11, 13, 17, 111, 123, 345 ]
  end

fun findafact n =
  let
    val start = Word.toLargeInt (MLton.Random.rand ()) mod n
    fun f x = (x*x + 2) mod n
    fun loop x y =
      let val g = gcd (n, n+x-y)
      in if g = 1 then loop (f x) (f (f y)) else g end
  in loop start (f start) end

fun factor n =
  let
    fun suck n l =
      if n = 1 then l else
      if isPrime n then n :: l else
      let val x = findafact n 
      in suck x (suck (n div x) l) end
  in sort (suck n []) end

val n = (valOf o fromString o hd o CommandLine.arguments) ()
val l = factor n

val () = print (toString n ^ ":")
val () = app (fn x => print (" " ^ toString x)) l
val () = print "\n"

--vkogqOf2sHV7VnPd--