Added an operation to turn an extended private key to its public key version. We deserialize, turn the private key into the appropriate public key, grab the appropriate public key version then reserialize.
This commit is contained in:
parent
cf0733dc6f
commit
d47c7a633a
@ -358,7 +358,8 @@
|
||||
"Public Key To ETH Style Address",
|
||||
"Public Key To TRX Style Address",
|
||||
"ETH / TRX Conversion",
|
||||
"Key To Extended Key"
|
||||
"Key To Extended Key",
|
||||
"Private Extended Key To Public"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@ -448,6 +448,32 @@ const versionBytes = {
|
||||
"ttpv": "0436ef7d"
|
||||
};
|
||||
|
||||
// Lookup matching private extended key versions to public
|
||||
const privateToPublicExtendedKeys = {
|
||||
"xprv": "xpub",
|
||||
"yprv": "ypub",
|
||||
"zprv": "zpub",
|
||||
"Zprv": "Zpub",
|
||||
"Yprv": "Ypub",
|
||||
"Ltpv": "Ltub",
|
||||
"Mtpv": "Mtub",
|
||||
"ttpv": "ttub",
|
||||
"tprv": "tpub",
|
||||
"uprv": "upub",
|
||||
"vprv": "vprv",
|
||||
"Uprv": "Upub",
|
||||
"Vprv": "Vpub"
|
||||
};
|
||||
|
||||
/**
|
||||
* For a given private extended key version string, returns the appropriate public version string.
|
||||
* @param {*} input
|
||||
* @returns
|
||||
*/
|
||||
export function privateVersionToPublicVersion(input) {
|
||||
return privateToPublicExtendedKeys[input];
|
||||
}
|
||||
|
||||
/**
|
||||
* We return the correct version bytes from the versionBytes map, given input string.
|
||||
* @param {*} input
|
||||
|
||||
65
src/core/operations/PrivateExtendedKeyToPublic.mjs
Normal file
65
src/core/operations/PrivateExtendedKeyToPublic.mjs
Normal file
@ -0,0 +1,65 @@
|
||||
/**
|
||||
* @author dgoldenberg [virtualcurrency@mitre.org]
|
||||
* @copyright Crown Copyright 2025
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import ec from "elliptic";
|
||||
import { deserializeExtendedKeyFunc, serializeExtendedKeyFunc, getExtendedKeyVersion, privateVersionToPublicVersion, getExtendedKeyString
|
||||
} from "../lib/Bitcoin.mjs";
|
||||
|
||||
/**
|
||||
* PrivateExtendedKeyToPublic operation
|
||||
*/
|
||||
class PrivateExtendedKeyToPublic extends Operation {
|
||||
|
||||
/**
|
||||
* PrivateExtendedKeyToPublic constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Private Extended Key To Public";
|
||||
this.module = "Default";
|
||||
this.description = "Convert a private extended key to its associated public key. This may be useful post a BIP32Derivation operation if you need the extended public key for a different toolset.";
|
||||
this.infoURL = "https://en.bitcoin.it/wiki/BIP_0032"; // Usually a Wikipedia link. Remember to remove localisation (i.e. https://wikipedia.org/etc rather than https://en.wikipedia.org/etc)
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
// const [firstArg, secondArg] = args;
|
||||
// const [firstArg, secondArg] = args;
|
||||
if (input.trim().length === 0) {
|
||||
return "";
|
||||
}
|
||||
input = input.trim();
|
||||
|
||||
const result = deserializeExtendedKeyFunc(input);
|
||||
const versionString = getExtendedKeyString(result.version);
|
||||
const privateVersions = ["xprv", "yprv", "zprv", "Zprv", "Yprv", "Ltpv", "Mtpv", "ttpv", "tprv", "uprv", "vprv", "Uprv", "Vprv"];
|
||||
if (privateVersions.indexOf(versionString) === -1) {
|
||||
throw new OperationError("Not an extended private key.");
|
||||
}
|
||||
const newVersion = privateVersionToPublicVersion(versionString);
|
||||
|
||||
const processedInput = result.masterkey.slice(2,);
|
||||
const ecContext = ec.ec("secp256k1");
|
||||
const key = ecContext.keyFromPrivate(processedInput);
|
||||
const pubkey = key.getPublic(true, "hex");
|
||||
|
||||
return serializeExtendedKeyFunc(getExtendedKeyVersion(newVersion), result.level, result.fingerprint, result.i, result.chaincode, pubkey);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default PrivateExtendedKeyToPublic;
|
||||
@ -186,6 +186,7 @@ import "./tests/PublicKeyToETHStyleAddress.mjs";
|
||||
import "./tests/PublicKeyToTRXStyleAddress.mjs";
|
||||
import "./tests/ETHTRXConversion.mjs";
|
||||
import "./tests/KeyToExtendedKey.mjs";
|
||||
import "./tests/PrivateExtendedKeyToPublic.mjs";
|
||||
import "./tests/SeedToAddress.mjs";
|
||||
import "./tests/GetAllCasings.mjs";
|
||||
import "./tests/SIGABA.mjs";
|
||||
|
||||
58
tests/operations/tests/PrivateExtendedKeyToPublic.mjs
Normal file
58
tests/operations/tests/PrivateExtendedKeyToPublic.mjs
Normal file
@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Private Extended Key to Public Version Extended Key Tests.
|
||||
*
|
||||
* @author dgoldenberg [virtualcurrency@mitre.org]
|
||||
* @copyright MITRE 2023
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "Private Extended Key To Public (xprv)",
|
||||
input: "xprv9yoUuSwPzquxGY9ZsqizskpbKBbthhTpj5w4k2o8cxoFKigDAhUV3GCHtKL4CFuUCHvwGt9bo1DRnavubpiiS2wJ9AN9bbnipT95qKyda6r",
|
||||
expectedOutput: "xpub6CnqJxUHqDUFV2E2ysG1EtmKsDSP7ABg6JrfYRCkBJLECX1MiEnjb4WmjYnUvYjzvnrygmcVMH2vSuZMNUWozhrDpqr8fpEZfxAune2FYPX",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Private Extended Key To Public",
|
||||
"args": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Private Extended Key To Public (yprv)",
|
||||
input: "yprvAJEHhwPWiVEbr18CDkhzPRm3ywbJCCuVV7Q8UzLtE4t75hajmN7DvjeS3BWbQGPdAANzyPmhUZitHEqyLX8KoBBnRqitj2Kvisw6dgmVwBH",
|
||||
expectedOutput: "ypub6XDe7SvQYrnu4VCfKnEzkZhnXyRnbfdLrLKjHNkVnQR5xVutJuRUUXxutSgRgjRaJKHKHW1WXLqCmbgQgapdwsx98NnRDXwhZFkavU6ojct",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Private Extended Key To Public",
|
||||
"args": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Private Extended Key To Public (zprv)",
|
||||
input: "zprvAdjAKuQajRu4ptst29FzkcB18fyZuHCKJhe51m38ejMcjW5P4frUffXMYfwLiTs4UrFD5m41So3VhAWGyrb4YV4gFRwYuLom8psLoW252Xd",
|
||||
expectedOutput: "zpub6riWjQwUZoTN3NxM8Ao17k7jghp4JjvAfvZfp9SkD4tbcJQXcDAjDTqqPxywFFvD1BHiMMKvW3EjwMvuc7k2YcQbF1v2R42gxac4k3qq3sc",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Private Extended Key To Public",
|
||||
"args": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Private Extended Key To Public (blank)",
|
||||
input: "",
|
||||
expectedOutput: "",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Private Extended Key To Public",
|
||||
"args": []
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
]);
|
||||
Loading…
x
Reference in New Issue
Block a user