Merge pull request #1 from Scarjit/master

zstd for GCHQ
This commit is contained in:
Ferdinand Linnenberg 2024-10-07 13:03:29 +02:00 committed by GitHub
commit 2d0654fd44
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 115 additions and 1 deletions

6
package-lock.json generated
View file

@ -44,6 +44,7 @@
"fernet": "^0.4.0",
"file-saver": "^2.0.5",
"flat": "^6.0.1",
"fzstd": "^0.1.1",
"geodesy": "1.1.3",
"highlight.js": "^11.9.0",
"ieee754": "^1.2.1",
@ -7916,6 +7917,11 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/fzstd": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/fzstd/-/fzstd-0.1.1.tgz",
"integrity": "sha512-dkuVSOKKwh3eas5VkJy1AW1vFpet8TA/fGmVA5krThl8YcOVE/8ZIoEA1+U1vEn5ckxxhLirSdY837azmbaNHA=="
},
"node_modules/gamma": {
"version": "1.0.0",
"license": "MIT"

View file

@ -128,6 +128,7 @@
"fernet": "^0.4.0",
"file-saver": "^2.0.5",
"flat": "^6.0.1",
"fzstd": "^0.1.1",
"geodesy": "1.1.3",
"highlight.js": "^11.9.0",
"ieee754": "^1.2.1",

View file

@ -381,7 +381,8 @@
"LZMA Compress",
"LZ4 Decompress",
"LZ4 Compress",
"LZNT1 Decompress"
"LZNT1 Decompress",
"ZStandard Decompress"
]
},
{

View file

@ -0,0 +1,91 @@
/**
* @author Scarjit [ferdinand@linnenberg.dev]
* @copyright Crown Copyright 2024
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import {isWorkerEnvironment} from "../Utils.mjs";
import * as fzstd from "fzstd";
/**
* ZStandard Decompress operation
*/
class ZStandardDecompress extends Operation {
/**
* ZStandardDecompress constructor
*/
constructor() {
super();
this.name = "ZStandard Decompress";
this.module = "Compress";
this.description = "ZStandard is a compression algorithm focused on fast decompression.";
this.infoURL = "https://wikipedia.org/wiki/Zstd"; // Usually a Wikipedia link. Remember to remove localisation (i.e. https://wikipedia.org/etc rather than https://en.wikipedia.org/etc)
this.inputType = "ArrayBuffer";
this.outputType = "ArrayBuffer";
this.args = [
{
"name": "Chunk Size (bytes)",
"type": "number",
"value": 65536
}
];
}
/**
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {ArrayBuffer}
*/
run(input, args) {
const chunkSize = args[0];
if (input.byteLength <= 0) {
throw new OperationError("Please provide an input.");
}
// Validate input starts with ZStandard magic number
const ZSTD_MAGIC_NUMBER = [0x28, 0xb5, 0x2f, 0xfd];
const magicNumber = new Uint8Array(input, 0, 4);
if (!ZSTD_MAGIC_NUMBER.every((val, index) => val === magicNumber[index])) {
throw new OperationError("Invalid ZStandard input: does not start with magic number.");
}
if (isWorkerEnvironment()) self.sendStatusMessage("Loading ZStandard...");
return new Promise((resolve, reject) => {
const compressed = new Uint8Array(input);
try {
const outChunks = []; // Array of Uint8Array chunks
const stream = new fzstd.Decompress((chunk, isLast) => {
// Add to the list of output chunks
outChunks.push(chunk);
if (isLast) {
// Combine all chunks into a single Uint8Array
const totalLength = outChunks.reduce((sum, chunk) => sum + chunk.length, 0);
const result = new Uint8Array(totalLength);
let offset = 0;
for (const chunk of outChunks) {
result.set(chunk, offset);
offset += chunk.length;
}
resolve(result.buffer);
}
});
const chunks = Math.ceil(compressed.length / chunkSize);
for (let i = 0; i < compressed.length; i += chunkSize) {
if (isWorkerEnvironment()) self.sendStatusMessage(`Decompressing chunk ${i / chunkSize + 1} of ${chunks}...`);
const chunk = compressed.subarray(i, i + chunkSize);
stream.push(chunk);
}
stream.push(new Uint8Array(0), true); // Signal end of stream
} catch (error) {
reject(new OperationError("Decompression failed: " + error.message));
}
});
}
}
export default ZStandardDecompress;

View file

@ -105,4 +105,19 @@ TestRegister.addTests([
}
],
},
{
name: "ZStandard Decompress",
input: "KLUv/QRYuQAAVGhlIGNhdCBzYXQgb24gdGhlIG1hdC4tJ481",
expectedOutput: "The cat sat on the mat.",
recipeConfig: [
{
"op": "From Base64",
"args": []
},
{
"op": "ZStandard Decompress",
"args": [65536]
}
],
}
]);