I will preface this by saying that I made this for fun; I have absolutely no formal knowledge on cryptography or error correction. Do not use this algorithm in anything remotely important.
I was kind of bored a few days ago, so I decided to write a simple function to take some data and return an easily memorable (but not necessarily secure :p) checksum of it. The output format is a number of digits in base 36, between 0
and z
(think of it like hexadecimal, but with all the letters used).
Your program or function will take two inputs: data
, and block_size
. The data
will be a list of values 0
to 255
, and the block_size
will be at least 4
. It will return a base 36 string (or list of values 0-36) with the length block_size
.
Using [182, 109, 211, 144, 65, 109, 105, 135, 151, 233]
and 4
as the inputs, this is how you would find the checksum:
The length of the
data
is padded with zeroes to a multiple of theblock_size
182, 109, 211, 144, 65, 109, 105, 135, 151, 233, 0, 0
The
data
is broken into blocks based on theblock_size
182 109 211 144 65 109 105 135 151 233 0 0
For each item
n
of the resulting block, take the sum of all items at positionn
in one of the above blocks mod 256182 109 211 144 + 65 109 105 135 + 151 233 0 0 -------------------- 142 195 60 23
Take the binary representation of each item in the result
10001110 11000011 00111100 00010111
For each item, add the least significant five bits of the next (wrapping) item, and the least significant bit of the (wrapping) item after that (note that this value can be higher than
256
)10001110 11000011 00111100 00010111 + 00011 11100 10111 01110 + 0 1 0 1 -------------------------------------------- 10010001 11100000 01010011 00100110
Convert back to decimal, and take the mod 36
1, 8, 11, 2
Covert into base 36
18b2
A reference implementation can be found here. Input and output can be in any reasonable manner.
This is code-golf, so shortest in bytes per language wins!
Test cases
[]; 8 -> 00000000
[0, 1, 2, 3, 4, 5, 6, 7]; 8 -> 14589cd8
[0, 1, 2, 3, 4, 5, 6, 7]; 6 -> eb589b
[0, 4, 2, 1]; 48 -> 473100000000000000000000000000000000000000000000
[195, 180, 1, 0]; 4 -> 0123
[31, 32, 65, 4]; 4 -> wxyz
[20, 8, 247, 41]; 4 -> tw4p
[250, 175, 225, 200]; 4 -> ewhb
[33]; 3 -> (does not need to be handled)
paddb
/_mm_add_epi8
, reducing to 4 elements if you used a wider vector in the main loop. Then take that 4-byte "word" SIMD-byte-add two rotated and masked copies of it. (x + rotl(x, 8)&0x1f1f1f1f + rotl(x, 16)&0x01010101
where + is a SIMD byte add). It's very likely not a good checksum, but can run very fast on modern CPUs, just as fast as a simple sum of 4-byte integer elements. (Or faster for large unaligned buffers; group at the end.) \$\endgroup\$