Files
lightning/libwally-core/src/mnemonic.c
2017-02-21 15:15:28 +10:30

98 lines
2.9 KiB
C

#include "internal.h"
#include "mnemonic.h"
#include "wordlist.h"
#define U8_AT(bytes, pos) (bytes)[(pos) / 8u]
#define U8_MASK(pos) (1u << (7u - (pos) % 8u))
/* Get n'th value (of w->bits length) from bytes */
static size_t extract_index(size_t bits, const unsigned char *bytes_in, size_t n)
{
size_t pos, end, value;
for (pos = n * bits, end = pos + bits, value = 0; pos < end; ++pos)
value = (value << 1u) | !!(U8_AT(bytes_in, pos) & U8_MASK(pos));
return value;
}
/* Store n'th value (of w->bits length) to bytes
* Assumes: 1) the bits we are writing to are zero
* 2) value fits within w->bits
*/
static void store_index(size_t bits, unsigned char *bytes_out, size_t n, size_t value)
{
size_t i, pos;
for (pos = n * bits, i = 0; i < bits; ++i, ++pos)
if (value & (1u << (bits - i - 1u)))
U8_AT(bytes_out, pos) |= U8_MASK(pos);
}
char *mnemonic_from_bytes(const struct words *w, const unsigned char *bytes_in, size_t len_in)
{
size_t total_bits = len_in * 8u; /* bits in 'bytes' */
size_t total_mnemonics = total_bits / w->bits; /* Mnemonics in 'bytes' */
size_t i, str_len = 0;
char *str = NULL;
/* Compute length of result */
for (i = 0; i < total_mnemonics; ++i) {
size_t idx = extract_index(w->bits, bytes_in, i);
size_t mnemonic_len = strlen(w->indices[idx]);
str_len += mnemonic_len + 1; /* +1 for following separator or NUL */
}
/* Allocate and fill result */
if (str_len && (str = wally_malloc(str_len))) {
char *out = str;
for (i = 0; i < total_mnemonics; ++i) {
size_t idx = extract_index(w->bits, bytes_in, i);
size_t mnemonic_len = strlen(w->indices[idx]);
memcpy(out, w->indices[idx], mnemonic_len);
out[mnemonic_len] = ' '; /* separator */
out += mnemonic_len + 1;
}
str[str_len - 1] = '\0'; /* Overwrite the last separator with NUL */
}
return str;
}
int mnemonic_to_bytes(const struct words *w, const char *mnemonic,
unsigned char *bytes_out, size_t len, size_t *written)
{
struct words *mnemonic_w = wordlist_init(mnemonic);
size_t i;
if (written)
*written = 0;
if (!mnemonic_w)
return WALLY_ENOMEM;
if (!w || !bytes_out || !len)
return WALLY_EINVAL;
if ((mnemonic_w->len * w->bits + 7u) / 8u > len)
goto cleanup; /* Return the length we would have written */
clear(bytes_out, len);
for (i = 0; i < mnemonic_w->len; ++i) {
size_t idx = wordlist_lookup_word(w, mnemonic_w->indices[i]);
if (!idx) {
wordlist_free(mnemonic_w);
clear(bytes_out, len);
return WALLY_EINVAL;
}
store_index(w->bits, bytes_out, i, idx - 1);
}
cleanup:
if (written)
*written = (mnemonic_w->len * w->bits + 7u) / 8u;
wordlist_free(mnemonic_w);
return WALLY_OK;
}