/** * Copyright 2013 Matija Mazi. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.devcoin.crypto; import org.junit.Test; import org.spongycastle.util.encoders.Hex; import static org.junit.Assert.assertEquals; /** * This test is adapted from Armory's BIP 32 tests. */ public class ChildKeyDerivationTest { private static final int HDW_CHAIN_EXTERNAL = 0; private static final int HDW_CHAIN_INTERNAL = 1; @Test public void testChildKeyDerivation() throws Exception { String ckdTestVectors[] = { // test case 1: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "04" + "6a04ab98d9e4774ad806e302dddeb63b" + "ea16b5cb5f223ee77478e861bb583eb3" + "36b6fbcb60b5b3d4f1551ac45e5ffc49" + "36466e7d98f6c7c0ec736539f74691a6", "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", // test case 2: "be05d9ded0a73f81b814c93792f753b35c575fe446760005d44e0be13ba8935a", "02" + "b530da16bbff1428c33020e87fc9e699" + "cc9c753a63b8678ce647b7457397acef", "7012bc411228495f25d666d55fdce3f10a93908b5f9b9b7baa6e7573603a7bda" }; for(int i = 0; i < 1; i++) { byte[] priv = Hex.decode(ckdTestVectors[3 * i]); byte[] pub = Hex.decode(ckdTestVectors[3 * i + 1]); byte[] chain = Hex.decode(ckdTestVectors[3 * i + 2]); // chain code ////////////////////////////////////////////////////////////////////////// // Start with an extended PRIVATE key DeterministicKey ekprv = HDKeyDerivation.createMasterPrivKeyFromBytes(priv, chain); // Create two accounts DeterministicKey ekprv_0 = HDKeyDerivation.deriveChildKey(ekprv, 0); DeterministicKey ekprv_1 = HDKeyDerivation.deriveChildKey(ekprv, 1); // Create internal and external chain on Account 0 DeterministicKey ekprv_0_EX = HDKeyDerivation.deriveChildKey(ekprv_0, HDW_CHAIN_EXTERNAL); DeterministicKey ekprv_0_IN = HDKeyDerivation.deriveChildKey(ekprv_0, HDW_CHAIN_INTERNAL); // Create three addresses on external chain DeterministicKey ekprv_0_EX_0 = HDKeyDerivation.deriveChildKey(ekprv_0_EX, 0); DeterministicKey ekprv_0_EX_1 = HDKeyDerivation.deriveChildKey(ekprv_0_EX, 1); DeterministicKey ekprv_0_EX_2 = HDKeyDerivation.deriveChildKey(ekprv_0_EX, 2); // Create three addresses on internal chain DeterministicKey ekprv_0_IN_0 = HDKeyDerivation.deriveChildKey(ekprv_0_IN, 0); DeterministicKey ekprv_0_IN_1 = HDKeyDerivation.deriveChildKey(ekprv_0_IN, 1); DeterministicKey ekprv_0_IN_2 = HDKeyDerivation.deriveChildKey(ekprv_0_IN, 2); // Now add a few more addresses with very large indices DeterministicKey ekprv_1_IN = HDKeyDerivation.deriveChildKey(ekprv_1, HDW_CHAIN_INTERNAL); DeterministicKey ekprv_1_IN_4095 = HDKeyDerivation.deriveChildKey(ekprv_1_IN, 4095); // ExtendedHierarchicKey ekprv_1_IN_4bil = HDKeyDerivation.deriveChildKey(ekprv_1_IN, 4294967295L); ////////////////////////////////////////////////////////////////////////// // Repeat the above with PUBLIC key DeterministicKey ekpub = HDKeyDerivation.createMasterPubKeyFromBytes(HDUtils.toCompressed(pub), chain); // Create two accounts DeterministicKey ekpub_0 = HDKeyDerivation.deriveChildKey(ekpub, 0); DeterministicKey ekpub_1 = HDKeyDerivation.deriveChildKey(ekpub, 1); // Create internal and external chain on Account 0 DeterministicKey ekpub_0_EX = HDKeyDerivation.deriveChildKey(ekpub_0, HDW_CHAIN_EXTERNAL); DeterministicKey ekpub_0_IN = HDKeyDerivation.deriveChildKey(ekpub_0, HDW_CHAIN_INTERNAL); // Create three addresses on external chain DeterministicKey ekpub_0_EX_0 = HDKeyDerivation.deriveChildKey(ekpub_0_EX, 0); DeterministicKey ekpub_0_EX_1 = HDKeyDerivation.deriveChildKey(ekpub_0_EX, 1); DeterministicKey ekpub_0_EX_2 = HDKeyDerivation.deriveChildKey(ekpub_0_EX, 2); // Create three addresses on internal chain DeterministicKey ekpub_0_IN_0 = HDKeyDerivation.deriveChildKey(ekpub_0_IN, 0); DeterministicKey ekpub_0_IN_1 = HDKeyDerivation.deriveChildKey(ekpub_0_IN, 1); DeterministicKey ekpub_0_IN_2 = HDKeyDerivation.deriveChildKey(ekpub_0_IN, 2); // Now add a few more addresses with very large indices DeterministicKey ekpub_1_IN = HDKeyDerivation.deriveChildKey(ekpub_1, HDW_CHAIN_INTERNAL); DeterministicKey ekpub_1_IN_4095 = HDKeyDerivation.deriveChildKey(ekpub_1_IN, 4095); // ExtendedHierarchicKey ekpub_1_IN_4bil = HDKeyDerivation.deriveChildKey(ekpub_1_IN, 4294967295L); assertEquals(hexEncodePub(ekprv.getPubOnly()), hexEncodePub(ekpub)); assertEquals(hexEncodePub(ekprv_0.getPubOnly()), hexEncodePub(ekpub_0)); assertEquals(hexEncodePub(ekprv_1.getPubOnly()), hexEncodePub(ekpub_1)); assertEquals(hexEncodePub(ekprv_0_IN.getPubOnly()), hexEncodePub(ekpub_0_IN)); assertEquals(hexEncodePub(ekprv_0_IN_0.getPubOnly()), hexEncodePub(ekpub_0_IN_0)); assertEquals(hexEncodePub(ekprv_0_IN_1.getPubOnly()), hexEncodePub(ekpub_0_IN_1)); assertEquals(hexEncodePub(ekprv_0_IN_2.getPubOnly()), hexEncodePub(ekpub_0_IN_2)); assertEquals(hexEncodePub(ekprv_0_EX_0.getPubOnly()), hexEncodePub(ekpub_0_EX_0)); assertEquals(hexEncodePub(ekprv_0_EX_1.getPubOnly()), hexEncodePub(ekpub_0_EX_1)); assertEquals(hexEncodePub(ekprv_0_EX_2.getPubOnly()), hexEncodePub(ekpub_0_EX_2)); assertEquals(hexEncodePub(ekprv_1_IN.getPubOnly()), hexEncodePub(ekpub_1_IN)); assertEquals(hexEncodePub(ekprv_1_IN_4095.getPubOnly()), hexEncodePub(ekpub_1_IN_4095)); //assertEquals(hexEncodePub(ekprv_1_IN_4bil.getPubOnly()), hexEncodePub(ekpub_1_IN_4bil)); } } private static String hexEncodePub(DeterministicKey pubKey) { return hexEncode(pubKey.getPubKeyBytes()); } private static String hexEncode(byte[] bytes) { return new String(Hex.encode(bytes)); } }