Skip to content

Commit

Permalink
docs: update draft URLs
Browse files Browse the repository at this point in the history
  • Loading branch information
TheEdoRan committed Apr 26, 2024
1 parent 5901e62 commit 4ece54e
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 15 deletions.
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,15 +119,15 @@ The library provides a few function aliases for convenience. You can use them wi

## Implementation details

This library follows the [draft-ietf-uuidrev-rfc4122bis-11](https://www.ietf.org/archive/id/draft-ietf-uuidrev-rfc4122bis-11.html#name-uuid-version-7) draft to generate UUIDv7s:
This library follows the [draft-ietf-uuidrev-rfc4122bis](https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis#name-uuid-version-7) draft to generate UUIDv7s:

- if the current timestamp is ahead of the last stored one, it generates new [rand_a] and [rand_b] parts;
- if the current timestamp is behind the last stored one, it waits for the next valid timestamp to return a UUIDv7 with newly generated random parts;
- if the current timestamp is the same as the last stored one:
- it uses `rand_b` and then `rand_a` as randomly seeded counters, in that order. `rand_b` is the primary counter, and `rand_a` is used as the secondary one, when `rand_b` overflows its 62 bits (rare case). When used as a counter, `rand_b` increments its previous random value by a random integer between 2^6 (64) and 2^16 - 1 (65535), and `rand_a` increments its previous random value by 1, while generating a new `rand_b` part.
- if both counters overflow their bit sizes, the generation function waits for the next millisecond to return a UUIDv7 with newly generated random parts.

This approach follows the [method 2](https://www.ietf.org/archive/id/draft-ietf-uuidrev-rfc4122bis-11.html#monotonicity_counters) of the "Monotonicity and Counters" section of the draft. It guarantees monotonicity and uniqueness per instance, and always keeps timestamp the same as `Date.now()` value.
This approach follows the [method 2](https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis#monotonicity_counters) of the "Monotonicity and Counters" section of the draft. It guarantees monotonicity and uniqueness per instance, and always keeps timestamp the same as `Date.now()` value.

## Field and Bit Layout

Expand All @@ -151,23 +151,23 @@ This is the UUIDv7 Field and Bit Layout, took from the draft linked above:

#### unix_ts_ms

48 bit big-endian unsigned number of Unix epoch timestamp in milliseconds as per [Section 6.1](https://www.ietf.org/archive/id/draft-ietf-uuidrev-rfc4122bis-11.html#timestamp_considerations). Occupies bits 0 through 47 (octets 0-5).
48 bit big-endian unsigned number of Unix epoch timestamp in milliseconds as per [Section 6.1](https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis#timestamp_considerations). Occupies bits 0 through 47 (octets 0-5).

#### ver

The 4 bit version field as defined by [Section 4.2](https://www.ietf.org/archive/id/draft-ietf-uuidrev-rfc4122bis-11.html#version_field), set to 0b0111 (7). Occupies bits 48 through 51 of octet 6.
The 4 bit version field as defined by [Section 4.2](https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis#version_field), set to 0b0111 (7). Occupies bits 48 through 51 of octet 6.

#### rand_a

12 bits pseudo-random data to provide uniqueness as per [Section 6.8](https://www.ietf.org/archive/id/draft-ietf-uuidrev-rfc4122bis-11.html#unguessability) and/or optional constructs to guarantee additional monotonicity as per [Section 6.2](https://www.ietf.org/archive/id/draft-ietf-uuidrev-rfc4122bis-11.html#monotonicity_counters). Occupies bits 52 through 63 (octets 6-7).
12 bits pseudo-random data to provide uniqueness as per [Section 6.9](https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis#unguessability) and/or optional constructs to guarantee additional monotonicity as per [Section 6.2](https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis#monotonicity_counters). Occupies bits 52 through 63 (octets 6-7).

#### var

The 2 bit variant field as defined by [Section 4.1](https://www.ietf.org/archive/id/draft-ietf-uuidrev-rfc4122bis-11.html#variant_field), set to 0b10. Occupies bits 64 and 65 of octet 8.
The 2 bit variant field as defined by [Section 4.1](https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis#variant_field), set to 0b10. Occupies bits 64 and 65 of octet 8.

#### rand_b

The final 62 bits of pseudo-random data to provide uniqueness as per [Section 6.8](https://www.ietf.org/archive/id/draft-ietf-uuidrev-rfc4122bis-11.html#unguessability) and/or an optional counter to guarantee additional monotonicity as per [Section 6.2](https://www.ietf.org/archive/id/draft-ietf-uuidrev-rfc4122bis-11.html#monotonicity_counters). Occupies bits 66 through 127 (octets 8-15).
The final 62 bits of pseudo-random data to provide uniqueness as per [Section 6.9](https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis#unguessability) and/or an optional counter to guarantee additional monotonicity as per [Section 6.2](https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis#monotonicity_counters). Occupies bits 66 through 127 (octets 8-15).

## Feedback

Expand Down
15 changes: 7 additions & 8 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,24 +53,23 @@ export class UUIDv7 {
let randA: number;
let randB: bigint;

// If current timestamp is after the last stored one, generate new [rand_a] and [rand_b] parts.
if (timestamp > this.#lastTimestamp) {
// If current timestamp is after the last stored one, generate new [rand_a] and [rand_b] parts.
randA = randomInt(0, 2 ** 12);
randB = BigInt("0x" + randomBytes(8).toString("hex")) % 2n ** 62n;

} else if (timestamp < this.#lastTimestamp) {
// If current timestamp is before the last stored one, it means that the system clock went
// backwards. So wait until it goes ahead before generating new UUIDs.
} else if (timestamp < this.#lastTimestamp) {
continue;

// Otherwise, current timestamp is the same as the previous one.
} else {
// Otherwise, current timestamp is the same as the previous one.

// Method 2 - Monotonic Random
// https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis#monotonicity_counters

// Keep the same [rand_a] part by default.
randA = this.#lastRandA;

// Method 2 - monotonic random for [rand_b]:
// https://www.ietf.org/archive/id/draft-ietf-uuidrev-rfc4122bis-11.html#monotonicity_counters

// Random increment value is between 2 ** 6 (64) and 2 ** 16 - 1 (65535).
randB = this.#lastRandB + BigInt(randomInt(2 ** 6, 2 ** 16));

Expand Down

0 comments on commit 4ece54e

Please sign in to comment.