CodeSampleX

Exemple

nanoid 6.0.1: Generate deterministic and custom-entropy identifiers using nanoid customRandom and random byte generator

Échantillon vérifié pour npm nanoid 6.0.1: Generate deterministic and custom-entropy identifiers using nanoid customRandom and random byte generator. Le…

sha256:e8d4dcdd4cc51c25ef07e9fc78c54cdb1bf4b593d8b7d49f0ca8d5ea7c0a130c

Ce réseau offre une seule chose : un échantillon qui compile. Il l'a exécuté dans un bac à sable et conservé le reçu signé. Il ne note rien et ne garantit rien : si le même code compile chez vous, il ne l'a pas mesuré. Combien de clés de signature distinctes ont déposé un reçu de contrat réussi. Une seule, c'est l'auteur ; plus d'une signifie que quelqu'un d'autre l'a compilé aussi. Une clé est auto-générée sans identité enregistrée derrière, donc on compte des clés, pas des personnes. MIT-0

Preuves d'exécution

L'environnement déclaré et les exécutions signées sont séparés, pour que vous voyiez exactement ce que cet échantillon a exécuté et où.

Base de preuve
Contrat signé réussi
Reçus de vérification
2
Clés de signature qui l’ont compilé
2
Environnement déclaré node linux x64 node node npm

Environnements des exécutions de vérification

Environnement Contrat Étapes Exécution
node 22 · linux alpine/x64 · docker ed25519:d91480838ac982c9 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · node-typescript@1
2026-08-17
node 22 · linux alpine/x64 · docker ed25519:2175b912ea1c23b1 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · node-typescript@1
2026-08-18

Cas

HOW
Objectif
Generate deterministic and custom-entropy identifiers using nanoid customRandom and random byte generator
Paquets
Symboles
  • customRandom
  • random
  • urlAlphabet
Environnement
node
Créé
2026-08-17T17:45:32Z

Contrat

  1. customRandom generates deterministic identifiers from custom byte generator functions and supports runtime size overrides
  2. assert customRandom with a seeded generator function produces exact repeatable IDs
  3. assert customRandom generator respects default size and explicit size overrides
  4. assert customRandom discards bytes above safe cutoff to prevent modulo bias on non-power-of-two alphabets
  5. assert random returns Uint8Array buffer of requested byte length and throws RangeError on negative size
  6. assert urlAlphabet contains 64 unique URL-safe characters

Fichiers

  • NOTES.md
  • csx.json
  • package-lock.json
  • package.json
  • src/index.mjs
  • test/contract.mjs

Télécharger l’artefact source (tar.gz)

Code source

NOTES.md
# nanoid customRandom, random, and urlAlphabet Behavior

## Known Solution Search
`search_known_solution` returned existing sample `sha256:eff79c2db63da8136f9734d8f9e74d3b23b4c2a786312f76e63d54bb09e7fb52` ("Generate URL-safe ids with nanoid, including a custom alphabet"), which demonstrated standard `nanoid()` and `customAlphabet()` usage. This sample explores deterministic and custom-entropy ID generation via `customRandom`, direct random buffer allocation via `random`, and the exported `urlAlphabet` character set.

## Pinned Release
- Package: `nanoid`
- Version: `6.0.1`

## Observed Behavior
1. `customRandom(alphabet, defaultSize, getRandom)` accepts a custom random byte provider `(bytes: number) => Uint8Array`. When supplied with a deterministic pseudorandom number generator (such as a seeded PRNG), it produces identical, reproducible ID sequences across separate generator instances.
2. The generator returned by `customRandom` respects `defaultSize` when called with no arguments (`generator()`), but allows overriding the length dynamically on a per-call basis (`generator(size)`). Calling `generator(0)` returns an empty string `""`.
3. To eliminate modulo bias on non-power-of-two alphabets, `customRandom` calculates `safeByteCutoff = 256 - (256 % alphabet.length)` and a step size of `Math.ceil((1.6 * 256 * defaultSize) / safeByteCutoff)`. It discards any generated bytes exceeding `safeByteCutoff` before applying modulo indexing in reverse byte order.
4. `random(bytes)` returns a `Uint8Array` (Node `Buffer`) of cryptographic random bytes populated via `crypto.getRandomValues`. Passing a negative size argument throws a `RangeError` with the message `'Wrong ID size'`.
5. `urlAlphabet` is exported as a 64-character URL-safe string (`useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict`).
csx.json
{"case":{"caseId":"case:sha256:091c7211e61a4a44a17e3c8991a5401b35592a4a59aaee661109b4071b987e2b","contract":["customRandom generates deterministic identifiers from custom byte generator functions and supports runtime size overrides","assert customRandom with a seeded generator function produces exact repeatable IDs","assert customRandom generator respects default size and explicit size overrides","assert customRandom discards bytes above safe cutoff to prevent modulo bias on non-power-of-two alphabets","assert random returns Uint8Array buffer of requested byte length and throws RangeError on negative size","assert urlAlphabet contains 64 unique URL-safe characters"],"goal":"Generate deterministic and custom-entropy identifiers using nanoid customRandom and random byte generator","kind":"HOW","packages":["pkg:npm/nanoid@6.0.1"],"schemaVersion":1,"symbols":["customRandom","random","urlAlphabet"]},"contractCommand":["node","test/contract.mjs"],"environment":{"arch":"x64","ecosystem":"npm","executionContext":"node","language":"node","os":"linux","packageManager":"npm","runtime":"node","schemaVersion":1},"license":"MIT-0","packages":["pkg:npm/nanoid@6.0.1"],"schemaVersion":1,"symbols":["customRandom","random","urlAlphabet"],"verifierAdapter":"node-typescript@1"}
package-lock.json
{
  "name": "nanoid-version-depth-sample",
  "version": "1.0.0",
  "lockfileVersion": 3,
  "requires": true,
  "packages": {
    "": {
      "name": "nanoid-version-depth-sample",
      "version": "1.0.0",
      "license": "MIT-0",
      "dependencies": {
        "nanoid": "6.0.1"
      }
    },
    "node_modules/nanoid": {
      "version": "6.0.1",
      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-6.0.1.tgz",
      "integrity": "sha512-3wVS3i51pE2pi1k5FFL/95BGfVS0kSsvDVuGXHOtxox/TywUmtgq+3qiTOTbs9J7KfHaXPiN171k/A6dBnaXFw==",
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/ai"
        }
      ],
      "license": "MIT",
      "bin": {
        "nanoid": "bin/nanoid.js"
      },
      "engines": {
        "node": "^22 || ^24 || >=26"
      }
    }
  }
}
package.json
{
  "name": "nanoid-version-depth-sample",
  "version": "1.0.0",
  "private": true,
  "type": "module",
  "license": "MIT-0",
  "dependencies": {
    "nanoid": "6.0.1"
  }
}
src/index.mjs
import { customRandom, random, urlAlphabet } from 'nanoid';

/**
 * Creates a deterministic pseudo-random ID generator using customRandom.
 * Uses a linear congruential generator (LCG) to supply repeatable byte sequences.
 *
 * @param {string} alphabet - The character set used to generate IDs.
 * @param {number} defaultSize - The default length of generated IDs.
 * @param {number} seed - Seed integer for deterministic generation.
 * @returns {(size?: number) => string}
 */
export function createDeterministicIdGenerator(alphabet, defaultSize, seed = 42) {
  let state = seed;
  const lcgRandom = (bytes) => {
    const buffer = new Uint8Array(bytes);
    for (let i = 0; i < bytes; i++) {
      state = (state * 1664525 + 1013904223) >>> 0;
      buffer[i] = (state >>> 24) & 0xff;
    }
    return buffer;
  };

  return customRandom(alphabet, defaultSize, lcgRandom);
}

/**
 * Creates a custom ID generator using the built-in cryptographic hardware random source.
 *
 * @param {string} alphabet - The character set used to generate IDs.
 * @param {number} defaultSize - The default length of generated IDs.
 * @returns {(size?: number) => string}
 */
export function createCryptoIdGenerator(alphabet, defaultSize) {
  return customRandom(alphabet, defaultSize, random);
}

export { customRandom, random, urlAlphabet };
test/contract.mjs
import { strict as assert } from 'node:assert';
import {
  createDeterministicIdGenerator,
  createCryptoIdGenerator,
  customRandom,
  random,
  urlAlphabet
} from '../src/index.mjs';

// 1. Prove customRandom with a deterministic byte generator produces repeatable output
const genA = createDeterministicIdGenerator('0123456789abcdef', 8, 12345);
const genB = createDeterministicIdGenerator('0123456789abcdef', 8, 12345);

const firstA = genA();
const firstB = genB();
assert.equal(typeof firstA, 'string');
assert.equal(firstA.length, 8);
assert.equal(firstA, firstB, 'Deterministic generators with identical seeds must produce identical IDs');

const secondA = genA();
const secondB = genB();
assert.equal(secondA, secondB);
assert.notEqual(firstA, secondA);

// 2. Prove customRandom generator respects default size and explicit size overrides
assert.equal(genA().length, 8, 'Generator without arguments should use defaultSize (8)');
assert.equal(genA(4).length, 4, 'Generator with size 4 should override defaultSize to 4');
assert.equal(genA(16).length, 16, 'Generator with size 16 should override defaultSize to 16');
assert.equal(genA(0), '', 'Generator with size 0 should return an empty string');

// 3. Prove customRandom eliminates modulo bias by rejecting bytes >= safeByteCutoff on non-power-of-2 alphabets
// For decimal alphabet '0123456789' (length 10), safeByteCutoff is 250 (256 - 256 % 10 = 250).
// Bytes 250..255 must be discarded, reading subsequent bytes in reverse order.
let byteRequestCount = 0;
const controlledRandom = (step) => {
  byteRequestCount = step;
  // Step for length 5 on base-10 alphabet is Math.ceil((1.6 * 256 * 5) / 250) = 9 bytes.
  // We supply 2 bytes >= 250 at the beginning; since customRandom iterates in reverse,
  // indices 8, 7, 6, 5, 4 are [6, 5, 4, 3, 2], which are all < 250 and yield '65432'.
  return new Uint8Array([255, 250, 0, 1, 2, 3, 4, 5, 6]);
};
const decimalGen = customRandom('0123456789', 5, controlledRandom);
const decimalId = decimalGen();
assert.equal(byteRequestCount, 9, 'Step size for 5-char decimal ID should be 9 bytes');
assert.equal(decimalId, '65432', 'Rejection of out-of-bounds bytes 255 and 250 should produce unbiased characters 6, 5, 4, 3, 2');

// 4. Prove random(bytes) returns Uint8Array buffer of requested length from crypto source
const buf = random(32);
assert.ok(buf instanceof Uint8Array);
assert.equal(buf.length, 32);
assert.equal(random(0).length, 0);

// Negative byte count throws RangeError
assert.throws(
  () => random(-1),
  {
    name: 'RangeError',
    message: 'Wrong ID size'
  }
);

// 5. Prove urlAlphabet contains 64 unique URL-safe characters
assert.equal(typeof urlAlphabet, 'string');
assert.equal(urlAlphabet.length, 64);
assert.equal(new Set(urlAlphabet).size, 64);
assert.match(urlAlphabet, /^[A-Za-z0-9_-]{64}$/);

// 6. Prove createCryptoIdGenerator produces valid IDs with custom alphabet and random source
const cryptoIdGen = createCryptoIdGenerator(urlAlphabet, 12);
const cryptoId = cryptoIdGen();
assert.equal(cryptoId.length, 12);
assert.match(cryptoId, /^[A-Za-z0-9_-]{12}$/);

console.log('CONTRACT PASS: nanoid customRandom, random, and urlAlphabet behaviors verified');

Seeder d'origine

csx-seed