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

org.bitcoinj.crypto.HDPath Maven / Gradle / Ivy

There is a newer version: 0.17-beta1
Show newest version
/*
 * Copyright 2019 Michael Sean Gilligan.
 *
 * 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 org.bitcoinj.crypto;

import com.google.common.base.Splitter;

import javax.annotation.Nonnull;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

/**
 * HD Key derivation path. {@code HDPath} can be used to represent a full path or a relative path.
 * The {@code hasPrivateKey} {@code boolean} is used for rendering to {@code String}
 * but (at present) not much else. It defaults to {@code false} which is the preferred setting for a relative path.
 * 

* {@code HDPath} is immutable and uses the {@code Collections.UnmodifiableList} type internally. *

* It implements {@code java.util.List} to ease migration * from the previous Guava {@code ImmutableList}. It should be a minor breaking change * to replace {@code ImmutableList} with {@code List} where necessary in your code. Although * it is recommended to use the {@code HDPath} type for clarity and for access to {@code HDPath}-specific functionality. *

* Take note of the overloaded factory methods {@link HDPath#M()} and {@link HDPath#m()}. These can be used to very * concisely create HDPath objects (especially when statically imported.) */ public class HDPath extends AbstractList { private static final char PREFIX_PRIVATE = 'm'; private static final char PREFIX_PUBLIC = 'M'; private static final char SEPARATOR = '/'; private static final Splitter SEPARATOR_SPLITTER = Splitter.on(SEPARATOR).trimResults(); protected final boolean hasPrivateKey; protected final List unmodifiableList; /** * Constructs a path for a public or private key. * * @param hasPrivateKey Whether it is a path to a private key or not * @param list List of children in the path */ public HDPath(boolean hasPrivateKey, List list) { this.hasPrivateKey = hasPrivateKey; this.unmodifiableList = Collections.unmodifiableList(list); } /** * Constructs a path for a public key. * * @param list List of children in the path */ public HDPath(List list) { this(false, list); } /** * Returns a path for a public or private key. * * @param hasPrivateKey Whether it is a path to a private key or not * @param list List of children in the path */ private static HDPath of(boolean hasPrivateKey, List list) { return new HDPath(hasPrivateKey, list); } /** * Returns a path for a public key. * * @param list List of children in the path */ public static HDPath M(List list) { return HDPath.of(false, list); } /** * Returns an empty path for a public key. */ public static HDPath M() { return HDPath.M(Collections.emptyList()); } /** * Returns a path for a public key. * * @param childNumber Single child in path */ public static HDPath M(ChildNumber childNumber) { return HDPath.M(Collections.singletonList(childNumber)); } /** * Returns a path for a public key. * * @param children Children in the path */ public static HDPath M(ChildNumber... children) { return HDPath.M(Arrays.asList(children)); } /** * Returns a path for a private key. * * @param list List of children in the path */ public static HDPath m(List list) { return HDPath.of(true, list); } /** * Returns an empty path for a private key. */ public static HDPath m() { return HDPath.m(Collections.emptyList()); } /** * Returns a path for a private key. * * @param childNumber Single child in path */ public static HDPath m(ChildNumber childNumber) { return HDPath.m(Collections.singletonList(childNumber)); } /** * Returns a path for a private key. * * @param children Children in the path */ public static HDPath m(ChildNumber... children) { return HDPath.m(Arrays.asList(children)); } /** * Create an HDPath from a path string. The path string is a human-friendly representation of the deterministic path. For example: * * "44H / 0H / 0H / 1 / 1" * * Where a letter "H" means hardened key. Spaces are ignored. */ public static HDPath parsePath(@Nonnull String path) { List parsedNodes = new LinkedList<>(SEPARATOR_SPLITTER.splitToList(path)); boolean hasPrivateKey = false; if (!parsedNodes.isEmpty()) { final String firstNode = parsedNodes.get(0); if (firstNode.equals(Character.toString(PREFIX_PRIVATE))) hasPrivateKey = true; if (hasPrivateKey || firstNode.equals(Character.toString(PREFIX_PUBLIC))) parsedNodes.remove(0); } List nodes = new ArrayList<>(parsedNodes.size()); for (String n : parsedNodes) { if (n.isEmpty()) continue; boolean isHard = n.endsWith("H"); if (isHard) n = n.substring(0, n.length() - 1).trim(); int nodeNumber = Integer.parseInt(n); nodes.add(new ChildNumber(nodeNumber, isHard)); } return new HDPath(hasPrivateKey, nodes); } /** * Is this a path to a private key? * * @return true if yes, false if no or a partial path */ public boolean hasPrivateKey() { return hasPrivateKey; } /** * Extend the path by appending additional ChildNumber objects. * * @param child1 the first child to append * @param children zero or more additional children to append * @return A new immutable path */ public HDPath extend(ChildNumber child1, ChildNumber... children) { List mutable = new ArrayList<>(this.unmodifiableList); // Mutable copy mutable.add(child1); mutable.addAll(Arrays.asList(children)); return new HDPath(this.hasPrivateKey, mutable); } /** * Extend the path by appending a relative path. * * @param path2 the relative path to append * @return A new immutable path */ public HDPath extend(HDPath path2) { List mutable = new ArrayList<>(this.unmodifiableList); // Mutable copy mutable.addAll(path2); return new HDPath(this.hasPrivateKey, mutable); } /** * Extend the path by appending a relative path. * * @param path2 the relative path to append * @return A new immutable path */ public HDPath extend(List path2) { return this.extend(HDPath.M(path2)); } @Override public ChildNumber get(int index) { return unmodifiableList.get(index); } @Override public int size() { return unmodifiableList.size(); } @Override public String toString() { StringBuilder b = new StringBuilder(); b.append(hasPrivateKey ? HDPath.PREFIX_PRIVATE : HDPath.PREFIX_PUBLIC); for (ChildNumber segment : unmodifiableList) { b.append(HDPath.SEPARATOR); b.append(segment.toString()); } return b.toString(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy