packages feed

disco-0.1.0.0: example/rsa.disco

import num
import list

-- Implementation of RSA encryption algorithm.
-- Reference: https://simple.wikipedia.org/wiki/RSA_(algorithm)

-- To use, first call `getKeys` with two prime numbers, which returns
-- two pairs. The first pair is the public key, the second is the
-- private key. These keys, along with the `encrypt` and `decrypt`
-- functions can be used to encrypt and decrypt lists of natural
-- numbers.

encrypt : N * N -> List(N) -> List(N)
encrypt key xs = each (encrypt1 key, xs)

decrypt : N * N -> List(N) -> List(N)
decrypt = encrypt

-- takes two primes, returns a pair of pairs containing the RSA public/private keys
-- prime -> prime -> (public key, private key)
getKeys : N -> N -> (N * N) * (N * N)
getKeys p1 p2 =
  let m = p1 * p2,
      totient = (p1 .- 1)*(p2 .- 1),
      e = getPubExp 2 totient
  in ((m, e), (m, getPrivExp e totient))

-- guess -> totient -> e
getPubExp : N -> N -> N
getPubExp e totient =
  {? e                          if gcd(e, totient) == 1
   , getPubExp (e+1) totient    otherwise
  ?}

gcd : N*N -> N
gcd (a, 0) = a
gcd (a, b) = gcd (b, a mod b)

getPrivExp : N -> N -> N
getPrivExp e totient =
  let t = inverse (0,1) (totient,e)
  in {? abs t              if t>=0
      , abs (t+totient)    otherwise
     ?}


-- Implemented using Extended Euclidean Algorithm (reference:
-- https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Computing_multiplicative_inverses_in_modular_structures)
inverse : (Z * Z) -> (Z * Z) -> Z
inverse (t,newt) (r,newr) =
  {? t                                                                    if newr==0
   , let q = r // newr in (inverse (newt, t-q*newt) (newr,r-q*newr))      otherwise
  ?}

-- encrypt1 : msg -> public key (mod,exp) -> encrypted msg
-- encrypts one single number
encrypt1 : Nat * Nat -> Nat -> Nat
encrypt1 (m, e) msg = modPower msg e m

-- decrypts one single number
decrypt1 : Nat * Nat -> Nat -> Nat
decrypt1 = encrypt1

-- modPower : n -> power -> modulus -> nat
-- Exponentiating by squaring algorithm reference:
-- https://simple.wikipedia.org/wiki/Exponentiation_by_squaring
modPower : Nat -> Nat -> Nat -> Nat
modPower n p m =
  {? 1                                     if p==0
   , n % m                                 if p==1
   , (modPower (n^2) (p//2) m) % m         if (even p)
   , (n * (modPower (n^2) (p//2) m)) % m   if (p>2) && (odd p)
  ?}