Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: tinybitsofcode/ulid
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: master
Choose a base ref
...
head repository: ulid/javascript
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref
Checking mergeability… Don’t worry, you can still create the pull request.
  • 10 commits
  • 4 files changed
  • 4 contributors

Commits on Apr 2, 2025

  1. Update utils.ts

    Hi @j0pgrm, re ulid#81
    
    Your `if` statement is there to cover the possbility that your PRNG will generate the number 1. 
    In general, PRNGs produce values from 0 to _less than_ 1, i.e. from the range 0 (inclusive) to 1 (exclusive). This is because when they generate an N-bit binary fraction, the highest value (all `1`s) will be just a tiny bit smaller than 1.
    
    Your `Math.floor` correctly rounds downward, so that `rand` will be in the range 0 (inclusive) to ENCODING_LEN *- 1* (inclusive). 
    So the `if` will never be triggered.
    
    If, for some reason, you in future switch to a prng that somehow can generate a 1, for example because it has an idiosyncratic desire to cover a range of 0 (_exclusive_) to 1 (_inclusive_), then:
    
    * the chance of this is extremely small (1 in 2**N, not 1 in 2**8)
    * the PRNG will have lost the ability to generate 0
    * your random character generator would have a micrscopically smaller chance of generating the first encoding character, and have a microscopic chance of trying to pick the non-existent character at #ENCODING_LEN.
    
    A neat solution for you is to simply wrap round that exactly-1 PRNG value back to 0, most conveniently  A simple way to achieve this is to modulo the `rand` by ENCODING_LEN.
    
    
    
    Thank you for an excellent library.
    darrelfrancis authored Apr 2, 2025
    Configuration menu
    Copy the full SHA
    d44c3d9 View commit details
    Browse the repository at this point in the history

Commits on Jun 8, 2025

  1. Fix typo

    perry-mitchell authored Jun 8, 2025
    Configuration menu
    Copy the full SHA
    5c14ac9 View commit details
    Browse the repository at this point in the history
  2. Merge pull request ulid#120 from darrelfrancis/master

    Resolve ulid#81 to deal with a potential future scenario of PRNG generating `1`
    perry-mitchell authored Jun 8, 2025
    Configuration menu
    Copy the full SHA
    63784e2 View commit details
    Browse the repository at this point in the history
  3. Fix formatting

    perry-mitchell committed Jun 8, 2025
    Configuration menu
    Copy the full SHA
    b17312d View commit details
    Browse the repository at this point in the history
  4. Update dependencies

    perry-mitchell committed Jun 8, 2025
    Configuration menu
    Copy the full SHA
    fe3953d View commit details
    Browse the repository at this point in the history
  5. 3.0.1

    perry-mitchell committed Jun 8, 2025
    Configuration menu
    Copy the full SHA
    ab232d7 View commit details
    Browse the repository at this point in the history
  6. Add prepublish script

    perry-mitchell committed Jun 8, 2025
    Configuration menu
    Copy the full SHA
    09c28ab View commit details
    Browse the repository at this point in the history

Commits on Nov 21, 2025

  1. [LOW][Security] Fix biased random number generation

    The random number generation logic results in a bias leading to some
    characters being more frequent than others, due to incorrect processing
    of random bytes.
    
    This can result in more easily guessable IDs, enabling some enumeration
    of resources.
    
    The crux of the vulnerability is that the RNG (as defined in
    `detectPRNG`), generates a float by generating a random byte and
    dividing by 255 (0xff). So, if the random byte is 0x00, it returns 0. If
    the byte is 0x01, it returns ~0.0039, and so on, until if the random
    byte is 0xff, it returns 1.
    
    Thus, the float returned could be [0, 1], rather than [0, 1) (as some
    comments expect).
    
    For reference, The whole list of possible outputs of the rng function
    returned by `detectPRNG` can be obtained by the following snippet:
    
    ```
    const rngValues = Array.from(new Array(256), (_, idx) => (idx)/0xff);
    > [0, 0.0039, …, 1]
    ```
    
    As a result, the `randomChar` function (as used by `encodeRandom`) will
    generate a bias, as it wraps around if the value is 1.
    
    All possible randomPosition values are thus (where 32 is from
    `ENCODING_LEN`):
    
    ```
    const randomPositions = rngValues.map((v) => Math.floor(v * 32) % 32)
    > [0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1, …, 31, 0]
    ```
    
    If you take a look at the values of this array, you’ll notice that the
    distribution isn’t equal:
    
    ```
    randomPositions.reduce((acc, v) => {
      if (!acc.has(v)) { acc.set(v, 0); }
      acc.set(v, acc.get(v)+1);
      return acc;
    }, new Map());
    > { 0 => 9, 1 => 8, 2 => 8, …, 30 => 8, 31 => 7 }
    ```
    
    Therefore, it’s more likely to generate a ‘0’ character, than a ‘Z’
    character, and thus will lead to bias, thus a lower entropy than
    expected.
    pnappa committed Nov 21, 2025
    Configuration menu
    Copy the full SHA
    f100a81 View commit details
    Browse the repository at this point in the history

Commits on Nov 22, 2025

  1. Configuration menu
    Copy the full SHA
    263c23a View commit details
    Browse the repository at this point in the history

Commits on Nov 30, 2025

  1. Release 3.0.2

    perry-mitchell committed Nov 30, 2025
    Configuration menu
    Copy the full SHA
    11c2067 View commit details
    Browse the repository at this point in the history
Loading