Merge pull request #18 from sachaaaaa/mnemonic
Allow registering using a mnemonic word listpull/22/head
commit
bbabeb34b8
@ -0,0 +1,2 @@
|
||||
use emscripten to convert c to javascript:
|
||||
`emcc sc_reduce32.c -o sc_reduce32.js -s EXPORTED_FUNCTIONS="['_sc_reduce32']" -s WASM=0 -s ENVIRONMENT=node -s EXTRA_EXPORTED_RUNTIME_METHODS='["ccall"]'`
|
@ -0,0 +1,134 @@
|
||||
#include <stdint.h>
|
||||
|
||||
uint64_t load_3(const unsigned char *in) {
|
||||
uint64_t result;
|
||||
result = (uint64_t) in[0];
|
||||
result |= ((uint64_t) in[1]) << 8;
|
||||
result |= ((uint64_t) in[2]) << 16;
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t load_4(const unsigned char *in)
|
||||
{
|
||||
uint64_t result;
|
||||
result = (uint64_t) in[0];
|
||||
result |= ((uint64_t) in[1]) << 8;
|
||||
result |= ((uint64_t) in[2]) << 16;
|
||||
result |= ((uint64_t) in[3]) << 24;
|
||||
return result;
|
||||
}
|
||||
|
||||
void sc_reduce32(unsigned char *s) {
|
||||
int64_t s0 = 2097151 & load_3(s);
|
||||
int64_t s1 = 2097151 & (load_4(s + 2) >> 5);
|
||||
int64_t s2 = 2097151 & (load_3(s + 5) >> 2);
|
||||
int64_t s3 = 2097151 & (load_4(s + 7) >> 7);
|
||||
int64_t s4 = 2097151 & (load_4(s + 10) >> 4);
|
||||
int64_t s5 = 2097151 & (load_3(s + 13) >> 1);
|
||||
int64_t s6 = 2097151 & (load_4(s + 15) >> 6);
|
||||
int64_t s7 = 2097151 & (load_3(s + 18) >> 3);
|
||||
int64_t s8 = 2097151 & load_3(s + 21);
|
||||
int64_t s9 = 2097151 & (load_4(s + 23) >> 5);
|
||||
int64_t s10 = 2097151 & (load_3(s + 26) >> 2);
|
||||
int64_t s11 = (load_4(s + 28) >> 7);
|
||||
int64_t s12 = 0;
|
||||
int64_t carry0;
|
||||
int64_t carry1;
|
||||
int64_t carry2;
|
||||
int64_t carry3;
|
||||
int64_t carry4;
|
||||
int64_t carry5;
|
||||
int64_t carry6;
|
||||
int64_t carry7;
|
||||
int64_t carry8;
|
||||
int64_t carry9;
|
||||
int64_t carry10;
|
||||
int64_t carry11;
|
||||
|
||||
carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
|
||||
carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
|
||||
carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
|
||||
carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
|
||||
carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
|
||||
carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
|
||||
|
||||
carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
|
||||
carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
|
||||
carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
|
||||
carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
|
||||
carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
|
||||
carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
|
||||
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
s12 = 0;
|
||||
|
||||
carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
|
||||
carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
|
||||
carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
|
||||
carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
|
||||
carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
|
||||
carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
|
||||
carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
|
||||
carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
|
||||
carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
|
||||
carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
|
||||
carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
|
||||
carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21;
|
||||
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
|
||||
carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
|
||||
carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
|
||||
carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
|
||||
carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
|
||||
carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
|
||||
carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
|
||||
carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
|
||||
carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
|
||||
carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
|
||||
carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
|
||||
carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
|
||||
|
||||
s[0] = s0 >> 0;
|
||||
s[1] = s0 >> 8;
|
||||
s[2] = (s0 >> 16) | (s1 << 5);
|
||||
s[3] = s1 >> 3;
|
||||
s[4] = s1 >> 11;
|
||||
s[5] = (s1 >> 19) | (s2 << 2);
|
||||
s[6] = s2 >> 6;
|
||||
s[7] = (s2 >> 14) | (s3 << 7);
|
||||
s[8] = s3 >> 1;
|
||||
s[9] = s3 >> 9;
|
||||
s[10] = (s3 >> 17) | (s4 << 4);
|
||||
s[11] = s4 >> 4;
|
||||
s[12] = s4 >> 12;
|
||||
s[13] = (s4 >> 20) | (s5 << 1);
|
||||
s[14] = s5 >> 7;
|
||||
s[15] = (s5 >> 15) | (s6 << 6);
|
||||
s[16] = s6 >> 2;
|
||||
s[17] = s6 >> 10;
|
||||
s[18] = (s6 >> 18) | (s7 << 3);
|
||||
s[19] = s7 >> 5;
|
||||
s[20] = s7 >> 13;
|
||||
s[21] = s8 >> 0;
|
||||
s[22] = s8 >> 8;
|
||||
s[23] = (s8 >> 16) | (s9 << 5);
|
||||
s[24] = s9 >> 3;
|
||||
s[25] = s9 >> 11;
|
||||
s[26] = (s9 >> 19) | (s10 << 2);
|
||||
s[27] = s10 >> 6;
|
||||
s[28] = (s10 >> 14) | (s11 << 7);
|
||||
s[29] = s11 >> 1;
|
||||
s[30] = s11 >> 9;
|
||||
s[31] = s11 >> 17;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,162 @@
|
||||
const crc32 = require('buffer-crc32');
|
||||
const sc_reduce32_module = require('../components/sc_reduce32/sc_reduce32');
|
||||
|
||||
module.exports = {
|
||||
mn_encode,
|
||||
mn_decode,
|
||||
sc_reduce32,
|
||||
};
|
||||
class MnemonicError extends Error {}
|
||||
|
||||
function hexToUint8Array(e) {
|
||||
if (e.length % 2 != 0)
|
||||
throw "Hex string has invalid length!";
|
||||
for (var t = new Uint8Array(e.length / 2), r = 0; r < e.length / 2; ++r)
|
||||
t[r] = parseInt(e.slice(2 * r, 2 * r + 2), 16);
|
||||
return t
|
||||
}
|
||||
|
||||
function Uint8ArrayToHex(e) {
|
||||
for (var t = [], r = 0; r < e.length; ++r)
|
||||
t.push(("0" + e[r].toString(16)).slice(-2));
|
||||
return t.join("")
|
||||
}
|
||||
|
||||
function sc_reduce32(e) {
|
||||
var t = hexToUint8Array(e);
|
||||
if (32 !== t.length)
|
||||
throw "Invalid input length";
|
||||
var r = sc_reduce32_module._malloc(32);
|
||||
sc_reduce32_module.HEAPU8.set(t, r),
|
||||
sc_reduce32_module.ccall("sc_reduce32", "void", ["number"], [r]);
|
||||
var o = sc_reduce32_module.HEAPU8.subarray(r, r + 32);
|
||||
return sc_reduce32_module._free(r),Uint8ArrayToHex(o);
|
||||
}
|
||||
/*
|
||||
mnemonic.js : Converts between 4-byte aligned strings and a human-readable
|
||||
sequence of words. Uses 1626 common words taken from wikipedia article:
|
||||
http://en.wiktionary.org/wiki/Wiktionary:Frequency_lists/Contemporary_poetry
|
||||
Originally written in python special for Electrum (lightweight Bitcoin client).
|
||||
This version has been reimplemented in javascript and placed in public domain.
|
||||
*/
|
||||
|
||||
var mn_default_wordset = 'english';
|
||||
|
||||
function mn_get_checksum_index(words, prefix_len) {
|
||||
var trimmed_words = "";
|
||||
for (var i = 0; i < words.length; i++) {
|
||||
trimmed_words += words[i].slice(0, prefix_len);
|
||||
}
|
||||
var checksum = crc32.unsigned(trimmed_words);
|
||||
var index = checksum % words.length;
|
||||
return index;
|
||||
}
|
||||
|
||||
function mn_encode(str, wordset_name) {
|
||||
'use strict';
|
||||
wordset_name = wordset_name || mn_default_wordset;
|
||||
var wordset = mn_words[wordset_name];
|
||||
var out = [];
|
||||
var n = wordset.words.length;
|
||||
for (var j = 0; j < str.length; j += 8) {
|
||||
str = str.slice(0, j) + mn_swap_endian_4byte(str.slice(j, j + 8)) + str.slice(j + 8);
|
||||
}
|
||||
for (var i = 0; i < str.length; i += 8) {
|
||||
var x = parseInt(str.substr(i, 8), 16);
|
||||
var w1 = (x % n);
|
||||
var w2 = (Math.floor(x / n) + w1) % n;
|
||||
var w3 = (Math.floor(Math.floor(x / n) / n) + w2) % n;
|
||||
out = out.concat([wordset.words[w1], wordset.words[w2], wordset.words[w3]]);
|
||||
}
|
||||
if (wordset.prefix_len > 0) {
|
||||
out.push(out[mn_get_checksum_index(out, wordset.prefix_len)]);
|
||||
}
|
||||
return out.join(' ');
|
||||
}
|
||||
|
||||
function mn_swap_endian_4byte(str) {
|
||||
'use strict';
|
||||
if (str.length !== 8) throw new MnemonicError('Invalid input length: ' + str.length);
|
||||
return str.slice(6, 8) + str.slice(4, 6) + str.slice(2, 4) + str.slice(0, 2);
|
||||
}
|
||||
|
||||
function mn_decode(str, wordset_name) {
|
||||
'use strict';
|
||||
wordset_name = wordset_name || mn_default_wordset;
|
||||
var wordset = mn_words[wordset_name];
|
||||
var out = '';
|
||||
var n = wordset.words.length;
|
||||
var wlist = str.split(' ');
|
||||
var checksum_word = '';
|
||||
if (wlist.length < 12) throw new MnemonicError("You've entered too few words, please try again");
|
||||
if ((wordset.prefix_len === 0 && (wlist.length % 3 !== 0)) ||
|
||||
(wordset.prefix_len > 0 && (wlist.length % 3 === 2))) throw new MnemonicError("You've entered too few words, please try again");
|
||||
if (wordset.prefix_len > 0 && (wlist.length % 3 === 0)) throw new MnemonicError("You seem to be missing the last word in your private key, please try again");
|
||||
if (wordset.prefix_len > 0) {
|
||||
// Pop checksum from mnemonic
|
||||
checksum_word = wlist.pop();
|
||||
}
|
||||
// Decode mnemonic
|
||||
for (var i = 0; i < wlist.length; i += 3) {
|
||||
var w1, w2, w3;
|
||||
if (wordset.prefix_len === 0) {
|
||||
w1 = wordset.words.indexOf(wlist[i]);
|
||||
w2 = wordset.words.indexOf(wlist[i + 1]);
|
||||
w3 = wordset.words.indexOf(wlist[i + 2]);
|
||||
} else {
|
||||
w1 = wordset.trunc_words.indexOf(wlist[i].slice(0, wordset.prefix_len));
|
||||
w2 = wordset.trunc_words.indexOf(wlist[i + 1].slice(0, wordset.prefix_len));
|
||||
w3 = wordset.trunc_words.indexOf(wlist[i + 2].slice(0, wordset.prefix_len));
|
||||
}
|
||||
if (w1 === -1 || w2 === -1 || w3 === -1) {
|
||||
throw MnemonicError("invalid word in mnemonic");
|
||||
}
|
||||
var x = w1 + n * (((n - w1) + w2) % n) + n * n * (((n - w2) + w3) % n);
|
||||
if (x % n != w1) throw new MnemonicError('Something went wrong when decoding your private key, please try again');
|
||||
out += mn_swap_endian_4byte(('0000000' + x.toString(16)).slice(-8));
|
||||
}
|
||||
// Verify checksum
|
||||
if (wordset.prefix_len > 0) {
|
||||
var index = mn_get_checksum_index(wlist, wordset.prefix_len);
|
||||
var expected_checksum_word = wlist[index];
|
||||
if (expected_checksum_word.slice(0, wordset.prefix_len) !== checksum_word.slice(0, wordset.prefix_len)) {
|
||||
throw new MnemonicError("Your private key could not be verified, please try again");
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
var mn_words = {
|
||||
'electrum': {
|
||||
prefix_len: 0,
|
||||
words: require('../mnemonic_languages/electrum'),
|
||||
},
|
||||
'english': {
|
||||
prefix_len: 3,
|
||||
words: require('../mnemonic_languages/english'),
|
||||
},
|
||||
'spanish': {
|
||||
prefix_len: 4,
|
||||
words: require('../mnemonic_languages/spanish'),
|
||||
},
|
||||
'portuguese': {
|
||||
prefix_len: 4,
|
||||
words: require('../mnemonic_languages/portuguese'),
|
||||
},
|
||||
'japanese': {
|
||||
prefix_len: 3,
|
||||
words: require('../mnemonic_languages/japanese'),
|
||||
}
|
||||
};
|
||||
|
||||
for (var i in mn_words) {
|
||||
if (mn_words.hasOwnProperty(i)) {
|
||||
if (mn_words[i].prefix_len === 0) {
|
||||
continue;
|
||||
}
|
||||
mn_words[i].trunc_words = [];
|
||||
for (var j = 0; j < mn_words[i].words.length; ++j) {
|
||||
mn_words[i].trunc_words.push(mn_words[i].words[j].slice(0, mn_words[i].prefix_len));
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue