forked from trezor/trezor-crypto
-
Notifications
You must be signed in to change notification settings - Fork 0
/
bip39.c
139 lines (124 loc) · 2.76 KB
/
bip39.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
#include <string.h>
#include "bip39.h"
#include "hmac.h"
#include "rand.h"
#include "sha2.h"
#include "pbkdf2.h"
#include "bip39_english.h"
#define PBKDF2_ROUNDS 2048
const char *mnemonic_generate(int strength)
{
if (strength % 32 || strength < 128 || strength > 256) {
return 0;
}
static uint8_t data[32];
random_buffer(data, 32);
return mnemonic_from_data(data, strength / 8);
}
const char *mnemonic_from_data(const uint8_t *data, int len)
{
if (len % 4 || len < 16 || len > 32) {
return 0;
}
uint8_t bits[32 + 1];
memcpy(bits, data, len);
sha256_Raw(data, len, bits);
bits[len] = bits[0];
memcpy(bits, data, len);
int mlen = len * 3 / 4;
static char mnemo[24 * 10];
int i, j, idx;
char *p = mnemo;
for (i = 0; i < mlen; i++) {
idx = 0;
for (j = 0; j < 11; j++) {
idx <<= 1;
idx += (bits[(i * 11 + j) / 8] & (1 << (7 - ((i * 11 + j) % 8)))) > 0;
}
strcpy(p, wordlist[idx]);
p += strlen(wordlist[idx]);
*p = (i < mlen - 1) ? ' ' : 0;
p++;
}
return mnemo;
}
int mnemonic_check(const char *mnemonic)
{
if (!mnemonic) {
return 0;
}
uint32_t i, n;
i = 0; n = 0;
while (mnemonic[i]) {
if (mnemonic[i] == ' ') {
n++;
}
i++;
}
n++;
// check number of words
if (n != 12 && n != 18 && n != 24) {
return 0;
}
char current_word[10];
uint32_t j, k, ki, bi;
uint8_t bits[32 + 1];
memset(bits, 0, sizeof(bits));
i = 0; bi = 0;
while (mnemonic[i]) {
j = 0;
while (mnemonic[i] != ' ' && mnemonic[i] != 0) {
if (j >= sizeof(current_word)) {
return 0;
}
current_word[j] = mnemonic[i];
i++; j++;
}
current_word[j] = 0;
if (mnemonic[i] != 0) i++;
k = 0;
for (;;) {
if (!wordlist[k]) { // word not found
return 0;
}
if (strcmp(current_word, wordlist[k]) == 0) { // word found on index k
for (ki = 0; ki < 11; ki++) {
if (k & (1 << (10 - ki))) {
bits[bi / 8] |= 1 << (7 - (bi % 8));
}
bi++;
}
break;
}
k++;
}
}
if (bi != n * 11) {
return 0;
}
bits[32] = bits[n * 4 / 3];
sha256_Raw(bits, n * 4 / 3, bits);
if (n == 12) {
return (bits[0] & 0xF0) == (bits[32] & 0xF0); // compare first 4 bits
} else
if (n == 18) {
return (bits[0] & 0xFC) == (bits[32] & 0xFC); // compare first 6 bits
} else
if (n == 24) {
return bits[0] == bits[32]; // compare 8 bits
}
return 0;
}
void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed[512 / 8], void (*progress_callback)(uint32_t current, uint32_t total))
{
static uint8_t salt[8 + 256 + 4];
int saltlen = strlen(passphrase);
memcpy(salt, "mnemonic", 8);
memcpy(salt + 8, passphrase, saltlen);
saltlen += 8;
pbkdf2((const uint8_t *)mnemonic, strlen(mnemonic), salt, saltlen, PBKDF2_ROUNDS, seed, 512 / 8, progress_callback);
}
const char **mnemonic_wordlist(void)
{
return wordlist;
}