aboutsummaryrefslogtreecommitdiff
path: root/onion_base32.c
blob: 6f1713dd195ee40aadd2ec87b3dcbfaa19fac86b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include <stdlib.h>
#include <string.h>

static const char base32_lookup[] = "abcdefghijklmnopqrstuvwxyz234567";

int
check_base32(char *subject) {
	size_t offset = 0;

	if ((offset = strspn(subject, base32_lookup)) != strlen(subject)) {
		return offset;
	}
	return -1;
}

/* Simple and reliable base32 algorithm - "old trusty"
 * Note: This is not a general base32 algorithm; it outputs only the
 * first 16 base32 symbols of the input buffer, using only the first
 * 20 bytes of that buffer.
 */
void
onion_base32(char output[16], unsigned char sum[20]) {
	size_t c = 0;
	int i = 0;

	for (i = 0; i < 10; i+=5) {
		output[c++] = base32_lookup[sum[i] >> 3];
		output[c++] = base32_lookup[((sum[i] & 0x07) << 2) | (sum[i+1] >> 6)];
		output[c++] = base32_lookup[(sum[i+1] >> 1) & 0x1F];
		output[c++] = base32_lookup[((sum[i+1] & 1) << 4) | (sum[i+2] >> 4)];
		output[c++] = base32_lookup[((sum[i+2] & 0x0F) << 1) | ((sum[i+3] & 0x80) >> 7)];
		output[c++] = base32_lookup[(sum[i+3] >> 2) & 0x1F];
		output[c++] = base32_lookup[((sum[i+3] & 0x03) << 3) | (sum[i+4] >> 5)];
		output[c++] = base32_lookup[sum[i+4] & 0x1F];
	}
}

unsigned char
base32_dec_single(char b) {
	int ret = 0;

	if (b < 'a')
		ret = b - '2' + 26;
	else
		ret = b - 'a';

	printf("%d «%d»\n", ret, b);
	return ret;
}

void
onion_base32_dec(unsigned char dec[10], char base32[16])
{
	size_t c = 0;
	size_t i = 0;

	for (i = 0; i < 16; i += 8) {
		dec[c++] = base32_dec_single(base32[i]) << 3 | base32_dec_single(base32[i+1]) >> 2;
		dec[c++] = base32_dec_single(base32[i+1]) << 6 | base32_dec_single(base32[i+2]) << 1 | base32_dec_single(base32[i+3]) >> 4;
		dec[c++] = base32_dec_single(base32[i+3]) << 4 | base32_dec_single(base32[i+4]) >> 1;
		dec[c++] = base32_dec_single(base32[i+4]) << 7 | base32_dec_single(base32[i+5]) << 2 | base32_dec_single(base32[i+6]) >> 3;
		dec[c++] = base32_dec_single(base32[i+7]) | base32_dec_single(base32[i+6]) << 5;
	}

}
#ifdef __SSSE3__
#include <tmmintrin.h>

/* A slightly-parallel base32 algorithm using SSSE3
 * Note: This is not a general base32 algorithm; it outputs only the
 * first 16 base32 symbols of the input buffer, using only the first
 * 20 bytes of that buffer.
 *
 * Somewhat inspired by http://www.alfredklomp.com/programming/sse-base64/
 */
void
onion_base32_ssse3(char output[16], unsigned char sum[20]) {
	__m128i res;
	__m128i ssum;
	__m128i masklow5;
	__m128i lmask, l;
	__m128i nmask, n;

	ssum = _mm_loadu_si128((__m128i*)sum);

	/* FIXME seems a little hacky */
	masklow5 = _mm_set1_epi32(0x1F000000);
	masklow5 = _mm_slli_epi64(masklow5, 32);

	ssum = _mm_shuffle_epi8(ssum,
		_mm_setr_epi8(9,9,9,9,8,7,6,5,4,4,4,4,3,2,1,0 ));

	/* remember how I said "slightly parallel" ? */
	res = _mm_srli_epi64(ssum, 3) & masklow5;
	masklow5 = _mm_srli_epi64(masklow5, 8);

	res |= _mm_srli_epi64(ssum, 6) & masklow5;
	masklow5 = _mm_srli_epi64(masklow5, 8);

	res |= _mm_srli_epi64(ssum, 9) & masklow5;
	masklow5 = _mm_srli_epi64(masklow5, 8);

	res |= _mm_srli_epi64(ssum, 12) & masklow5;
	masklow5 = _mm_srli_epi64(masklow5, 8);

	res |= _mm_srli_epi64(ssum, 15) & masklow5;
	masklow5 = _mm_srli_epi64(masklow5, 8);

	res |= _mm_srli_epi64(ssum, 18) & masklow5;
	masklow5 = _mm_srli_epi64(masklow5, 8);

	res |= _mm_srli_epi64(ssum, 21) & masklow5;
	masklow5 = _mm_srli_epi64(masklow5, 8);

	res |= _mm_srli_epi64(ssum, 24) & masklow5;
	masklow5 = _mm_srli_epi64(masklow5, 8);


	res = _mm_shuffle_epi8(res,
		_mm_setr_epi8(15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0));

	lmask = _mm_cmplt_epi8(res, _mm_set1_epi8(26));
	nmask = _mm_andnot_si128(lmask, _mm_cmplt_epi8(res, _mm_set1_epi8(32)));

	l = lmask & _mm_add_epi8(res, _mm_set1_epi8('a'));
	n = nmask & _mm_add_epi8(res, _mm_set1_epi8('2' - 26));

	_mm_storeu_si128((__m128i*)output, l|n);
}
#endif /* ifdef __SSSE3__ */