New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

scru128

Package Overview
Dependencies
Maintainers
1
Versions
35
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

scru128 - npm Package Compare versions

Comparing version 0.1.0 to 0.2.0

28

dist/index.js

@@ -16,3 +16,3 @@ "use strict";

const MAX_COUNTER = 268435455;
/** Returns a random uint generator based on available cryptographic RNG. */
/** Returns a random bit generator based on available cryptographic RNG. */
const detectRng = () => {

@@ -51,3 +51,3 @@ if (typeof window !== "undefined" && window.crypto) {

/** Returns a `k`-bit (cryptographically strong) random unsigned integer. */
this.getRandomUint = detectRng();
this.getRandomBits = detectRng();
}

@@ -60,3 +60,3 @@ /** Generates a new SCRU128 ID object. */

this.tsLastGen = tsNow;
this.counter = this.getRandomUint(28);
this.counter = this.getRandomBits(28);
}

@@ -75,3 +75,3 @@ else if (++this.counter > MAX_COUNTER) {

this.tsLastGen = tsNow;
this.counter = this.getRandomUint(28);
this.counter = this.getRandomBits(28);
}

@@ -81,5 +81,5 @@ // update perSecRandom

this.tsLastSec = this.tsLastGen;
this.perSecRandom = this.getRandomUint(16);
this.perSecRandom = this.getRandomBits(24);
}
return new Identifier(this.tsLastGen - TIMESTAMP_EPOCH, this.counter, this.perSecRandom, this.getRandomUint(40));
return new Identifier(this.tsLastGen - TIMESTAMP_EPOCH, this.counter, this.perSecRandom, this.getRandomBits(32));
}

@@ -92,4 +92,4 @@ }

* @param counter - 28-bit counter.
* @param perSecRandom - 16-bit per-second randomness.
* @param perGenRandom - 40-bit per-generation randomness.
* @param perSecRandom - 24-bit per-second randomness.
* @param perGenRandom - 32-bit per-generation randomness.
*/

@@ -111,4 +111,4 @@ constructor(timestamp, counter, perSecRandom, perGenRandom) {

this.counter > MAX_COUNTER ||
this.perSecRandom > 0xffff ||
this.perGenRandom > 1099511627775) {
this.perSecRandom > 16777215 ||
this.perGenRandom > 4294967295) {
throw new RangeError("invalid field value");

@@ -120,6 +120,7 @@ }

const h48 = this.timestamp * 0x10 + (this.counter >> 24);
const m40 = (this.counter & 16777215) * 65536 + this.perSecRandom;
const m40 = (this.counter & 16777215) * 65536 + (this.perSecRandom >> 8);
const l40 = (this.perSecRandom & 0xff) * 4294967296 + this.perGenRandom;
return (("000000000" + h48.toString(32)).slice(-10) +
("0000000" + m40.toString(32)).slice(-8) +
("0000000" + this.perGenRandom.toString(32)).slice(-8)).toUpperCase();
("0000000" + l40.toString(32)).slice(-8)).toUpperCase();
}

@@ -134,3 +135,4 @@ /** Parses textual representation to create an object. */

const m40 = parseInt(m[2], 32);
return new Identifier(Math.trunc(h48 / 0x10), (h48 % 0x10 << 24) | Math.trunc(m40 / 65536), m40 % 65536, parseInt(m[3], 32));
const l40 = parseInt(m[3], 32);
return new Identifier(Math.trunc(h48 / 0x10), (h48 % 0x10 << 24) | Math.trunc(m40 / 65536), (m40 % 65536 << 8) | Math.trunc(l40 / 4294967296), l40 % 4294967296);
}

@@ -137,0 +139,0 @@ }

{
"name": "scru128",
"version": "0.1.0",
"version": "0.2.0",
"description": "SCRU128: Sortable, Clock and Random number-based Unique identifier",

@@ -5,0 +5,0 @@ "main": "./dist/index.js",

@@ -17,4 +17,4 @@ # SCRU128: Sortable, Clock and Random number-based Unique identifier

console.log(scru128()); // e.g. "00PFDQ1L5D1SM1S3KUUCL9ABV2"
console.log(scru128()); // e.g. "00PFDQ1L5D1SM1U3KUE2JOB6LC"
console.log(scru128()); // e.g. "00PGHAJ3Q9VAJ7IU6PQBHBUAK4"
console.log(scru128()); // e.g. "00PGHAJ3Q9VAJ7KU6PQ92NVBTV"
```

@@ -26,2 +26,68 @@

## Design
A SCRU128 ID is a 128-bit unsigned integer consisting of four terms:
```
timestamp * 2^84 + counter * 2^56 + per_sec_random * 2^32 + per_gen_random
```
Where:
- `timestamp` is a 44-bit unix time in milliseconds biased by 50 years (i.e.
milliseconds elapsed since 2020-01-01 00:00:00+00:00, ignoring leap seconds).
- `counter` is a 28-bit counter incremented by one for each ID generated within
the same `timestamp` and reset to a random number every millisecond.
- `per_sec_random` is a 24-bit random number refreshed only once per second.
- `per_gen_random` is a 32-bit random number renewed per generation of a new ID.
This is essentially equivalent to allocating four unsigned integer fields to a
128-bit space as follows in a big-endian system, and thus it is easier to be
implemented with bitwise operators than arithmetic operators in many languages.
| Bit numbers | Field name | Length | Data type |
| ------------ | -------------- | ------- | ---------------- |
| Msb 0 - 43 | timestamp | 44 bits | Unsigned integer |
| Msb 44 - 71 | counter | 28 bits | Unsigned integer |
| Msb 72 - 95 | per_sec_random | 24 bits | Unsigned integer |
| Msb 96 - 127 | per_gen_random | 32 bits | Unsigned integer |
### Layered randomness
SCRU128 utilizes monotonic `counter` to guarantee the uniqueness of IDs with the
same `timestamp`; however, this mechanism does not ensure the uniqueness of IDs
generated by multiple generators that do not share a `counter` state. SCRU128
relies on random numbers to avoid such collisions.
For a given length of random bits, the greater the number of random numbers
generated, the higher the probability of collision. Therefore, SCRU128 gives
some random bits a longer life to reduce the number of random number generation
per a unit of time. As a result, even if each of multiple generators generates a
million IDs at the same millisecond, no collision will occur as long as the
random numbers generated only once per second (`per_sec_random`) differ.
That being said, the `per_sec_random` field is refreshed every second to prevent
potential attackers from using this field as a fingerprint to identify a
generator. Also, the 32-bit `per_gen_random` field is reset to a new random
number whenever an ID is generated to make sure the adjacent IDs generated
within the same `timestamp` are not predictable.
## Textual representation
A SCRU128 ID is encoded to a string as a 128-bit unsigned integer denoted in the
radix of 32 using the digits of `[0-9A-V]`, with leading zeros added to form a
26-digit canonical representation. Converters for this simple base 32 notation
are widely available in many languages; even if not, it is easily implemented
with bitwise operations by translating each 5-bit group, from the least
significant group to the most, into one digit of `[0-9A-V]`, from the least
significant digit to the most. Since the three most significant bits are mapped
to one of `[0-7]`, any numeral greater than `7VVVVVVVVVVVVVVVVVVVVVVVVV` is not
a valid SCRU128 ID.
Note that this is different from the encodings commonly referred to as _base32_
or _base32hex_ (e.g. [RFC 4648]), which read and translate 5-bit groups from the
most significant one to the least.
[rfc 4648]: https://www.ietf.org/rfc/rfc4648.txt
## License

@@ -41,1 +107,7 @@

specific language governing permissions and limitations under the License.
## See also
- [npm package](https://www.npmjs.com/package/scru128)
- [API Documentation](https://scru128.github.io/javascript/docs/)
- [Run tests on your browser](https://scru128.github.io/javascript/test/)
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc