Add chez-crypto: OpenSSL libcrypto bindings + jerboa crypto modules

ober

56b40dffddd20f5ee617f508271d343ebc9f30f1

diff --git a/Makefile b/Makefile
index 9b78543..7b53799 100644
--- a/Makefile
+++ b/Makefile
@@ -1,9 +1,9 @@
 SCHEME = scheme
 LIBDIRS = lib
 # External chez-* library paths for wrapper modules
-CHEZ_EXT_LIBDIRS = $(HOME)/mine/chez-https/src:$(HOME)/mine/chez-ssl/src:$(HOME)/mine/chez-zlib/src:$(HOME)/mine/chez-pcre2:$(HOME)/mine/chez-yaml:$(HOME)/mine/chez-leveldb:$(HOME)/mine/chez-epoll/src:$(HOME)/mine/chez-inotify/src
+CHEZ_EXT_LIBDIRS = $(HOME)/mine/chez-https/src:$(HOME)/mine/chez-ssl/src:$(HOME)/mine/chez-zlib/src:$(HOME)/mine/chez-pcre2:$(HOME)/mine/chez-yaml:$(HOME)/mine/chez-leveldb:$(HOME)/mine/chez-epoll/src:$(HOME)/mine/chez-inotify/src:$(HOME)/mine/chez-crypto/src
 # Shared object paths for FFI-based chez-* libraries
-CHEZ_EXT_LDPATH = $(HOME)/mine/chez-ssl:$(HOME)/mine/chez-zlib:$(HOME)/mine/chez-pcre2:$(HOME)/mine/chez-leveldb:$(HOME)/mine/chez-epoll:$(HOME)/mine/chez-inotify
+CHEZ_EXT_LDPATH = $(HOME)/mine/chez-ssl:$(HOME)/mine/chez-zlib:$(HOME)/mine/chez-pcre2:$(HOME)/mine/chez-leveldb:$(HOME)/mine/chez-epoll:$(HOME)/mine/chez-inotify:$(HOME)/mine/chez-crypto
 
 .PHONY: test test-reader test-core test-runtime test-stdlib test-ffi test-modules test-expanded test-wrappers clean
 
@@ -63,6 +63,9 @@ test-wrappers:
 	@LD_LIBRARY_PATH="$(CHEZ_EXT_LDPATH):$$LD_LIBRARY_PATH" \
 		$(SCHEME) --libdirs "$(LIBDIRS):$(CHEZ_EXT_LIBDIRS)" --script tests/test-wrapper-inotify.ss 2>/dev/null \
 		|| echo "  inotify: SKIP (requires chez_inotify_shim.so)"
+	@LD_LIBRARY_PATH="$(CHEZ_EXT_LDPATH):$$LD_LIBRARY_PATH" \
+		$(SCHEME) --libdirs "$(LIBDIRS):$(CHEZ_EXT_LIBDIRS)" --script tests/test-wrapper-crypto.ss 2>/dev/null \
+		|| echo "  crypto: SKIP (requires chez_crypto_shim.so)"
 
 test-all: test test-wrappers
 
diff --git a/lib/std/crypto/cipher.sls b/lib/std/crypto/cipher.sls
new file mode 100644
index 0000000..51ea630
--- /dev/null
+++ b/lib/std/crypto/cipher.sls
@@ -0,0 +1,19 @@
+#!chezscheme
+;;; :std/crypto/cipher -- Symmetric encryption (wraps chez-crypto)
+
+(library (std crypto cipher)
+  (export
+    encrypt decrypt
+    cipher-key-length cipher-iv-length cipher-block-size
+    make-cipher-ctx free-cipher-ctx
+    encrypt-init! encrypt-update! encrypt-final!
+    decrypt-init! decrypt-update! decrypt-final!)
+
+  (import (only (chez-crypto)
+    encrypt decrypt
+    cipher-key-length cipher-iv-length cipher-block-size
+    make-cipher-ctx free-cipher-ctx
+    encrypt-init! encrypt-update! encrypt-final!
+    decrypt-init! decrypt-update! decrypt-final!))
+
+  ) ;; end library
diff --git a/lib/std/crypto/etc.sls b/lib/std/crypto/etc.sls
new file mode 100644
index 0000000..bc58b5d
--- /dev/null
+++ b/lib/std/crypto/etc.sls
@@ -0,0 +1,9 @@
+#!chezscheme
+;;; :std/crypto/etc -- Crypto utilities (wraps chez-crypto)
+
+(library (std crypto etc)
+  (export random-bytes random-bytes! crypto-error-string)
+
+  (import (only (chez-crypto) random-bytes random-bytes! crypto-error-string))
+
+  ) ;; end library
diff --git a/lib/std/crypto/hmac.sls b/lib/std/crypto/hmac.sls
new file mode 100644
index 0000000..8351010
--- /dev/null
+++ b/lib/std/crypto/hmac.sls
@@ -0,0 +1,9 @@
+#!chezscheme
+;;; :std/crypto/hmac -- HMAC message authentication (wraps chez-crypto)
+
+(library (std crypto hmac)
+  (export hmac hmac-md5 hmac-sha1 hmac-sha256 hmac-sha384 hmac-sha512)
+
+  (import (only (chez-crypto) hmac hmac-md5 hmac-sha1 hmac-sha256 hmac-sha384 hmac-sha512))
+
+  ) ;; end library
diff --git a/lib/std/crypto/kdf.sls b/lib/std/crypto/kdf.sls
new file mode 100644
index 0000000..9203b9b
--- /dev/null
+++ b/lib/std/crypto/kdf.sls
@@ -0,0 +1,9 @@
+#!chezscheme
+;;; :std/crypto/kdf -- Key derivation functions (wraps chez-crypto)
+
+(library (std crypto kdf)
+  (export scrypt)
+
+  (import (only (chez-crypto) scrypt))
+
+  ) ;; end library
diff --git a/lib/std/crypto/pkey.sls b/lib/std/crypto/pkey.sls
new file mode 100644
index 0000000..46ceb21
--- /dev/null
+++ b/lib/std/crypto/pkey.sls
@@ -0,0 +1,9 @@
+#!chezscheme
+;;; :std/crypto/pkey -- Public key cryptography (wraps chez-crypto)
+
+(library (std crypto pkey)
+  (export ed25519-keygen ed25519-sign ed25519-verify)
+
+  (import (only (chez-crypto) ed25519-keygen ed25519-sign ed25519-verify))
+
+  ) ;; end library
diff --git a/tests/test-wrapper-crypto.ss b/tests/test-wrapper-crypto.ss
new file mode 100644
index 0000000..4523e3f
--- /dev/null
+++ b/tests/test-wrapper-crypto.ss
@@ -0,0 +1,51 @@
+#!chezscheme
+(import (chezscheme)
+        (std crypto cipher)
+        (std crypto hmac)
+        (std crypto pkey)
+        (std crypto kdf)
+        (std crypto etc))
+
+(define pass-count 0)
+(define fail-count 0)
+
+(define-syntax chk
+  (syntax-rules (=>)
+    [(_ expr => expected)
+     (let ([result expr] [exp expected])
+       (if (equal? result exp) (set! pass-count (+ pass-count 1))
+         (begin (set! fail-count (+ fail-count 1))
+                (display "FAIL: ") (write 'expr)
+                (display " => ") (write result)
+                (display " expected ") (write exp) (newline))))]))
+
+;; Random bytes
+(let ([bv (random-bytes 16)])
+  (chk (= (bytevector-length bv) 16) => #t))
+
+;; HMAC
+(let ([h (hmac-sha256 "key" "data")])
+  (chk (= (bytevector-length h) 32) => #t))
+
+;; Cipher round-trip
+(let* ([key (random-bytes 32)]
+       [iv  (random-bytes 16)]
+       [plain (string->utf8 "test")]
+       [enc (encrypt "aes-256-cbc" key iv plain)]
+       [dec (decrypt "aes-256-cbc" key iv enc)])
+  (chk (equal? plain dec) => #t))
+
+;; Ed25519
+(let-values ([(priv pub) (ed25519-keygen)])
+  (let ([sig (ed25519-sign priv "msg")])
+    (chk (ed25519-verify pub "msg" sig) => #t)
+    (chk (ed25519-verify pub "bad" sig) => #f)))
+
+;; Scrypt
+(let ([k (scrypt "pass" "salt" 32)])
+  (chk (= (bytevector-length k) 32) => #t))
+
+(display "  crypto: ") (display pass-count) (display " passed")
+(when (> fail-count 0) (display ", ") (display fail-count) (display " failed"))
+(newline)
+(when (> fail-count 0) (exit 1))