Logos, Thumos & Code

Let’s write some code

Base64 Encoding & Decoding

Looking for a first project to play with, I remembered CryptoPals. I did some of it several years ago, and it was fun, so I thought it could be a good way to get familiar with Common Lisp, at least the first set. With that in mind, I had a look, and hear we are!

The very first challenge is about hex and base64 encoding. The first time around I just used available libraries for both (I used Rust at the time), but the point of this was to open some black boxes, so I decided to implement everything from scratch!

I’ve used Base64 encoding several times in the past, both in my personal projects, and during my day job, and while I understood conceptually what it was, I had never tried to implement it myself. After a quick search I found a very nice description of the algorithm at b64encode.com, I opened Emacs, and got to work.

The algorithm is very well explained in the link above, so I will not try to do it again, but this is what I came up with for the encoding part:

(defun get-n-bits (n byte pos)
  "Get n bits from byte, starting at pos"
  (when byte
    (ldb (byte n pos) byte)))

(defun combine-3 (bytes start end)
  "Combine an array of three bytes into a single integer"
  (let ((seq (subseq bytes start (min (length bytes) end))))
    (values 
     (when seq 
       (logior (ash (try-aref seq 0) 16)
               (ash (try-aref seq 1) 8)
               (ash (try-aref seq 2) 0)))
     (+ 1 (- (min (length bytes) end) start)))))

(defun bytes-to-b64 (bytes)
  "Base64 Encode an array of bytes into a string"
  (with-output-to-string (str)
    (do* ((start 0 (+ start 3))
          (end 3 (+ end 3)))
         ((>= start (length bytes)) str)
      (multiple-value-bind (combined byte-count) (combine-3 bytes start end)
        (dotimes (n byte-count)
          (princ (char *b64-lookup* (get-n-bits 6 combined (- 18 (* n 6)))) str))
        (dotimes (n (- 4 byte-count))
          (princ #\= str))))))

It was much shorter than I thought it would be, so I was quite pleased! I was suprised with how handy the ldb function was, and how intuitive was to write to a string as a stream.

You can find the full source here.

After writing the code I went around to see how other people implemented this, and I found this, written 10 years ago. It’s a lot nicer than my version, and I love how they also used the input string as a stream, calling read-char, that simplifies things. I’m still not sold on the loop macro. Seems easy to read, but I find it a bit too magical, and unintuitive to write. But I guess that’s because I’m not familiar with it. I’ll have to try to use it in the future!