Memfrob
November 10, 2020
We give a function that performs encryption, and leave it to the reader to wrap that in a function that handles files:
(define (memfrob str)
(define (frob c)
(integer->char (bitwise-xor (char->integer c) 42)))
(list->string (map frob (string->list str))))
> (memfrob (memfrob "Programming Praxis"))
"Programming Praxis"
You can run the program at http://ideone.com/RnJDWB.
A quick solution using standard Scheme:
(import (scheme base) (scheme write) (only (srfi 60) bitwise-xor) (only (org eip10 okmij myenv) assert)) (define (memfrob-byte byt) (bitwise-xor byt 42)) (assert (equal? '(42 0 43 41) (map memfrob-byte '(0 42 1 3)))) (define (memfrob-bytevector bytvec) (let* ((n (bytevector-length bytvec)) (r (make-bytevector n))) (do ((i 0 (+ i 1))) ((>= i n) r) (bytevector-u8-set! r i (memfrob-byte (bytevector-u8-ref bytvec i)))))) (assert (equal? #u8(42 0 43 41) (memfrob-bytevector #u8(0 42 1 3)))) (define (memfrob-string str) (utf8->string (memfrob-bytevector (string->utf8 str)))) (assert (string=? "Hello, World!" (memfrob-string (memfrob-string "Hello, World!"))))In Python:
def memfrob(msg): return bytes(c ^ 42 for c in msg)Input argument must be a bytes-like object.
Here are a few solutions in C. The first is a plain vanilla implementation, followed by an implementation that uses
memfrobfrom the GNU C library, and then an implementation that uses AVX2 intrinsics (the other solutions—compiled with optimizations—are still faster in my tests on a large file).#include <stdio.h> int main(void) { char buffer[BUFSIZ]; while (1) { size_t n = fread(buffer, 1, BUFSIZ, stdin); if (!n) break; for (int i = 0; i < n; ++i) buffer[i] ^= 42; fwrite(buffer, 1, n, stdout); } }#define _GNU_SOURCE #include <stdio.h> #include <string.h> int main(void) { char buffer[BUFSIZ]; while (1) { size_t n = fread(buffer, 1, BUFSIZ, stdin); if (!n) break; memfrob(buffer, n); fwrite(buffer, 1, n, stdout); } }// Requires -mavx2 compiler flag. #include <immintrin.h> #include <stdio.h> int main(void) { int bufsize = 8192; // Must be divisible by 32. char buffer[bufsize]; __m256i mask = _mm256_set1_epi8(42); while (1) { size_t n = fread(buffer, 1, bufsize, stdin); if (!n) break; for (int i = 0; i < bufsize; i += 32) { char* p = (char*)buffer + i; __m256i x = _mm256_loadu_si256((__m256i*)p); __m256i y = _mm256_xor_si256(x, mask); *((__m256i*)p) = y; } fwrite(buffer, 1, n, stdout); } return 0; }Example usage: