base32.c
#include <stdint.h>
#include <unistd.h>
#include "common.h"
#include "types.h"
/**
* Base32 encoding/decoding - for now only supports presenting blake3 hashes (32
* bytes).
*/
/**
* Inspired by the base32 implementation here:
*
* https://sourceforge.net/p/cyoencode/code/HEAD/tree/trunk/src/CyoDecode.c
*
* Basically, the idea is to allocate a much too large array, fill it with 0xff
* and plug in the values from the alphabet in their corresponding holes.
*/
/* clang-format off */
static u8 BASE32[0x80] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
/* clang-format on */
/**
* Known limitations:
*
* (1) processes exactly 53 characters, so not a general base32 decoder
* (2) assumes that all characters are valid base32 characters
* (3) no validation that input values are <= 0x80 (so out-of-bounds is
* possible)
* (4) does not validate the 33rd byte to be a "1" meaning blake3.
*/
void
b32dec(u8 *dst, char const *in)
{
int i, r, off;
u8 v[8];
for (r = 0; r < 6; r++) {
off = 8 * r;
for (i = 0; i < 8; i++)
v[i] = BASE32[(int)in[off + i]];
off = 5 * r;
dst[off] = v[0] << 3 | v[1] >> 2;
dst[off + 1] = v[1] << 6 | v[2] << 1 | v[3] >> 4;
dst[off + 2] = v[3] << 4 | v[4] >> 1;
dst[off + 3] = v[4] << 7 | v[5] << 2 | v[6] >> 3;
dst[off + 4] = v[6] << 5 | v[7];
}
/* decode the remaining two bytes */
off = 48; /* 6×8 */
for (i = 0; i < 5; i++)
v[i] = BASE32[(int)in[off + i]];
off = 30; /* 6×5 */
dst[off] = v[0] << 3 | v[1] >> 2;
dst[off + 1] = v[1] << 6 | v[2] << 1 | v[3] >> 4;
}
static const char BASE32_ENC[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=";
/**
* Base32 encoding for hashes. This routine only handles (and assumes) inputs of
* length 32. Additionally, it doesn't do any padding.
*
* The output should large enough to hold 53 character. One interesting feature
* of Pijul's use of base32 is that the hash type is appended to the output as
* an extra byte where 1 = BLAKE3. This is the reason that all blake3-hashed
* change files end with "C".
*/
void
b32enc(char *dst, u8 const *hash)
{
u8 b[5];
int i, j;
for (i = 0; i < 6; i++) {
for (j = 0; j < 5; j++)
b[j] = hash[i * 5 + j];
*dst++ = BASE32_ENC[b[0] >> 3];
*dst++ = BASE32_ENC[(b[0] & 0x7) << 2 | (b[1] & 0xc0) >> 6];
*dst++ = BASE32_ENC[(b[1] & 0x3e) >> 1];
*dst++ = BASE32_ENC[(b[1] & 0x1) << 4 | (b[2] & 0xf0) >> 4];
*dst++ = BASE32_ENC[(b[2] & 0x0f) << 1 | (b[3] & 0x80) >> 7];
*dst++ = BASE32_ENC[(b[3] & 0x7c) >> 2];
*dst++ = BASE32_ENC[(b[3] & 0x3) << 3 | (b[4] & 0xe0) >> 5];
*dst++ = BASE32_ENC[b[4] & 0x1f];
}
b[0] = hash[30];
b[1] = hash[31];
b[2] = 1; /* Blake3 */
b[3] = b[4] = 0;
*dst++ = BASE32_ENC[b[0] >> 3];
*dst++ = BASE32_ENC[(b[0] & 0x7) << 2 | (b[1] & 0xc0) >> 6];
*dst++ = BASE32_ENC[(b[1] & 0x3e) >> 1];
*dst++ = BASE32_ENC[(b[1] & 0x1) << 4 | (b[2] & 0xf0) >> 4];
*dst++ = BASE32_ENC[(b[2] & 0x0f) << 1 | (b[3] & 0x80) >> 7];
}