From 4847b45f7d91fc83fe4077b4f763fe427ba600c3 Mon Sep 17 00:00:00 2001 From: Spencer Walden Date: Thu, 30 Mar 2023 23:51:19 -0700 Subject: [PATCH 1/4] Adds Rolling, Rolling cumulative, and Rolling cumulative (self) XOR options. Not in love with those names though, tbh --- src/core/operations/XOR.mjs | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/src/core/operations/XOR.mjs b/src/core/operations/XOR.mjs index aa228842..7f6f8e50 100644 --- a/src/core/operations/XOR.mjs +++ b/src/core/operations/XOR.mjs @@ -6,7 +6,7 @@ import Operation from "../Operation.mjs"; import Utils from "../Utils.mjs"; -import { bitOp, xor, BITWISE_OP_DELIMS } from "../lib/BitwiseOp.mjs"; +import { bitOp, xor, add, BITWISE_OP_DELIMS } from "../lib/BitwiseOp.mjs"; /** * XOR operation @@ -21,7 +21,7 @@ class XOR extends Operation { this.name = "XOR"; this.module = "Default"; - this.description = "XOR the input with the given key.
e.g. fe023da5

Options
Null preserving: If the current byte is 0x00 or the same as the key, skip it.

Scheme:"; + this.description = "XOR the input with the given key.
e.g. fe023da5

Options
Null preserving: If the current byte is 0x00 or the same as the key, skip it.

Scheme:"; this.infoURL = "https://wikipedia.org/wiki/XOR"; this.inputType = "ArrayBuffer"; this.outputType = "byteArray"; @@ -35,7 +35,7 @@ class XOR extends Operation { { "name": "Scheme", "type": "option", - "value": ["Standard", "Input differential", "Output differential", "Cascade"] + "value": ["Standard", "Input differential", "Output differential", "Cascade", "Rolling", "Rolling cumulative", "Rolling cumulative (self)"] }, { "name": "Null preserving", @@ -55,6 +55,31 @@ class XOR extends Operation { const key = Utils.convertToByteArray(args[0].string || "", args[0].option), [, scheme, nullPreserving] = args; + if (scheme.startswith("Rolling") && key.length) { + const inputChunks = Utils.chunked(input, key.length); + let runningIndex = 0; + let runningKey = key; + let xorred = null; + return inputChunks.reduce((result, current, index) => { + runningIndex += index; + switch (scheme) { + case "Rolling": // key = key + index + return result.concat(bitOp(current, key.map(x => add(x, index)), xor, nullPreserving, scheme)); + case "Rolling cumulative": // key = key + index + previous + return result.concat(bitOp(current, key.map(x => add(x, runningIndex)), xor, nullPreserving, scheme)); + case "Rolling cumulative (self)": // key = key XOR previous chunk + // Xor this chunk + xorred = bitOp(current, runningKey, xor, nullPreserving, scheme)); + + // Update the running key for next part of loop + runningKey = bitOp(runningKey, current, xor, nullPreserving, scheme)); + + // Return the result with the newest xor'd chunk + return result.concat(xorred); + } + }, Utils.strToByteArray("")); + } + return bitOp(input, key, xor, nullPreserving, scheme); } From 69d9ad9ab7bb5f7963ca41bdef04d1dbc0246ae8 Mon Sep 17 00:00:00 2001 From: Spencer Walden Date: Thu, 30 Mar 2023 23:51:43 -0700 Subject: [PATCH 2/4] Adds a few more tests to the BitwiseOp to test some XOR functionality --- tests/operations/tests/BitwiseOp.mjs | 46 ++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/tests/operations/tests/BitwiseOp.mjs b/tests/operations/tests/BitwiseOp.mjs index 50303677..b8716aeb 100644 --- a/tests/operations/tests/BitwiseOp.mjs +++ b/tests/operations/tests/BitwiseOp.mjs @@ -10,7 +10,7 @@ import TestRegister from "../../lib/TestRegister.mjs"; TestRegister.addTests([ { name: "Bit shift left", - input: "01010101 10101010 11111111 00000000 11110000 00001111 00110011 11001100", + input: "01010101 10101010 11111111 00000000 11110000 00001111 00110011 11001100", expectedOutput: "10101010 01010100 11111110 00000000 11100000 00011110 01100110 10011000", recipeConfig: [ { "op": "From Binary", @@ -23,7 +23,7 @@ TestRegister.addTests([ }, { name: "Bit shift right: Logical shift", - input: "01010101 10101010 11111111 00000000 11110000 00001111 00110011 11001100", + input: "01010101 10101010 11111111 00000000 11110000 00001111 00110011 11001100", expectedOutput: "00101010 01010101 01111111 00000000 01111000 00000111 00011001 01100110", recipeConfig: [ { "op": "From Binary", @@ -36,7 +36,7 @@ TestRegister.addTests([ }, { name: "Bit shift right: Arithmetic shift", - input: "01010101 10101010 11111111 00000000 11110000 00001111 00110011 11001100", + input: "01010101 10101010 11111111 00000000 11110000 00001111 00110011 11001100", expectedOutput: "00101010 11010101 11111111 00000000 11111000 00000111 00011001 11100110", recipeConfig: [ { "op": "From Binary", @@ -47,4 +47,44 @@ TestRegister.addTests([ "args": ["Space"] } ] }, + { + name: "XOR: empty", + input: "", + expectedOutput: "", + recipeConfig: [ + { "op": "From Binary", + "args": ["Space"] }, + { "op": "XOR", + "args": ["binary", "11111111", "Standard", false] }, + { "op": "To Binary", + "args": ["Space"] } + ] + }, + { + name: "XOR: 1111111, standard, no preserve nulls", + input: "01010101 10101010 11111111 00000000 11110000 00001111 00110011 11001100", + expectedOutput: "10101010 01010101 00000000 11111111 00001111 11110000 11001100 00110011", + recipeConfig: [ + { "op": "From Binary", + "args": ["Space"] }, + { "op": "XOR", + "args": ["binary", "11111111", "Standard", false] }, + { "op": "To Binary", + "args": ["Space"] } + ] + }, + { + name: "XOR: 1111111, standard, preserve nulls", + input: "01010101 10101010 11111111 00000000 11110000 00001111 00110011 11001100", + // Should the ones be kept as ones? Seems like it's not a null that we're preserving... + expectedOutput: "10101010 01010101 11111111 00000000 00001111 11110000 11001100 00110011", + recipeConfig: [ + { "op": "From Binary", + "args": ["Space"] }, + { "op": "XOR", + "args": ["binary", "11111111", "Standard", true] }, + { "op": "To Binary", + "args": ["Space"] } + ] + }, ]); From 6b529cc79d61b97ef47f9b8835d6b14afa84f6c1 Mon Sep 17 00:00:00 2001 From: Spencer Walden Date: Fri, 31 Mar 2023 00:11:22 -0700 Subject: [PATCH 3/4] Fix dumb mistakes in transcribing old code --- src/core/operations/XOR.mjs | 117 ++++++++++++++++++++++++------------ 1 file changed, 80 insertions(+), 37 deletions(-) diff --git a/src/core/operations/XOR.mjs b/src/core/operations/XOR.mjs index 7f6f8e50..b8884419 100644 --- a/src/core/operations/XOR.mjs +++ b/src/core/operations/XOR.mjs @@ -12,7 +12,6 @@ import { bitOp, xor, add, BITWISE_OP_DELIMS } from "../lib/BitwiseOp.mjs"; * XOR operation */ class XOR extends Operation { - /** * XOR constructor */ @@ -21,27 +20,36 @@ class XOR extends Operation { this.name = "XOR"; this.module = "Default"; - this.description = "XOR the input with the given key.
e.g. fe023da5

Options
Null preserving: If the current byte is 0x00 or the same as the key, skip it.

Scheme:
  • Standard - key is unchanged after each round
  • Input differential - key is set to the value of the previous unprocessed byte
  • Output differential - key is set to the value of the previous processed byte
  • Cascade - key is set to the input byte shifted by one
  • Rolling - key is set to the value of itself added with the current position in the bytes
  • Rolling cumulative - key is set to the value of itself added with a cumulative addition of the position in the bytes
  • Rolling cumulative (self) - key is set to the value of itself XOR'd with the previous chunk of bytes (where the chunk size is equal to key size)
"; + this.description = + "XOR the input with the given key.
e.g. fe023da5

Options
Null preserving: If the current byte is 0x00 or the same as the key, skip it.

Scheme:
  • Standard - key is unchanged after each round
  • Input differential - key is set to the value of the previous unprocessed byte
  • Output differential - key is set to the value of the previous processed byte
  • Cascade - key is set to the input byte shifted by one
  • Rolling - key is set to the value of itself added with the current position in the bytes
  • Rolling cumulative - key is set to the value of itself added with a cumulative addition of the position in the bytes
  • Rolling cumulative (self) - key is set to the value of itself XOR'd with the previous chunk of bytes (where the chunk size is equal to key size)
"; this.infoURL = "https://wikipedia.org/wiki/XOR"; this.inputType = "ArrayBuffer"; this.outputType = "byteArray"; this.args = [ { - "name": "Key", - "type": "toggleString", - "value": "", - "toggleValues": BITWISE_OP_DELIMS + name: "Key", + type: "toggleString", + value: "", + toggleValues: BITWISE_OP_DELIMS, }, { - "name": "Scheme", - "type": "option", - "value": ["Standard", "Input differential", "Output differential", "Cascade", "Rolling", "Rolling cumulative", "Rolling cumulative (self)"] + name: "Scheme", + type: "option", + value: [ + "Standard", + "Input differential", + "Output differential", + "Cascade", + "Rolling", + "Rolling cumulative", + "Rolling cumulative (self)", + ], }, { - "name": "Null preserving", - "type": "boolean", - "value": false - } + name: "Null preserving", + type: "boolean", + value: false, + }, ]; } @@ -52,33 +60,69 @@ class XOR extends Operation { */ run(input, args) { input = new Uint8Array(input); - const key = Utils.convertToByteArray(args[0].string || "", args[0].option), + const key = Utils.convertToByteArray( + args[0].string || "", + args[0].option + ), [, scheme, nullPreserving] = args; - if (scheme.startswith("Rolling") && key.length) { - const inputChunks = Utils.chunked(input, key.length); - let runningIndex = 0; - let runningKey = key; - let xorred = null; - return inputChunks.reduce((result, current, index) => { - runningIndex += index; - switch (scheme) { - case "Rolling": // key = key + index - return result.concat(bitOp(current, key.map(x => add(x, index)), xor, nullPreserving, scheme)); - case "Rolling cumulative": // key = key + index + previous - return result.concat(bitOp(current, key.map(x => add(x, runningIndex)), xor, nullPreserving, scheme)); - case "Rolling cumulative (self)": // key = key XOR previous chunk - // Xor this chunk - xorred = bitOp(current, runningKey, xor, nullPreserving, scheme)); + if (scheme.startsWith("Rolling") && key.length) { + const inputChunks = Utils.chunked(input, key.length); + let runningIndex = 0; + let runningKey = key; + let xorred = null; + return inputChunks.reduce((result, current, index) => { + runningIndex += index; + switch (scheme) { + // key = key + index + case "Rolling": + return result.concat( + bitOp( + current, + key.map((x) => add(x, index)), + xor, + nullPreserving, + scheme + ) + ); - // Update the running key for next part of loop - runningKey = bitOp(runningKey, current, xor, nullPreserving, scheme)); + // key = key + index + previous + case "Rolling cumulative": + return result.concat( + bitOp( + current, + key.map((x) => add(x, runningIndex)), + xor, + nullPreserving, + scheme + ) + ); - // Return the result with the newest xor'd chunk - return result.concat(xorred); - } - }, Utils.strToByteArray("")); - } + // key = key XOR previous chunk + case "Rolling cumulative (self)": + // Xor this chunk + xorred = bitOp( + current, + runningKey, + xor, + nullPreserving, + scheme + ); + + // Update the running key for next part of loop + runningKey = bitOp( + runningKey, + current, + xor, + nullPreserving, + scheme + ); + + // Return the result with the newest xor'd chunk + return result.concat(xorred); + } + }, Utils.strToByteArray("")); // Start our reduction with an empty byte array + } return bitOp(input, key, xor, nullPreserving, scheme); } @@ -108,7 +152,6 @@ class XOR extends Operation { highlightReverse(pos, args) { return pos; } - } export default XOR; From b74f65b8ed0331f832612efa2d010b8d8568b973 Mon Sep 17 00:00:00 2001 From: Spencer Walden Date: Fri, 31 Mar 2023 00:11:45 -0700 Subject: [PATCH 4/4] Update the tests to work with the newer versions of the codebase when transcribing from old code --- tests/operations/tests/BitwiseOp.mjs | 117 +++++++++++++++------------ 1 file changed, 64 insertions(+), 53 deletions(-) diff --git a/tests/operations/tests/BitwiseOp.mjs b/tests/operations/tests/BitwiseOp.mjs index b8716aeb..af32c72a 100644 --- a/tests/operations/tests/BitwiseOp.mjs +++ b/tests/operations/tests/BitwiseOp.mjs @@ -10,81 +10,92 @@ import TestRegister from "../../lib/TestRegister.mjs"; TestRegister.addTests([ { name: "Bit shift left", - input: "01010101 10101010 11111111 00000000 11110000 00001111 00110011 11001100", - expectedOutput: "10101010 01010100 11111110 00000000 11100000 00011110 01100110 10011000", + input: "01010101 10101010 11111111 00000000 11110000 00001111 00110011 11001100", + expectedOutput: + "10101010 01010100 11111110 00000000 11100000 00011110 01100110 10011000", recipeConfig: [ - { "op": "From Binary", - "args": ["Space"] }, - { "op": "Bit shift left", - "args": [1] }, - { "op": "To Binary", - "args": ["Space"] } - ] + { op: "From Binary", args: ["Space"] }, + { op: "Bit shift left", args: [1] }, + { op: "To Binary", args: ["Space"] }, + ], }, { name: "Bit shift right: Logical shift", - input: "01010101 10101010 11111111 00000000 11110000 00001111 00110011 11001100", - expectedOutput: "00101010 01010101 01111111 00000000 01111000 00000111 00011001 01100110", + input: "01010101 10101010 11111111 00000000 11110000 00001111 00110011 11001100", + expectedOutput: + "00101010 01010101 01111111 00000000 01111000 00000111 00011001 01100110", recipeConfig: [ - { "op": "From Binary", - "args": ["Space"] }, - { "op": "Bit shift right", - "args": [1, "Logical shift"] }, - { "op": "To Binary", - "args": ["Space"] } - ] + { op: "From Binary", args: ["Space"] }, + { op: "Bit shift right", args: [1, "Logical shift"] }, + { op: "To Binary", args: ["Space"] }, + ], }, { name: "Bit shift right: Arithmetic shift", - input: "01010101 10101010 11111111 00000000 11110000 00001111 00110011 11001100", - expectedOutput: "00101010 11010101 11111111 00000000 11111000 00000111 00011001 11100110", + input: "01010101 10101010 11111111 00000000 11110000 00001111 00110011 11001100", + expectedOutput: + "00101010 11010101 11111111 00000000 11111000 00000111 00011001 11100110", recipeConfig: [ - { "op": "From Binary", - "args": ["Space"] }, - { "op": "Bit shift right", - "args": [1, "Arithmetic shift"] }, - { "op": "To Binary", - "args": ["Space"] } - ] + { op: "From Binary", args: ["Space"] }, + { op: "Bit shift right", args: [1, "Arithmetic shift"] }, + { op: "To Binary", args: ["Space"] }, + ], }, { name: "XOR: empty", input: "", expectedOutput: "", recipeConfig: [ - { "op": "From Binary", - "args": ["Space"] }, - { "op": "XOR", - "args": ["binary", "11111111", "Standard", false] }, - { "op": "To Binary", - "args": ["Space"] } - ] + { op: "From Binary", args: ["Space"] }, + { + op: "XOR", + args: [ + { option: "Binary", string: "11111111" }, + "Standard", + false, + ], + }, + { op: "To Binary", args: ["Space"] }, + ], }, { name: "XOR: 1111111, standard, no preserve nulls", - input: "01010101 10101010 11111111 00000000 11110000 00001111 00110011 11001100", - expectedOutput: "10101010 01010101 00000000 11111111 00001111 11110000 11001100 00110011", + input: "01010101 10101010 11111111 00000000 11110000 00001111 00110011 11001100", + expectedOutput: + "10101010 01010101 00000000 11111111 00001111 11110000 11001100 00110011", recipeConfig: [ - { "op": "From Binary", - "args": ["Space"] }, - { "op": "XOR", - "args": ["binary", "11111111", "Standard", false] }, - { "op": "To Binary", - "args": ["Space"] } - ] + { op: "From Binary", args: ["Space"] }, + { + op: "XOR", + args: [ + { option: "Binary", string: "11111111" }, + "Standard", + false, + ], + }, + { op: "To Binary", args: ["Space"] }, + ], }, { name: "XOR: 1111111, standard, preserve nulls", - input: "01010101 10101010 11111111 00000000 11110000 00001111 00110011 11001100", - // Should the ones be kept as ones? Seems like it's not a null that we're preserving... - expectedOutput: "10101010 01010101 11111111 00000000 00001111 11110000 11001100 00110011", + input: "01010101 10101010 11111111 00000000 11110000 00001111 00110011 11001100", + /* + * We preserve the all 1's case as well, as the `preserve nulls` option + * also preserves the bytes if they're equivalent to the key + */ + expectedOutput: + "10101010 01010101 11111111 00000000 00001111 11110000 11001100 00110011", recipeConfig: [ - { "op": "From Binary", - "args": ["Space"] }, - { "op": "XOR", - "args": ["binary", "11111111", "Standard", true] }, - { "op": "To Binary", - "args": ["Space"] } - ] + { op: "From Binary", args: ["Space"] }, + { + op: "XOR", + args: [ + { option: "Binary", string: "11111111" }, + "Standard", + true, + ], + }, + { op: "To Binary", args: ["Space"] }, + ], }, ]);