OSDN Git Service

Merge pull request #7 from Bytom/merge_tx_signer
[bytom/bytom-java-sdk.git] / tx-signer / src / main / java / io / bytom / offline / common / NonHardenedChild.java
diff --git a/tx-signer/src/main/java/io/bytom/offline/common/NonHardenedChild.java b/tx-signer/src/main/java/io/bytom/offline/common/NonHardenedChild.java
new file mode 100755 (executable)
index 0000000..15091b3
--- /dev/null
@@ -0,0 +1,84 @@
+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