--- /dev/null
+package io.bytom.offline.common;\r
+\r
+import org.bouncycastle.util.encoders.Hex;\r
+\r
+import javax.crypto.Mac;\r
+import javax.crypto.spec.SecretKeySpec;\r
+import java.io.ByteArrayOutputStream;\r
+import java.security.InvalidKeyException;\r
+import java.security.NoSuchAlgorithmException;\r
+\r
+public class NonHardenedChild {\r
+\r
+ private static byte[] hmacSha512(byte[] data, byte[] key)\r
+ throws NoSuchAlgorithmException, InvalidKeyException {\r
+ SecretKeySpec signingKey = new SecretKeySpec(key, "HmacSHA512");\r
+ Mac mac = Mac.getInstance("HmacSHA512");\r
+ mac.init(signingKey);\r
+ return mac.doFinal(data);\r
+ }\r
+\r
+ public static byte[] nhChild(byte[] path, byte[] xprv, byte[] xpub) throws NoSuchAlgorithmException, InvalidKeyException {\r
+ // begin build data\r
+ ByteArrayOutputStream out = new ByteArrayOutputStream();\r
+ out.write('N');\r
+ out.write(xpub, 0, xpub.length / 2);\r
+ out.write(path, 0, path.length);\r
+ byte[] data = out.toByteArray();\r
+ // end build data\r
+\r
+ // begin build key\r
+ byte[] key = new byte[xpub.length / 2];\r
+ System.arraycopy(xpub, xpub.length / 2, key, 0, xpub.length / 2);\r
+ // end build key\r
+\r
+ // doFinal()\r
+ byte[] res = hmacSha512(data, key);\r
+\r
+ //begin operate res[:32]\r
+ byte[] f = new byte[res.length / 2];\r
+ System.arraycopy(res, 0, f, 0, res.length / 2);\r
+ f = pruneIntermediateScalar(f);\r
+ System.arraycopy(f, 0, res, 0, res.length / 2);\r
+ //end operate res[:32]\r
+\r
+ //begin operate res[:32] again\r
+ int carry = 0;\r
+ int sum = 0;\r
+ for (int i = 0; i < 32; i++) {\r
+ int xprvInt = xprv[i] & 0xFF;\r
+ int resInt = res[i] & 0xFF;\r
+ sum = xprvInt + resInt + carry;\r
+ res[i] = (byte) sum;\r
+ carry = sum >> 8;\r
+ }\r
+ if ((sum >> 8) != 0) {\r
+ System.err.println("sum does not fit in 256-bit int");\r
+ }\r
+ //end operate res[:32] again\r
+ return res;\r
+ }\r
+\r
+ private static byte[] pruneIntermediateScalar(byte[] f) {\r
+ f[0] &= 248; // clear bottom 3 bits\r
+ f[29] &= 1; // clear 7 high bits\r
+ f[30] = 0; // clear 8 bits\r
+ f[31] = 0; // clear 8 bits\r
+ return f;\r
+ }\r
+\r
+ public static byte[] child(byte[] xprv, String[] hpaths) throws NoSuchAlgorithmException, InvalidKeyException {\r
+ byte[][] paths = new byte[][]{\r
+ Hex.decode(hpaths[0]),\r
+ Hex.decode(hpaths[1])\r
+ };\r
+ byte[] res = xprv;\r
+ for (int i = 0; i < hpaths.length; i++) {\r
+ byte[] xpub = DeriveXpub.deriveXpub(res);\r
+ res = NonHardenedChild.nhChild(paths[i], res, xpub);\r
+ }\r
+ return res;\r
+ }\r
+}\r
+\r
+\r