>From 
>[https://github.com/mratsim/number-theory/blob/12c54a7476327cf9ab00989c9964732e3eb68be7/src/modular_arithmetic.nim](https://github.com/mratsim/number-theory/blob/12c54a7476327cf9ab00989c9964732e3eb68be7/src/modular_arithmetic.nim)

Modular addition 
    
    
    proc addmod*[T: SomeInteger](a, b, m: T): T =
      ## Modular addition
      
      let a_m = if a < m: a
                else: a mod m
      if b == 0.T:
        return a_m
      let b_m = if b < m: b
                else: b mod m
      
      # We don't do a + b to avoid overflows
      # But we know that m at least is inferior to biggest T
      
      let b_from_m = m - b_m
      if a_m >= b_from_m:
        return a_m - b_from_m
      return m - b_from_m + a_m
    
    
    Run

Modular multiplication 
    
    
    proc mulmod*[T: SomeInteger](a, b, m: T): T =
      ## Modular multiplication
      
      var a_m = a mod m
      var b_m = b mod m
      if b_m > a_m:
        swap(a_m, b_m)
      while b_m > 0.T:
        if b_m.isOdd:
          result = addmod(result, a_m, m)
        #a_m = doublemod(a_m, m)
        a_m = (a_m shl 1) - (if a_m >= (m - a): m else: 0)
        b_m = b_m shr 1
    
    
    Run

Modular inversion (via GCD, so can return the GCD) 
    
    
    proc invmod*[T:SomeInteger](a, m: T): T =
      ## Modular multiplication inverse
      ## Input:
      ##   - 2 positive integers a and m
      ## Result:
      ##   - An integer z that solves `az ≡ 1 mod m`
      # Adapted from Knuth, The Art of Computer Programming, Vol2 p342
      # and Menezes, Handbook of Applied Cryptography (HAC), p610
      # to avoid requiring signed integers
      # http://cacr.uwaterloo.ca/hac/about/chap14.pdf
      
      # Starting from the extended GCD formula (Bezout identity),
      # `ax + by = gcd(x,y)`
      # with input x,y and outputs a, b, gcd
      # We assume a and m are coprimes, i.e. gcd is 1, otherwise no inverse
      # `ax + my = 1`
      # `ax + my ≡ 1 mod m`
      # `ax ≡ 1 mod m``
      # Meaning we can use the Extended Euclid Algorithm
      # `ax + by` with
      # a = a, x = result, b = m, y = 0
      
      var
        a = a
        x = 1.T
        b = m
        y = 0.T
        oddIter = true # instead of requiring signed int, we keep track of 
even/odd iterations which would be in negative
      
      while b != 0.T:
        let
          (q, r) = divmod(a,b)
          t = x + q * y
        x = y; y = t; a = b; b = r
        oddIter = not oddIter
      
      if a != 1.T:
        # a now holds the gcd(a, m) and should equal 1
        raise newException(ValueError, "No modular inverse exists")
      
      if oddIter:
        return x
      return m - x
    
    
    Run

The whole point of proof-of-work is to have non-trivial computation. 
Factorizing small number is very fast hence you need them at a decent bit-width 
but if you're really desperate, I have an arbitrary bigint factorization 
algorithm in BrainFuck here ;): 
[https://github.com/numforge/laser/blob/d1e6ae61/examples/ex07_jit_brainfuck_src/factor.bf](https://github.com/numforge/laser/blob/d1e6ae61/examples/ex07_jit_brainfuck_src/factor.bf)

Reply via email to