descriptor.c (1672B)
1 2 #include "short_types.h" 3 #include <stdlib.h> 4 #include <stdio.h> 5 6 static const char CHECKSUM_CHARSET[] = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; 7 8 static const char INPUT_CHARSET[] = 9 "0123456789()[],'/*abcdefgh@:$%{}" 10 "IJKLMNOPQRSTUVWXYZ&+-.;<=>?!^_|~" 11 "ijklmnopqrstuvwxyzABCDEFGH`#\"\\ "; 12 13 static inline int charset_find(char ch) { 14 for (size_t i = 0; i < sizeof(INPUT_CHARSET); i++) { 15 if (INPUT_CHARSET[i] == ch) 16 return i; 17 } 18 return -1; 19 } 20 21 static u64 polymod(u64 c, int val) 22 { 23 u8 c0 = c >> 35; 24 c = ((c & 0x7ffffffff) << 5) ^ val; 25 if (c0 & 1) c ^= 0xf5dee51989; 26 if (c0 & 2) c ^= 0xa9fdca3312; 27 if (c0 & 4) c ^= 0x1bab10e32d; 28 if (c0 & 8) c ^= 0x3706b1677a; 29 if (c0 & 16) c ^= 0x644d626ffd; 30 return c; 31 } 32 33 34 int descriptor_checksum(const char *descriptor, int desc_size, char *checksum, 35 int checksum_capacity) 36 { 37 if (checksum_capacity < 8+1) 38 return 0; 39 40 checksum[0] = 0; 41 42 int j; 43 u64 c = 1; 44 int cls = 0; 45 int clscount = 0; 46 47 for (int i = 0; i < desc_size; i++) { 48 char ch = descriptor[i]; 49 int pos = charset_find(ch); 50 if (pos == -1) { 51 checksum[0] = 0; 52 return 0; 53 } 54 // Emit a symbol for the position inside the group, for every character. 55 c = polymod(c, pos & 31); 56 57 // Accumulate the group numbers 58 cls = cls * 3 + (pos >> 5); 59 60 if (++clscount == 3) { 61 c = polymod(c, cls); 62 cls = 0; 63 clscount = 0; 64 } 65 } 66 67 if (clscount > 0) 68 c = polymod(c, cls); 69 70 // Shift further to determine the checksum. 71 for (j = 0; j < 8; ++j) 72 c = polymod(c, 0); 73 74 // Prevent appending zeroes from not affecting the checksum. 75 c ^= 1; 76 77 for (j = 0; j < 8; ++j) 78 checksum[j] = CHECKSUM_CHARSET[(c >> (5 * (7 - j))) & 31]; 79 80 checksum[8] = 0; 81 82 return 8; 83 }