All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.xwc1125.chain5j.crypto.Bip32ECKeyPair Maven / Gradle / Ivy

There is a newer version: 4.3.9
Show newest version
package com.xwc1125.chain5j.crypto;

import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.util.Arrays;

import org.bouncycastle.math.ec.ECPoint;

import com.xwc1125.chain5j.utils.Numeric;

/**
 * BIP-32 key pair.
 *
 * 

Adapted from: * https://github.com/bitcoinj/bitcoinj/blob/master/core/src/main/java/org/bitcoinj/crypto/DeterministicKey.java */ public class Bip32ECKeyPair extends ECKeyPair { public static final int HARDENED_BIT = 0x80000000; private final boolean parentHasPrivate; private final int childNumber; private final int depth; private final byte[] chainCode; private int parentFingerprint; private ECPoint publicKeyPoint; public Bip32ECKeyPair(BigInteger privateKey, BigInteger publicKey, int childNumber, byte[] chainCode, Bip32ECKeyPair parent) { super(privateKey, publicKey); this.parentHasPrivate = parent != null && parent.hasPrivateKey(); this.childNumber = childNumber; this.depth = parent == null ? 0 : parent.depth + 1; this.chainCode = Arrays.copyOf(chainCode, chainCode.length); this.parentFingerprint = parent != null ? parent.getFingerprint() : 0; } public static Bip32ECKeyPair create(BigInteger privateKey, byte[] chainCode) { return new Bip32ECKeyPair(privateKey, Sign.publicKeyFromPrivate(privateKey), 0, chainCode, null); } public static Bip32ECKeyPair create(byte[] privateKey, byte[] chainCode) { return create(Numeric.toBigInt(privateKey), chainCode); } public static Bip32ECKeyPair generateKeyPair(byte[] seed) { byte[] i = Hash.hmacSha512("Bitcoin seed".getBytes(), seed); byte[] il = Arrays.copyOfRange(i, 0, 32); byte[] ir = Arrays.copyOfRange(i, 32, 64); Arrays.fill(i, (byte) 0); Bip32ECKeyPair keypair = Bip32ECKeyPair.create(il, ir); Arrays.fill(il, (byte) 0); Arrays.fill(ir, (byte) 0); return keypair; } public static Bip32ECKeyPair deriveKeyPair(Bip32ECKeyPair master, int[] path) { Bip32ECKeyPair curr = master; if (path != null) { for (int childNumber : path) { curr = curr.deriveChildKey(childNumber); } } return curr; } private Bip32ECKeyPair deriveChildKey(int childNumber) { if (!hasPrivateKey()) { byte[] parentPublicKey = getPublicKeyPoint().getEncoded(true); ByteBuffer data = ByteBuffer.allocate(37); data.put(parentPublicKey); data.putInt(childNumber); byte[] i = Hash.hmacSha512(getChainCode(), data.array()); byte[] il = Arrays.copyOfRange(i, 0, 32); byte[] chainCode = Arrays.copyOfRange(i, 32, 64); Arrays.fill(i, (byte) 0); BigInteger ilInt = new BigInteger(1, il); Arrays.fill(il, (byte) 0); ECPoint ki = Sign.publicPointFromPrivate(ilInt).add(getPublicKeyPoint()); return new Bip32ECKeyPair(null, Sign.publicFromPoint(ki.getEncoded(true)), childNumber, chainCode, this); } else { ByteBuffer data = ByteBuffer.allocate(37); if (isHardened(childNumber)) { data.put(getPrivateKeyBytes33()); } else { byte[] parentPublicKey = getPublicKeyPoint().getEncoded(true); data.put(parentPublicKey); } data.putInt(childNumber); byte[] i = Hash.hmacSha512(getChainCode(), data.array()); byte[] il = Arrays.copyOfRange(i, 0, 32); byte[] chainCode = Arrays.copyOfRange(i, 32, 64); Arrays.fill(i, (byte) 0); BigInteger ilInt = new BigInteger(1, il); Arrays.fill(il, (byte) 0); BigInteger privateKey = getPrivateKey().add(ilInt).mod(Sign.CURVE.getN()); return new Bip32ECKeyPair(privateKey, Sign.publicKeyFromPrivate(privateKey), childNumber, chainCode, this); } } private int getFingerprint() { byte[] id = getIdentifier(); return id[3] & 0xFF | (id[2] & 0xFF) << 8 | (id[1] & 0xFF) << 16 | (id[0] & 0xFF) << 24; } public int getDepth() { return depth; } public int getParentFingerprint() { return parentFingerprint; } public byte[] getChainCode() { return chainCode; } public int getChildNumber() { return childNumber; } private byte[] getIdentifier() { return Hash.sha256hash160(getPublicKeyPoint().getEncoded(true)); } public ECPoint getPublicKeyPoint() { if (publicKeyPoint == null) { publicKeyPoint = Sign.publicPointFromPrivate(getPrivateKey()); } return publicKeyPoint; } public byte[] getPrivateKeyBytes33() { final int numBytes = 33; byte[] bytes33 = new byte[numBytes]; byte[] priv = bigIntegerToBytes32(getPrivateKey()); System.arraycopy(priv, 0, bytes33, numBytes - priv.length, priv.length); return bytes33; } private boolean hasPrivateKey() { return this.getPrivateKey() != null || parentHasPrivate; } private static byte[] bigIntegerToBytes32(BigInteger b) { final int numBytes = 32; byte[] src = b.toByteArray(); byte[] dest = new byte[numBytes]; boolean isFirstByteOnlyForSign = src[0] == 0; int length = isFirstByteOnlyForSign ? src.length - 1 : src.length; int srcPos = isFirstByteOnlyForSign ? 1 : 0; int destPos = numBytes - length; System.arraycopy(src, srcPos, dest, destPos, length); return dest; } private static boolean isHardened(int a) { return (a & HARDENED_BIT) != 0; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy