Can you extract the seed from randomly generated perlin noise?

Can you get the seed from a randomly generated perlin noise graph?

please check the reference, noise can be initialised with a value that you choose.

https://p5js.org/reference/#/p5/noise

Thanks. That wasn’t my question.

Can you extract a seed from a perlin noise graph you did not initialize a seed for?

Thanks.

In theory, this might be possible. Perlin noise is based on a continuous/smooth interpolation of values between randomly generated vectors at discreet intervals, and in p5.js that field of vectors is generated using a Linear congruential generator. LCGs are not cryptographically secure (which is to say that it is not necessarily difficult to reverse engineer the seed, or key from a sequence of output values). Here is a blog post about finding a LCG seed that produces a specific output. I read over the source code for the noise function and it looks like this should be feasible assuming you can explicitly set the noiseDetail and get the output from noise(0, 0, 0):

// p5.js LCG constants
// m is basically chosen to be large (as it is the max period)
// and for its relationships to a and c
const m = 4294967296;
// a - 1 should be divisible by m's prime factors
const a = 1664525;
// c and m should be co-prime
const c = 1013904223;

// p5.js perlin constants
const PERLIN_YWRAP = 16;
const PERLIN_ZWRAP = 256;

function setup() {
  createCanvas(400, 400);
  noLoop();

  noiseSeed(2701);
  noiseDetail(1);
  print(`Actual noise(0, 0, 0): ${noise(0, 0, 0)}`);

  let lcgInt0 = (a * 2701 + c) % m;
  print(`Expected lcg0: ${lcgInt0}`);
  let lcgVal0 = lcgInt0 / m;

  let n1 = lcgVal0; // perlin[of & PERLIN_SIZE];
  /*
  // copy and pasted from noise.js
  // All of these terms go to 0 and so they have no impact on the output of noise(0,0,0)
  n1 += 0; // rxf * (perlin[(of + 1) & PERLIN_SIZE] - n1);
  let n2 = perlin[(of + PERLIN_YWRAP) & PERLIN_SIZE];
  n2 += 0; // rxf * (perlin[(of + PERLIN_YWRAP + 1) & PERLIN_SIZE] - n2);
  n1 += 0; // ryf * (n2 - n1);

  of += PERLIN_ZWRAP;
  n2 = perlin[of & PERLIN_SIZE];
  n2 += 0; // rxf * (perlin[(of + 1) & PERLIN_SIZE] - n2);
  n3 = perlin[(of + PERLIN_YWRAP) & PERLIN_SIZE];
  n3 += 0; // rxf * (perlin[(of + PERLIN_YWRAP + 1) & PERLIN_SIZE] - n3);
  n2 += 0; // ryf * (n3 - n2);

  n1 += 0; // scaled_cosine(zf) * (n2 - n1); */

  
  print(`noise(0, 0, 0) predicted: ${n1 * 0.5}`);
  print(`lcg0 predicted from noise output: ${noise(0, 0, 0) * 2 * m}`);
}

function draw() {}

Now, if you wanted to find the seed based on the output for some arbitrary set of non-integer points that would be much harder.

4 Likes

Wow! :grinning: Thank you for doing all of this.