CyberChef/src/core/operations/PowerSet.mjs

93 lines
2.4 KiB
JavaScript

/**
* @author d98762625 [d98762625@gmail.com]
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
import Operation from "../Operation";
/**
* Power Set operation
*/
class PowerSet extends Operation {
/**
* Power set constructor
*/
constructor() {
super();
this.name = "Power Set";
this.module = "Default";
this.description = "Calculates all the subsets of a set.";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
name: "Item delimiter",
type: "binaryString",
value: ","
},
];
}
/**
* Generate the power set
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
[this.itemDelimiter] = args;
// Split and filter empty strings
const inputArray = input.split(this.itemDelimiter).filter(a => a);
if (inputArray.length) {
return this.runPowerSet(inputArray);
}
return "";
}
/**
* Return the power set of the inputted set.
*
* @param {Object[]} a
* @returns {Object[]}
*/
runPowerSet(a) {
// empty array items getting picked up
a = a.filter(i => i.length);
if (!a.length) {
return [];
}
/**
* Decimal to binary function
* @param {*} dec
*/
const toBinary = (dec) => (dec >>> 0).toString(2);
const result = new Set();
// Get the decimal number to make a binary as long as the input
const maxBinaryValue = parseInt(Number(a.map(i => "1").reduce((p, c) => p + c)), 2);
// Make an array of each binary number from 0 to maximum
const binaries = [...Array(maxBinaryValue + 1).keys()]
.map(toBinary)
.map(i => i.padStart(toBinary(maxBinaryValue).length, "0"));
// XOR the input with each binary to get each unique permutation
binaries.forEach((binary) => {
const split = binary.split("");
result.add(a.filter((item, index) => split[index] === "1"));
});
// map for formatting & put in length order.
return [...result]
.map(r => r.join(this.itemDelimiter)).sort((a, b) => a.length - b.length)
.map(i => `${i}\n`).join("");
}
}
export default PowerSet;