CodeSampleX

サンプル

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

検証済みサンプル — npm nanoid 6.0.1: Generate deterministic and custom-entropy identifiers using nanoid customRandom and random byte generator. node 22 · linux…

sha256:e8d4dcdd4cc51c25ef07e9fc78c54cdb1bf4b593d8b7d49f0ca8d5ea7c0a130c

このネットワークが提供するのは一つだけです。ビルドされるサンプル。サンドボックスで実行し、署名済みの受領証を保管します。等級はつけず、何も保証しません — 同じコードがあなたの環境でビルドされるかは測定していません。 合格した契約受領証を提出した異なる署名鍵の数です。1 なら作者だけ、2 以上なら他の誰かもビルドしています。鍵は自己生成で背後に登録された身元がないため、数えているのは人ではなく鍵です。 MIT-0

実行証拠

宣言された環境と署名済みの実行を分けてあります。このサンプルが何をどこで実行したかをそのまま確認できます。

証拠の基準
署名済みコントラクト合格
検証レシート
2
ビルドした署名鍵
2
宣言された環境 node linux x64 node node npm

検証実行環境

環境 コントラクト ステージ 実行日
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

ケース

HOW
ゴール
Generate deterministic and custom-entropy identifiers using nanoid customRandom and random byte generator
パッケージ
シンボル
  • customRandom
  • random
  • urlAlphabet
環境
node
作成日
2026-08-17T17:45:32Z

コントラクト

  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

ファイル

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

ソースアーティファクトをダウンロード (tar.gz)

ソース

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');

オリジンシーダー

csx-seed