I got tired of using factorial and fibonacci as benchmarks for my
research, so I threw together an implementation of the RSA public-key
cryptography system in Scheme.
Automatic support for arbitrarily large numbers makes the implementation
feel more natural than an equivalent implementation in other languages.
I also learned that gcd, used for coprimality testing, has been a part
of the Scheme standard since at least R5RS.
The short implementation is appended below.
Note: I have also created an implementation of the Fermat and
Solovay-Strassen primality
tests,
useful for the key-generation phase of RSA.
   
  
  Code
;; Mathematical routines.
; extended-gcd(a,b) = (x,y), such that a*x + b*y = gcd(a,b)
(define (extended-gcd a b)
  (if (= (modulo a b) 0)
      (cons 0 1)
      (let* ((x:y (extended-gcd b (modulo a b)))
             (x (car x:y))
             (y (cdr x:y)))
        (cons y (- x (* y (quotient a b)))))))
; modulo-inverse(a,n) = b, such that a*b = 1 [mod n].
(define (modulo-inverse a n)
  (modulo (car (extended-gcd a n)) n))
; totient(n) = (p - 1)*(q - 1), 
;  where pq is the prime factorization of n.
(define (totient p q) (* (- p 1) (- q 1)))
; square(x) = x^2
(define (square x) (* x x))
; modulo-power(base,exp,n) = base^exp [mod n]
(define (modulo-power base exp n)
  (if (= exp 0)
      1
      (if (odd? exp)
          (modulo (* base (modulo-power base (- exp 1) n)) n)
          (modulo (square (modulo-power base (/ exp 2) n)) n))))
;; RSA routines.
; A legal public exponent e is between
;  1 and totient(n), and gcd(e,totient(n)) = 1
(define (is-legal-public-exponent? e p q)
  (and (< 1 e) 
       (< e (totient p q))
       (= 1 (gcd e (totient p q)))))
; The private exponent is the inverse of the public exponent, mod n.
(define (private-exponent e p q) 
  (if (is-legal-public-exponent? e p q)
      (modulo-inverse e (totient p q))
      (error "Not a legal public exponent for that modulus.")))
; An encrypted message is c = m^e [mod n].
(define (encrypt m e n)
  (if (> m n)
      (error "The modulus is too small to encrypt the message.")
      (modulo-power m e n)))
; A decrypted message is m = c^d [mod n].
(define (decrypt c d n)
  (modulo-power c d n))
;; RSA example.
(define p 41)       ; A "large" prime.
(define q 47)       ; Another "large" prime.
(define n (* p q))  ; The public modulus.
(define e 7)                        ; The public exponent.
(define d (private-exponent e p q)) ; The private exponent.
(define plaintext  42)           
(define ciphertext (encrypt plaintext e n)) 
(define decrypted-ciphertext (decrypt ciphertext d n))
(display "The plaintext is:            ")
(display plaintext)
(newline)
(display "The ciphertext is:           ")
(display ciphertext)
(newline)
(display "The decrypted ciphertext is: ")
(display decrypted-ciphertext)
(newline)
(if (not (= plaintext decrypted-ciphertext))
    (error "RSA fail!"))
    
  
Twitter: @mattmight
Instagram: @mattmight
LinkedIn: matthewmight
Mastodon: @mattmight@mathstodon.xyz
Sub-reddit: /r/mattmight