commit 22275f311cd1999bbf67c40bbf0df5b71bf84d7b
parent 870da62a1e970a9beb4cbab4a234c229bc300669
Author: Daniel Barlow <dan@telent.net>
Date: Sun, 10 Sep 2023 12:14:39 +0100
anoia: add simple hash function and base64 encoder
Diffstat:
2 files changed, 53 insertions(+), 1 deletion(-)
diff --git a/pkgs/anoia/init.fnl b/pkgs/anoia/init.fnl
@@ -13,4 +13,47 @@
(fn system [s] (assert (os.execute s)))
-{ : merge : split : file-exists? : system }
+(fn hash [str]
+ (accumulate [h 5381
+ c (str:gmatch ".")]
+ (+ (* h 33) (string.byte c))))
+
+
+(local
+ base64-indices
+ (doto [
+ "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P"
+ "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z" "a" "b" "c" "d" "e" "f"
+ "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v"
+ "w" "x" "y" "z" "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "-" "_"
+ ]
+ (tset 0 "A")))
+
+;; local function base64(s)
+;; local byte, rep = string.byte, string.rep
+;; local pad = 2 - ((#s-1) % 3)
+;; s = (s..rep('\0', pad)):gsub("...", function(cs)
+;; local a, b, c = byte(cs, 1, 3)
+;; return bs[a>>2] .. bs[(a&3)<<4|b>>4] .. bs[(b&15)<<2|c>>6] .. bs[c&63]
+;; end)
+;; return s:sub(1, #s-pad) .. rep('=', pad)
+;; end
+
+(fn base64url [s]
+ "URL-safe Base64-encoded form of s (no trailing padding)"
+ (let [pad (- 2 (% (- (# s) 1) 3))
+ bs base64-indices
+ blank (string.rep "\0" pad)
+ s (-> (.. s blank)
+ (: :gsub
+ "..."
+ (fn [cs]
+ (let [(a b c) (string.byte cs 1 3)]
+ (.. (. bs (rshift a 2))
+ (. bs (bor (lshift (band a 3) 4) (rshift b 4)))
+ (. bs (bor (lshift (band b 15) 2) (rshift c 6)))
+ (. bs (band c 63)))))))]
+ (s:sub 1 (- (# s) pad))))
+
+
+{ : merge : split : file-exists? : system : hash : base64url }
diff --git a/pkgs/anoia/test.fnl b/pkgs/anoia/test.fnl
@@ -0,0 +1,9 @@
+(local { : hash : base64url } (require :anoia))
+
+(assert (= (hash "") 5381))
+
+;; these examples from https://theartincode.stanis.me/008-djb2/
+(assert (= (hash "Hello") 210676686969))
+(assert (= (hash "Hello!") 6952330670010))
+
+(assert (= (base64url "hello world") "aGVsbG8gd29ybGQ"))