參考:助記詞(Mnemonics)生成種子,以及Public Key, Private key?https://my.oschina.net/gavinzheng731/blog/1847838
【區(qū)塊鏈 | ETH】Web3j創(chuàng)建錢包的2種方式的對(duì)比https://blog.csdn.net/qq_28505809/article/details/99857208
基本大意,根據(jù)BIP39,11位二進(jìn)制數(shù)轉(zhuǎn)化成一個(gè)單詞,如果有不足的位數(shù),使用私鑰hash的結(jié)果來填充,于是助記詞和私鑰之間就可以相互轉(zhuǎn)換了。
貼上代碼
/**
* pk is 256 bits, the mn words will be 24
*/
@Override
public List<String> getWords(byte[] pk) throws Exception {
ArrayList<String> ret = new ArrayList<String>();
byte[] out = CreateCredentialsUtil.pk2mn("SHA-256", "", pk);
int n;
n = (out[0] & 0xff) << 3 | (out[1] & 0xff) >> 5;
ret.add(words.get(n));
n = (out[1] & 0x1f) << 6 | (out[2] & 0xff) >> 2;
ret.add(words.get(n));
n = (out[2] & 0x03) << 9 | (out[3] & 0xff) << 1 | (out[4] & 0xff) >> 7;
ret.add(words.get(n));
n = (out[4] & 0x7f) << 4 | (out[5] & 0xff) >> 4;
ret.add(words.get(n));
n = (out[5] & 0x0f) << 7 | (out[6] & 0xff) >> 1;
ret.add(words.get(n));
n = (out[6] & 0x01) << 10 | (out[7] & 0xff) << 2 | (out[8] & 0xff) >> 6;
ret.add(words.get(n));
n = (out[8] & 0x3f) << 5 | (out[9] & 0xff) >> 3;
ret.add(words.get(n));
n = (out[9] & 0x07) << 8 | (out[10] & 0xff) ;
ret.add(words.get(n));
// round 2
n = (out[11] & 0xff) << 3 | (out[12] & 0xff) >> 5;
ret.add(words.get(n));
n = (out[12] & 0x1f) << 6 | (out[13] & 0xff) >> 2;
ret.add(words.get(n));
n = (out[13] & 0x03) << 9 | (out[14] & 0xff) << 1 | (out[15] & 0xff) >> 7;
ret.add(words.get(n));
n = (out[15] & 0x7f) << 4 | (out[16] & 0xff) >> 4;
ret.add(words.get(n));
n = (out[16] & 0x0f) << 7 | (out[17] & 0xff) >> 1;
ret.add(words.get(n));
n = (out[17] & 0x01) << 10 | (out[18] & 0xff) << 2 | (out[19] & 0xff) >> 6;
ret.add(words.get(n));
n = (out[19] & 0x3f) << 5 | (out[20] & 0xff) >> 3;
ret.add(words.get(n));
n = (out[20] & 0x07) << 8 | (out[21] & 0xff) ;
ret.add(words.get(n));
// round 3
n = (out[22] & 0xff) << 3 | (out[23] & 0xff) >> 5;
ret.add(words.get(n));
n = (out[23] & 0x1f) << 6 | (out[24] & 0xff) >> 2;
ret.add(words.get(n));
n = (out[24] & 0x03) << 9 | (out[25] & 0xff) << 1 | (out[26] & 0xff) >> 7;
ret.add(words.get(n));
n = (out[26] & 0x7f) << 4 | (out[27] & 0xff) >> 4;
ret.add(words.get(n));
n = (out[27] & 0x0f) << 7 | (out[28] & 0xff) >> 1;
ret.add(words.get(n));
n = (out[28] & 0x01) << 10 | (out[29] & 0xff) << 2 | (out[30] & 0xff) >> 6;
ret.add(words.get(n));
n = (out[30] & 0x3f) << 5 | (out[31] & 0xff) >> 3;
ret.add(words.get(n));
n = (out[31] & 0x07) << 8 | (out[32] & 0xff) ;
ret.add(words.get(n));
return ret;
}
@Override
public byte[] getPk(List<String> input) {
byte[] ret = new byte[32];
int[] in = new int[24];
for (int i = 0; i < 24; ++i) {
in[i] = words.indexOf(input.get(i));
}
// round 1
ret[0] = (byte) ((in[0] & 0x7ff) >> 3);
ret[1] = (byte) ((in[0] & 0x07) << 5 | (in[1] & 0x7ff) >> 6);
ret[2] = (byte) ((in[1] & 0x3f) << 2 | (in[2] & 0x7ff) >> 9);
ret[3] = (byte) ((in[2] & 0x1ff) >> 1);
ret[4] = (byte) ((in[2] & 0x1) << 7 | (in[3] & 0x7ff) >> 4);
ret[5] = (byte) ((in[3] & 0xf) << 4 | (in[4] & 0x7ff) >> 7);
ret[6] = (byte) ((in[4] & 0x7f) << 1 | (in[5] & 0x7ff) >> 10);
ret[7] = (byte) ((in[5] & 0x3ff) >> 2);
ret[8] = (byte) ((in[5] & 0x3) << 6 | (in[6] & 0x7ff) >> 5);
ret[9] = (byte) ((in[6] & 0x1f) << 3 | (in[7] & 0x7ff) >> 8);
ret[10] = (byte) ((in[7] & 0xff));
// round 2
ret[11] = (byte) ((in[8] & 0x7ff) >> 3);
ret[12] = (byte) ((in[8] & 0x07) << 5 | (in[9] & 0x7ff) >> 6);
ret[13] = (byte) ((in[9] & 0x3f) << 2 | (in[10] & 0x7ff) >> 9);
ret[14] = (byte) ((in[10] & 0x1ff) >> 1);
ret[15] = (byte) ((in[10] & 0x1) << 7 | (in[11] & 0x7ff) >> 4);
ret[16] = (byte) ((in[11] & 0xf) << 4 | (in[12] & 0x7ff) >> 7);
ret[17] = (byte) ((in[12] & 0x7f) << 1 | (in[13] & 0x7ff) >> 10);
ret[18] = (byte) ((in[13] & 0x3ff) >> 2);
ret[19] = (byte) ((in[13] & 0x3) << 6 | (in[14] & 0x7ff) >> 5);
ret[20] = (byte) ((in[14] & 0x1f) << 3 | (in[15] & 0x7ff) >> 8);
ret[21] = (byte) ((in[15] & 0xff));
// round 3
ret[22] = (byte) ((in[16] & 0x7ff) >> 3);
ret[23] = (byte) ((in[16] & 0x07) << 5 | (in[17] & 0x7ff) >> 6);
ret[24] = (byte) ((in[17] & 0x3f) << 2 | (in[18] & 0x7ff) >> 9);
ret[25] = (byte) ((in[18] & 0x1ff) >> 1);
ret[26] = (byte) ((in[18] & 0x1) << 7 | (in[19] & 0x7ff) >> 4);
ret[27] = (byte) ((in[19] & 0xf) << 4 | (in[20] & 0x7ff) >> 7);
ret[28] = (byte) ((in[20] & 0x7f) << 1 | (in[21] & 0x7ff) >> 10);
ret[29] = (byte) ((in[21] & 0x3ff) >> 2);
ret[30] = (byte) ((in[21] & 0x3) << 6 | (in[22] & 0x7ff) >> 5);
ret[31] = (byte) ((in[22] & 0x1f) << 3 | (in[23] & 0x7ff) >> 8);
// ret[32] = (byte) ((in[23] & 0xff));
return ret;
}
單詞文件,請(qǐng)到https://github.com/bitcoin/bips/tree/master/bip-0039自行尋找。
最后寫點(diǎn)小收獲,java的BigInteger, 轉(zhuǎn)成byte[]時(shí),如果第一個(gè)byte是負(fù)數(shù),那么會(huì)在其前加上一個(gè)byte,值是0。這樣,256位的私鑰,本來應(yīng)該變成32個(gè)byte,卻變成了33個(gè)byte,這樣處理,是因?yàn)槿绻胋yte數(shù)組生成大整數(shù),如果最高位為1,那么生成的整數(shù)是負(fù)的。但如果這些byte變成字串,則沒關(guān)系。比如BigInteger(“FFF”,16)并不會(huì)變成一個(gè)負(fù)數(shù)。
以上方法,助記詞和私鑰可以相互轉(zhuǎn)化,另有一種從助記詞生成私鑰的方法,(但反向不行)
參考 java使用bip39創(chuàng)建以太坊錢包http://www.itdecent.cn/p/14b9d2908a66
區(qū)塊鏈知識(shí)普及之 BIP39 助記詞生成過程詳解http://www.itdecent.cn/p/3db04e987a6c