Memfrob
November 10, 2020
Memfrob is a light encryption algorithm that works by xor-ing 4210 = 001010102 with each input byte to create encrypted output; decryption is symmetric with encryption. Memfrob is roughly equivalent to ROT13 in cryptographic security.
Your task is to implement memfrob. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.
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: