1 package io.bytom.common;
\r
3 import org.bouncycastle.util.encoders.Hex;
\r
5 import javax.crypto.Mac;
\r
6 import javax.crypto.spec.SecretKeySpec;
\r
7 import java.io.ByteArrayOutputStream;
\r
8 import java.security.InvalidKeyException;
\r
9 import java.security.NoSuchAlgorithmException;
\r
11 public class NonHardenedChild {
\r
13 private static byte[] hmacSha512(byte[] data, byte[] key)
\r
14 throws NoSuchAlgorithmException, InvalidKeyException {
\r
15 SecretKeySpec signingKey = new SecretKeySpec(key, "HmacSHA512");
\r
16 Mac mac = Mac.getInstance("HmacSHA512");
\r
17 mac.init(signingKey);
\r
18 return mac.doFinal(data);
\r
21 public static byte[] nhChild(byte[] path, byte[] xprv, byte[] xpub) throws NoSuchAlgorithmException, InvalidKeyException {
\r
23 ByteArrayOutputStream out = new ByteArrayOutputStream();
\r
25 out.write(xpub, 0, xpub.length / 2);
\r
26 out.write(path, 0, path.length);
\r
27 byte[] data = out.toByteArray();
\r
31 byte[] key = new byte[xpub.length / 2];
\r
32 System.arraycopy(xpub, xpub.length / 2, key, 0, xpub.length / 2);
\r
36 byte[] res = hmacSha512(data, key);
\r
38 //begin operate res[:32]
\r
39 byte[] f = new byte[res.length / 2];
\r
40 System.arraycopy(res, 0, f, 0, res.length / 2);
\r
41 f = pruneIntermediateScalar(f);
\r
42 System.arraycopy(f, 0, res, 0, res.length / 2);
\r
43 //end operate res[:32]
\r
45 //begin operate res[:32] again
\r
48 for (int i = 0; i < 32; i++) {
\r
49 int xprvInt = xprv[i] & 0xFF;
\r
50 int resInt = res[i] & 0xFF;
\r
51 sum = xprvInt + resInt + carry;
\r
52 res[i] = (byte) sum;
\r
55 if ((sum >> 8) != 0) {
\r
56 System.err.println("sum does not fit in 256-bit int");
\r
58 //end operate res[:32] again
\r
62 private static byte[] pruneIntermediateScalar(byte[] f) {
\r
63 f[0] &= 248; // clear bottom 3 bits
\r
64 f[29] &= 1; // clear 7 high bits
\r
65 f[30] = 0; // clear 8 bits
\r
66 f[31] = 0; // clear 8 bits
\r
70 public static byte[] child(byte[] xprv, String[] hpaths) throws NoSuchAlgorithmException, InvalidKeyException {
\r
71 byte[][] paths = new byte[][]{
\r
72 Hex.decode(hpaths[0]),
\r
73 Hex.decode(hpaths[1])
\r
76 for (int i = 0; i < hpaths.length; i++) {
\r
77 byte[] xpub = DeriveXpub.deriveXpub(res);
\r
78 res = NonHardenedChild.nhChild(paths[i], res, xpub);
\r