Last active
January 31, 2023 23:30
-
-
Save Marc-B-Reynolds/7db198a050c422936be4520fb0655a6f to your computer and use it in GitHub Desktop.
50 example 64-bit bijections using CRC32-C opcode (brute force validate)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// if 'f' is the 64-bit input CRC32-C (with 'incoming' 32-bit value of zero) then | |
// there are 50 bijections (invertiable functions) which are a sum of f | |
// and a simple xorshift. So the follow two forms: | |
// | |
// f(x) ^ (x ^ (x << S)) | |
// f(x) ^ (x ^ (x >> S)) | |
// | |
// and 23 using a rotate instead of a shift: | |
// | |
// f(x) ^ (x ^ rot(x,S)) | |
// | |
// if 'c' is the 32-bit CRC32-C (one input is zero) and x0 & x1 are lower and | |
// upper 32-bit parts of 'x' then: | |
// | |
// f(x) = c(x1) + c^2(x0) | |
// | |
// which is a uniform 2^32 to 1 mapping. Allowing the 32-bit input (assumed to be | |
// zero above) to be any value is also a bijection (code doesn't demo this) since | |
// it just adds an XOR by constant to the total function which can be considered | |
// a second logical step (and XOR by constant is invertiable) | |
// requires m4ri (https://bitbucket.org/malb/m4ri/src/master) | |
// clang -O3 -march=native -Wall -Wextra -Wconversion -Wpedantic quick.c -o quick -lm4ri | |
// EYE WARNING: total garbage code..ripped from an even bigger mess | |
#include <assert.h> | |
#include <m4ri/m4ri_config.h> | |
#include <m4ri/m4ri.h> | |
#include <x86intrin.h> | |
#define PRINT_MATRIX | |
//#define PRINT_FAIL | |
/* | |
f(x) ^ (x ^ rot(x, 1)) | |
f(x) ^ (x ^ rot(x, 5)) | |
f(x) ^ (x ^ rot(x, 6)) | |
f(x) ^ (x ^ rot(x, 8)) | |
f(x) ^ (x ^ rot(x,15)) | |
f(x) ^ (x ^ rot(x,19)) | |
f(x) ^ (x ^ rot(x,20)) | |
f(x) ^ (x ^ rot(x,22)) | |
f(x) ^ (x ^ rot(x,23)) | |
f(x) ^ (x ^ rot(x,24)) | |
f(x) ^ (x ^ rot(x,25)) | |
f(x) ^ (x ^ rot(x,29)) | |
f(x) ^ (x ^ rot(x,30)) | |
f(x) ^ (x ^ rot(x,31)) | |
f(x) ^ (x ^ rot(x,33)) | |
f(x) ^ (x ^ rot(x,39)) | |
f(x) ^ (x ^ rot(x,49)) | |
f(x) ^ (x ^ rot(x,50)) | |
f(x) ^ (x ^ rot(x,54)) | |
f(x) ^ (x ^ rot(x,58)) | |
f(x) ^ (x ^ rot(x,60)) | |
f(x) ^ (x ^ rot(x,61)) | |
f(x) ^ (x ^ rot(x,62)) | |
f(x) ^ (x ^ (x>> 2)) | |
f(x) ^ (x ^ (x>> 3)) | |
f(x) ^ (x ^ (x>> 4)) | |
f(x) ^ (x ^ (x>> 5)) | |
f(x) ^ (x ^ (x>> 6)) | |
f(x) ^ (x ^ (x>> 7)) | |
f(x) ^ (x ^ (x>>12)) | |
f(x) ^ (x ^ (x>>13)) | |
f(x) ^ (x ^ (x>>19)) | |
f(x) ^ (x ^ (x>>22)) | |
f(x) ^ (x ^ (x>>23)) | |
f(x) ^ (x ^ (x>>26)) | |
f(x) ^ (x ^ (x>>27)) | |
f(x) ^ (x ^ (x>>28)) | |
f(x) ^ (x ^ (x>>29)) | |
f(x) ^ (x ^ (x>>31)) | |
f(x) ^ (x ^ (x<< 1)) | |
f(x) ^ (x ^ (x<< 3)) | |
f(x) ^ (x ^ (x<< 4)) | |
f(x) ^ (x ^ (x<< 7)) | |
f(x) ^ (x ^ (x<< 9)) | |
f(x) ^ (x ^ (x<<10)) | |
f(x) ^ (x ^ (x<<11)) | |
f(x) ^ (x ^ (x<<12)) | |
f(x) ^ (x ^ (x<<14)) | |
f(x) ^ (x ^ (x<<16)) | |
f(x) ^ (x ^ (x<<17)) | |
f(x) ^ (x ^ (x<<18)) | |
f(x) ^ (x ^ (x<<21)) | |
f(x) ^ (x ^ (x<<24)) | |
f(x) ^ (x ^ (x<<26)) | |
f(x) ^ (x ^ (x<<27)) | |
f(x) ^ (x ^ (x<<28)) | |
f(x) ^ (x ^ (x<<30)) | |
f(x) ^ (x ^ (x<<31)) | |
f(x) ^ (x ^ (x<<32)) | |
f(x) ^ (x ^ (x<<35)) | |
f(x) ^ (x ^ (x<<36)) | |
f(x) ^ (x ^ (x<<38)) | |
f(x) ^ (x ^ (x<<42)) | |
f(x) ^ (x ^ (x<<43)) | |
f(x) ^ (x ^ (x<<44)) | |
f(x) ^ (x ^ (x<<45)) | |
f(x) ^ (x ^ (x<<48)) | |
f(x) ^ (x ^ (x<<50)) | |
f(x) ^ (x ^ (x<<53)) | |
f(x) ^ (x ^ (x<<55)) | |
f(x) ^ (x ^ (x<<57)) | |
f(x) ^ (x ^ (x<<60)) | |
f(x) ^ (x ^ (x<<63)) | |
*/ | |
static inline uint32_t crc32c_64(uint64_t x, uint32_t k) { return (uint32_t)_mm_crc32_u64(k,x); } | |
// these are the two shift mixing functions and one rotate tested. | |
// don't have affine matrix support in this file: so K must be zero | |
#define K 0 | |
uint32_t shift = 1; | |
uint64_t ls_mix(uint64_t x) { return crc32c_64(x,K) ^ (x ^ (x>>shift)); } | |
uint64_t rs_mix(uint64_t x) { return crc32c_64(x,K) ^ (x ^ (x<<shift)); } | |
static inline uint64_t rot_64(uint64_t x, uint32_t n) { n &= 0x3f; return (x<<n) | (x>>(-n & 0x3f)); } | |
uint64_t c_mix(uint64_t x) { return crc32c_64(x,K) ^ (x ^ rot_64(x,shift)); } | |
//--------------------------------------------------------------------------------- | |
typedef uint64_t ufunc_64_t(uint64_t); | |
enum { | |
MAT_TEMP_1, | |
MAT_TEMP_2, | |
MAT_NUM | |
}; | |
// NOTE: no plans to multithread ATM (but I should abstract this a bit anyway) | |
// like at gettemp functions | |
typedef struct { | |
mzd_t* id; | |
uint32_t dim; | |
uint32_t n; | |
mzd_t* m[MAT_NUM]; | |
} mat_common_t; | |
mat_common_t mat_32_common; | |
mat_common_t mat_64_common; | |
mat_common_t mat_32h_common; | |
mat_common_t mat_64h_common; | |
void mat_init_i(mat_common_t* data, uint32_t dim) | |
{ | |
data->dim = dim; | |
data->id = mzd_init((rci_t)dim,(rci_t)dim); | |
mzd_set_ui(data->id, 1); | |
for(int i=0; i<MAT_NUM; i++) | |
data->m[i] = mzd_init((rci_t)dim,(rci_t)dim); | |
} | |
#define MAT_FREE(X) { mzd_free(X); (X)=0; } | |
void mat_free_i(mat_common_t* data) | |
{ | |
MAT_FREE(data->id); | |
for(int i=0; i<MAT_NUM; i++) { | |
MAT_FREE(data->m[i]); | |
} | |
} | |
// fill in a M4RI matrix (d) with row-major dense matrix | |
void mat_from_dense_64(mzd_t* d, uint64_t* s) | |
{ | |
for(rci_t y=0; y<64; y++) { | |
uint64_t row = s[y]; | |
for(rci_t x=0; x<64; x++) { | |
mzd_write_bit(d,x,y, (row & 1)); | |
row >>= 1; | |
} | |
} | |
} | |
void mat_init() | |
{ | |
mat_init_i(&mat_32_common, 32); | |
mat_init_i(&mat_32h_common, 33); | |
mat_init_i(&mat_64_common, 64); | |
mat_init_i(&mat_64h_common, 65); | |
} | |
void mat_free() | |
{ | |
mat_free_i(&mat_32_common); | |
mat_free_i(&mat_32h_common); | |
mat_free_i(&mat_64_common); | |
mat_free_i(&mat_64h_common); | |
} | |
uint64_t mat_dense_from_func_64(uint64_t* m, uint64_t (*f)(uint64_t)) | |
{ | |
// an input of zero should yield a zero result. if not | |
// work on the assumption that it's 'f' is actually | |
// affine. | |
uint64_t t = f(0); | |
for(uint64_t i=0; i<64; i++) { m[i]=0; } | |
// build up matrix using single bit inputs | |
for(int i=0; i<64; i++) { | |
uint64_t p = UINT64_C(1)<<i; | |
uint64_t r = f(p) ^ t; | |
for(int j=0; j<64; j++) { | |
m[j] ^= ((r & (UINT64_C(1)<<j)) != 0) ? p : 0; | |
} | |
} | |
return t; | |
} | |
void mat_print(mzd_t* M) | |
{ | |
#if 1 | |
rci_t n = M->nrows; | |
for (rci_t r=0; r<n; r++) { | |
for (rci_t c=0; c<n; c++) { | |
rci_t v = mzd_read_bit(M,r,c); | |
putchar(v!=0 ? '1':'.'); | |
} | |
// uses internals of m4ri & is fragile | |
if (n == 32) { printf(" %08x", ((uint32_t*)(M->data))[r<<2]); } | |
putchar('\n'); | |
} | |
#else | |
mzd_print(M); | |
#endif | |
} | |
// multiply wrapper | |
inline mzd_t* mat_mul(mzd_t* r, mzd_t* a, mzd_t* b) { return mzd_mul(r,a,b,0); } | |
uint32_t mat_inv_k(mzd_t* I, mzd_t* M, mat_common_t* data) | |
{ | |
mzd_t* id = data->id; | |
mzd_t* t = data->m[MAT_TEMP_1]; | |
mzd_inv_m4ri(I,M,0); | |
mat_mul(t,I,M); | |
return (uint32_t)mzd_equal(t,id); | |
} | |
uint32_t mat_inv_64(mzd_t* I, mzd_t* M) { return mat_inv_k(I,M, &mat_64_common); } | |
// allocates and frees every time: meh..don't care here | |
void f2_bijection_test_64(ufunc_64_t* f) | |
{ | |
uint64_t m[64] = {0}; | |
uint64_t t = mat_dense_from_func_64(m,f); | |
if (t == 0) { | |
mzd_t* F = mzd_init(64,64); | |
mzd_t* R = mzd_init(64,64); | |
mat_from_dense_64(F,m); | |
if (mat_inv_64(R,F)) { | |
printf("good\n"); | |
#if defined(PRINT_MATRIX) | |
mat_print(F); printf("\n"); | |
mat_print(R); printf("\n"); | |
#endif | |
} | |
else printf("no inverse\n"); | |
mzd_free(F); | |
mzd_free(R); | |
} | |
else printf("no affine support here\n"); | |
} | |
int main() | |
{ | |
mat_init(); | |
for(uint32_t i=1; i<64; i++) { | |
shift = i; | |
printf("crc64(x) ^ (x ^ rot(x,%2d)) : ",i); | |
f2_bijection_test_64(&c_mix); | |
} | |
// all greater than 32 are non-invertiable | |
for(uint32_t i=1; i<32; i++) { | |
shift = i; | |
printf("crc64(x) ^ (x ^ (x>>%2d)) : ",i); | |
f2_bijection_test_64(&ls_mix); | |
} | |
for(uint32_t i=1; i<64; i++) { | |
shift = i; | |
printf("crc64(x) ^ (x ^ (x<<%2d)) : ",i); | |
f2_bijection_test_64(&rs_mix); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment