seccon22-noiseccon

Seccon 2022 Qualifier Challenge 'Noiseccon'
git clone https://git.sinitax.com/sinitax/seccon22-noiseccon
Log | Files | Refs | sfeed.txt

index.js (2573B)


      1const { noise } = require("./perlin.js");
      2const sharp = require("sharp");
      3const crypto = require("node:crypto");
      4const readline = require("node:readline").promises;
      5
      6const FLAG = process.env.FLAG ?? console.log("No flag") ?? process.exit(1);
      7const WIDTH = 256;
      8const HEIGHT = 256;
      9
     10console.log(
     11  `   _   _       _             ____                           _
     12  | \\ | | ___ (_)___  ___   / ___| ___ _ __   ___ _ __ __ _| |_ ___  _ __
     13  |  \\| |/ _ \\| / __|/ _ \\ | |  _ / _ \\ '_ \\ / _ \\ '__/ _\` | __/ _ \\| '__|
     14  | |\\  | (_) | \\__ \\  __/ | |_| |  __/ | | |  __/ | | (_| | || (_) | |
     15  |_| \\_|\\___/|_|___/\\___|  \\____|\\___|_| |_|\\___|_|  \\__,_|\\__\\___/|_|
     16  `
     17);
     18
     19console.log(`Flag length: ${FLAG.length}`);
     20console.log(`Image width: ${WIDTH}`);
     21console.log(`Image height: ${HEIGHT}`);
     22
     23const paddedFlag = [
     24  ...crypto.randomBytes(8), // random prefix
     25  ...Buffer.from(FLAG),
     26  ...crypto.randomBytes(8), // random suffix
     27];
     28
     29// bytes_to_long
     30let flagInt = 0n;
     31for (const b of Buffer.from(paddedFlag)) {
     32  flagInt = (flagInt << 8n) | BigInt(b);
     33}
     34
     35const generateNoise = async (scaleX, scaleY) => {
     36  const div = (x, y) => {
     37    const p = 4;
     38    return Number(BigInt.asUintN(32 + p, (x * BigInt(1 << p)) / y)) / (1 << p);
     39  };
     40
     41  const offsetX = div(flagInt, scaleX);
     42  const offsetY = div(flagInt, scaleY);
     43
     44  noise.seed(crypto.randomInt(65536));
     45  const colors = [];
     46  for (let y = 0; y < HEIGHT; y++) {
     47    for (let x = 0; x < WIDTH; x++) {
     48      let v = noise.perlin2(offsetX + x * 0.05, offsetY + y * 0.05);
     49      v = (v + 1.0) * 0.5; // [-1, 1] -> [0, 1]
     50      colors.push((v * 256) | 0);
     51    }
     52  }
     53
     54  const image = await sharp(Uint8Array.from(colors), {
     55    raw: {
     56      width: WIDTH,
     57      height: HEIGHT,
     58      channels: 1,
     59    },
     60  })
     61    .webp({ lossless: true })
     62    .toBuffer();
     63  return image;
     64};
     65
     66const main = async () => {
     67  const rl = readline.createInterface({
     68    input: process.stdin,
     69    output: process.stdout,
     70    terminal: false,
     71  });
     72
     73  const toBigInt = (value) => {
     74    if (value.length > 100) {
     75      console.log(`Invalid value: ${value}`);
     76      process.exit(1);
     77    }
     78    const result = BigInt(value);
     79    if (result <= 0n) {
     80      console.log(`Invalid value: ${value}`);
     81      process.exit(1);
     82    }
     83    return result;
     84  };
     85
     86  const query = async () => {
     87    const scaleX = toBigInt(await rl.question("Scale x: "));
     88    const scaleY = toBigInt(await rl.question("Scale y: "));
     89
     90    const image = await generateNoise(scaleX, scaleY);
     91    console.log(image.toString("base64"));
     92  };
     93  await query();
     94
     95  rl.close();
     96};
     97
     98main();