Update. Added Base58 Check operation (similar to Bech32 operation) with tests.
This commit is contained in:
parent
89d5f7e96b
commit
323774b9ae
@ -381,7 +381,9 @@
|
|||||||
"Public Key To TRX Style Address",
|
"Public Key To TRX Style Address",
|
||||||
"ETH / TRX Conversion",
|
"ETH / TRX Conversion",
|
||||||
"Key To Extended Key",
|
"Key To Extended Key",
|
||||||
"Private Extended Key To Public"
|
"Private Extended Key To Public",
|
||||||
|
"From Base58Check",
|
||||||
|
"To Base58Check"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
71
src/core/operations/FromBase58Check.mjs
Normal file
71
src/core/operations/FromBase58Check.mjs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/**
|
||||||
|
* @author dgoldenberg [dgoldenberg@mitre.org]
|
||||||
|
* @copyright Crown Copyright 2026
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
import { base58Decode, b58DoubleSHAChecksum} from "../lib/Bitcoin.mjs";
|
||||||
|
import { fromArrayBuffer } from "crypto-api/src/encoder/array-buffer.mjs";
|
||||||
|
import {toHex} from "crypto-api/src/encoder/hex.mjs";
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FromBase58Check operation
|
||||||
|
*/
|
||||||
|
class FromBase58Check extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FromBase58Check constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "From Base58Check";
|
||||||
|
this.module = "Default";
|
||||||
|
this.description = "Decodes Base58 check encoded data. This is a version byte, data and a 4 byte checksum at the end. Many addresses, private keys and other cryptocurrency artifacts are encoded in this format.";
|
||||||
|
this.infoURL = "https://en.bitcoin.it/Base58Check_encoding"; // 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 = "JSON";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
name: "Version Byte Length",
|
||||||
|
type: "number",
|
||||||
|
value: 1
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {JSON}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
// We check if input is blank.
|
||||||
|
// If its blank or just whitespace, we don't need to bother dealing with it.
|
||||||
|
|
||||||
|
if (input.trim().length === 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
input = input.trim();
|
||||||
|
if (b58DoubleSHAChecksum(input)) {
|
||||||
|
const decoded = base58Decode(input);
|
||||||
|
const versionHex = toHex(fromArrayBuffer(decoded.slice(0, args[0])));
|
||||||
|
const checksum = toHex(fromArrayBuffer(decoded.slice(-4,)));
|
||||||
|
const data = toHex(fromArrayBuffer(decoded.slice(args[0], -4)));
|
||||||
|
return {
|
||||||
|
"version": versionHex,
|
||||||
|
"checksum": checksum,
|
||||||
|
"data": data
|
||||||
|
};
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new OperationError("Invalid Checksum.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FromBase58Check;
|
||||||
64
src/core/operations/ToBase58Check.mjs
Normal file
64
src/core/operations/ToBase58Check.mjs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/**
|
||||||
|
* @author dgoldenberg [dgoldenberg@mitre.org]
|
||||||
|
* @copyright Crown Copyright 2026
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
// import OperationError from "../errors/OperationError.mjs";
|
||||||
|
import { base58Encode, doubleSHA, makeSureIsHex} from "../lib/Bitcoin.mjs";
|
||||||
|
import { fromArrayBuffer } from "crypto-api/src/encoder/array-buffer.mjs";
|
||||||
|
import {toHex} from "crypto-api/src/encoder/hex.mjs";
|
||||||
|
import Utils from "../Utils.mjs";
|
||||||
|
/**
|
||||||
|
* To Base58Check operation
|
||||||
|
*/
|
||||||
|
class ToBase58Check extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ToBase58Check constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "To Base58Check";
|
||||||
|
this.module = "Default";
|
||||||
|
this.description = "Converts passed in string to Base58 Check Encoding. Version Bytes (as hex) are pre-pended, and a checksum is created.";
|
||||||
|
this.infoURL = "https://en.bitcoin.it/Base58Check_encoding"; // 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 = [
|
||||||
|
{
|
||||||
|
"name": "Version Bytes",
|
||||||
|
"type": "toggleString",
|
||||||
|
"value": "",
|
||||||
|
"toggleValues": ["Hex"]
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
// We check if input is blank.
|
||||||
|
// If its blank or just whitespace, we don't need to bother dealing with it.
|
||||||
|
|
||||||
|
if (input.trim().length === 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
input = input.trim();
|
||||||
|
const processedInput = makeSureIsHex(input);
|
||||||
|
const processedVersion = makeSureIsHex(args[0].string);
|
||||||
|
const extendedInput = processedVersion + processedInput;
|
||||||
|
const checksumHash = toHex(doubleSHA(fromArrayBuffer(Utils.convertToByteArray(extendedInput, "hex"))));
|
||||||
|
const finalString = extendedInput + checksumHash.slice(0, 8);
|
||||||
|
const encodedOutput = base58Encode(Utils.convertToByteArray(finalString, "hex"));
|
||||||
|
return encodedOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ToBase58Check;
|
||||||
@ -206,6 +206,7 @@ import "./tests/ETHTRXConversion.mjs";
|
|||||||
import "./tests/KeyToExtendedKey.mjs";
|
import "./tests/KeyToExtendedKey.mjs";
|
||||||
import "./tests/PrivateExtendedKeyToPublic.mjs";
|
import "./tests/PrivateExtendedKeyToPublic.mjs";
|
||||||
import "./tests/SeedToAddress.mjs";
|
import "./tests/SeedToAddress.mjs";
|
||||||
|
import "./tests/Base58Check.mjs";
|
||||||
import "./tests/GetAllCasings.mjs";
|
import "./tests/GetAllCasings.mjs";
|
||||||
import "./tests/SIGABA.mjs";
|
import "./tests/SIGABA.mjs";
|
||||||
import "./tests/ELFInfo.mjs";
|
import "./tests/ELFInfo.mjs";
|
||||||
|
|||||||
144
tests/operations/tests/Base58Check.mjs
Normal file
144
tests/operations/tests/Base58Check.mjs
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
/**
|
||||||
|
* Private key to secp256k1 public key tests.
|
||||||
|
*
|
||||||
|
* @author dgoldenberg [virtualcurrency@mitre.org]
|
||||||
|
* @copyright MITRE 2023
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
|
|
||||||
|
TestRegister.addTests([
|
||||||
|
{
|
||||||
|
name: "Basic Base58 Check Decoding",
|
||||||
|
input: "1111111111111111111114oLvT2",
|
||||||
|
expectedOutput: "{\n \"version\": \"\",\n \"checksum\": \"94a00911\",\n \"data\": \"000000000000000000000000000000000000000000\"\n}",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Base58Check",
|
||||||
|
"args": [0]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Basic Base58 Check Decoding (Invalid Checksum)",
|
||||||
|
input: "1111111111111111111114oLvT3",
|
||||||
|
expectedOutput: "Invalid Checksum.",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Base58Check",
|
||||||
|
"args": [0]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Basic Base58 Check Decoding (Invalid Checksum Leading Zeros 1)",
|
||||||
|
input: "111111111111111111114oLvT2",
|
||||||
|
expectedOutput: "Invalid Checksum.",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Base58Check",
|
||||||
|
"args": [0]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Basic Base58 Check Decoding (Invalid Checksum Leading Zeros 2)",
|
||||||
|
input: "11111111111111111111114oLvT2",
|
||||||
|
expectedOutput: "Invalid Checksum.",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Base58Check",
|
||||||
|
"args": [0]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Basic Base58 Check Decoding (Invalid Checksum Leading Zeros 2 With Single Version Byte)",
|
||||||
|
input: "11111111111111111111114oLvT2",
|
||||||
|
expectedOutput: "Invalid Checksum.",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Base58Check",
|
||||||
|
"args": [1]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Basic Base58 Check Decoding Gibberish",
|
||||||
|
input: "A9CfWPWwyc4JC4ATfv4ajp9aGunQ375hLHQ8gcY",
|
||||||
|
expectedOutput: "Invalid Checksum.",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Base58Check",
|
||||||
|
"args": [1]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Basic Base58 Check Decoding (Invalid Checksum With one Byte Version)",
|
||||||
|
input: "1111111111111111111114oLvT3",
|
||||||
|
expectedOutput: "Invalid Checksum.",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Base58Check",
|
||||||
|
"args": [1]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Basic Base58 Check Decoding (Version Length 1)",
|
||||||
|
input: "1111111111111111111114oLvT2",
|
||||||
|
expectedOutput: "{\n \"version\": \"00\",\n \"checksum\": \"94a00911\",\n \"data\": \"0000000000000000000000000000000000000000\"\n}",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Base58Check",
|
||||||
|
"args": [1]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "To Base58 Check Basic",
|
||||||
|
input: "0000000000000000000000000000000000000000",
|
||||||
|
expectedOutput: "1111111111111111111114oLvT2",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "To Base58Check",
|
||||||
|
"args": [{ "option": "Hex", "string": "00" }]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "To and From Base58 Check",
|
||||||
|
input: "0000000000000000000000000000000000000000",
|
||||||
|
expectedOutput: "{\n \"version\": \"00\",\n \"checksum\": \"94a00911\",\n \"data\": \"0000000000000000000000000000000000000000\"\n}",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "To Base58Check",
|
||||||
|
"args": [{ "option": "Hex", "string": "00" }]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"op": "From Base58Check",
|
||||||
|
"args": [1]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "To and From Base58 Check (Technically wrong version byte length",
|
||||||
|
input: "0000000000000000000000000000000000000000",
|
||||||
|
expectedOutput: "{\n \"version\": \"0000000000\",\n \"checksum\": \"94a00911\",\n \"data\": \"00000000000000000000000000000000\"\n}",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "To Base58Check",
|
||||||
|
"args": [{ "option": "Hex", "string": "00" }]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"op": "From Base58Check",
|
||||||
|
"args": [5]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
]);
|
||||||
Loading…
x
Reference in New Issue
Block a user