forked from dsprenkels/sss
-
-
Notifications
You must be signed in to change notification settings - Fork 7
/
slip39_wordlist.c
191 lines (154 loc) · 4.67 KB
/
slip39_wordlist.c
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
#include "slip39.h"
#include "slip39_wordlist_english.h"
//////////////////////////////////////////////////
// slip39 words
//
int16_t lookup(const char *word) {
int16_t hi=WORDLIST_SIZE;
int16_t lo=-1;
while(hi>lo+1) {
int16_t mid = (hi + lo) / 2;
int16_t cmp = strcmp(word, wordlist[mid]);
if(cmp > 0) {
lo = mid;
} else if(cmp < 0){
hi = mid;
} else {
return mid;
}
}
return -1;
}
const char *slip39_word(int16_t word) {
if(word < 1024) {
return wordlist[word];
}
return "";
}
uint32_t parse_words(
const char *words_string,
uint16_t *words,
uint32_t words_length
) {
char buf[16];
uint8_t i=0;
uint32_t j=0;
const char *p = words_string;
while(*p) {
for(i=0; *p>='a' && *p<='z'; i++, p++) {
if(i<15) {
buf[i] = *p;
} else {
buf[15] = 0;
}
}
if(i<15) {
buf[i] = 0;
}
if(j<words_length) {
int16_t w = lookup(buf);
if(w<0) {
printf("%s is not valid.\n", buf);
return -1;
} else {
words[j] = w;
}
}
j++;
while(*p && (*p<'a' || *p>'z')) {
p++;
}
}
return j;
}
// convert a buffer of bytes into 10-bit mnemonic words
// returns the number of words written or -1 if there was an error
int32_t to_words(
const uint8_t *buffer, // byte buffer to encode into 10-bit words
uint32_t size, // buffer size
uint16_t *words, // destination for words
uint32_t max // maximum number of words to write
) {
// The bottom bit of the last byte should always line up with
// the bottom bit of the last word.
// calculate the padding bits to add to the first byte to get
// the last byte and the last word bottom bits to align
//
// bytes 5 4 3 2 1 0
// |...,...|...,...|...,...|...,...|...,...+
// X X X X *
// words 4 3 2 1 0
//
// Looks like the number of zero bit padding to add
// is 2x the remainder when your divide the number of
// bytes by 5.
uint32_t byte = 0;
uint32_t word = 0;
uint8_t bits = (size % 5) * 2; // padded so that bottom bits align
uint16_t i = 0;
if(max < bytes_to_words(size)) {
printf("Not enough space to encode into 10-bit words \n");
return -1;
}
while(byte < size && word < max) {
while(bits < 10) {
i = i << 8;
bits += 8;
if(byte < size) {
i = i | buffer[byte++];
}
}
words[word++] = (i >> (bits-10));
i = i & ((1<<(bits-10))-1);
bits -= 10;
}
return word;
}
// returns the number of bytes written, or -1 if there was an error
int32_t from_words(
const uint16_t *words, // words to decode
uint32_t wordsize, // number of words to decode
uint8_t *buffer, // space for result
size_t size // total space available
) {
// The bottom bit of the last byte will always show up in
// the bottom bit of the last word.
// calculate the padding bits to add to the first byte to get
// the last byte and the last word bottom bits to align
//
// bytes 5 4 3 2 1 0
// |...,...|...,...|...,...|...,...|...,...+
// X X X X *
// words 4 3 2 1 0
//
uint32_t word = 0;
int16_t bits = -2*(wordsize%4);
// A negiative number indicates a number of padding bits. Those bits
// must be zero.
if(bits <0 && (words[0] & (1023 << (10+bits)))) {
return ERROR_INVALID_PADDING;
}
// If the number of words is an odd multiple of 5, and the top
// byte is all zeros, we should probably discard it to get a
// resulting buffer that is an even number of bytes
uint8_t discard_top_zeros = (wordsize%4 == 0) && (wordsize & 4);
uint32_t byte = 0;
uint16_t i = 0;
if(size < words_to_bytes(wordsize)) {
return ERROR_INSUFFICIENT_SPACE;
}
while(word < wordsize && byte < size) {
i = (i << 10) | words[word++];
bits += 10;
if(discard_top_zeros && (i & 1020)==0) {
discard_top_zeros = 0;
bits -= 8;
}
while(bits >= 8 && byte < size) {
buffer[byte++] = (i >> (bits -8));
i = i & ((1<<(bits-8))-1);
bits -= 8;
}
}
return byte;
}