0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

UUIDバージョン4を生成する

Last updated at Posted at 2020-12-02

UUIDにはいくつかの変種やバージョンがあるが、その中でもRFC 4122の中で定義されているバージョン4(以下v4)は単純に乱数で生成するという非常にシンプルな仕組みである。

そのようなシンプルさのため自前で書くのも容易である。
実際にJavascriptでも書いてみた。

UUID生成コードの実装例1
class UUID {

  static #uuidIte = ( function* () {

    const HEXOCTETS = Object.freeze( [ ...Array(256) ].map( ( e, i ) => i.toString( 16 ).padStart( 2, "0" ).toUpperCase() ) );
    const VARSION = 0x40;
    const VARIANT = 0x80;

    for (;;) {

      const bytes = crypto.getRandomValues( new Uint8Array( 16 ) );
      yield "" +
        HEXOCTETS[ bytes[ 0 ] ] +
        HEXOCTETS[ bytes[ 1 ] ] +
        HEXOCTETS[ bytes[ 2 ] ] +
        HEXOCTETS[ bytes[ 3 ] ] + "-" +
        HEXOCTETS[ bytes[ 4 ] ] +
        HEXOCTETS[ bytes[ 5 ] ] + "-" +
        HEXOCTETS[ bytes[ 6 ] & 0x0f | VARSION ] +
        HEXOCTETS[ bytes[ 7 ] ] + "-" +
        HEXOCTETS[ bytes[ 8 ] & 0x3f | VARIANT ] +
        HEXOCTETS[ bytes[ 9 ] ] + "-" +
        HEXOCTETS[ bytes[ 10 ] ] +
        HEXOCTETS[ bytes[ 11 ] ] +
        HEXOCTETS[ bytes[ 12 ] ] +
        HEXOCTETS[ bytes[ 13 ] ] +
        HEXOCTETS[ bytes[ 14 ] ] +
        HEXOCTETS[ bytes[ 15 ] ];

    }

  } )();

  static randomUUID() {
  
    return this.#uuidIte.next().value;
  
  }

}

consle.log( UUID.randomUUID() ); //xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

乱数はMath.randomでも取得できるが、暗号強度の面でcrypto.getRandomValuesを使用した方が安全である。
また、バイト列であるので表現も簡潔になる。

しかし、意外にもcrypto.getRandomValuesを使用している記事が下記しか見つからなかった。

JavaScriptの1行小ネタ集

恐らく暗号強度云々よりも「衝突の危険がないIDを簡便に生成したい」というケースがほとんどだと思われるので、Math.randomを使用したところで危険性が少ないのだろう。

下記にMath.randomを使用した実装例も記載する。

UUID生成コードの実装例2
class UUID {

  static #uuidIte = ( function* () {

    const HEXOCTETS = Object.freeze( [ ...Array(256) ].map( ( e, i ) => i.toString( 16 ).padStart( 2, "0" ).toUpperCase() ) );
    const VARSION = 0x40;
    const VARIANT = 0x80;

    for (;;) {

      const uint32 = new Uint32Array( 4 ).fill( Math.random() * 0x100000000 >>> 0 );
      yield "" +
        HEXOCTETS[ uint32[ 0 ] & 0xff ] +
        HEXOCTETS[ uint32[ 0 ] >>> 8 & 0xff ] +
        HEXOCTETS[ uint32[ 0 ] >>> 16 & 0xff ] +
        HEXOCTETS[ uint32[ 0 ] >>> 24 & 0xff ] + "-" +
        HEXOCTETS[ uint32[ 1 ] & 0xff ] +
        HEXOCTETS[ uint32[ 1 ] >>> 8 & 0xff ] + "-" +
        HEXOCTETS[ uint32[ 1 ] >>> 16 & 0x0f | VARSION ] +
        HEXOCTETS[ uint32[ 1 ] >>> 24 & 0xff ] + "-" +
        HEXOCTETS[ uint32[ 2 ] & 0x3f | VARIANT ] +
        HEXOCTETS[ uint32[ 2 ] >>> 8 & 0xff ] + "-" +
        HEXOCTETS[ uint32[ 2 ] >>> 16 & 0xff ] +
        HEXOCTETS[ uint32[ 2 ] >>> 24 & 0xff ] +
        HEXOCTETS[ uint32[ 3 ] & 0xff ] +
        HEXOCTETS[ uint32[ 3 ] >>> 8 & 0xff ] +
        HEXOCTETS[ uint32[ 3 ] >>> 16 & 0xff ] +
        HEXOCTETS[ uint32[ 3 ] >>> 24 & 0xff ];

    }

  } )();
  
  static randomUUID() {
  
    return this.#uuidIte.next().value;
  
  }

}

実行速度を比較するとcrypto.getRandomValuesよりMath.randomを用いた方が圧倒的に速い。

Screenshot 2020-12-07 at 11.09.19.png

Screenshot 2020-12-07 at 11.09.26.png

実行環境によっても変わってくるだろうが、仕様を考えるとどの環境も概ね同じ結果になるのではないだろうか。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?