/zuuid

UUID application for Erlang.

Primary LanguageErlangMIT LicenseMIT

zuuid

An example Erlang project that implements RFC 4122 UUID generators and functions.

So what's a UUID?

A UUID is a 128-bit value generated in a way that can generally be assumed unique across all systems in the world. This solves a number of otherwise tricky "how should I identify item X?" problems in a uniform way that is respected across a wide variety of systems.

Why would I use this?

If you need to generate unique keys in an arbitrary number of systems and possibly merge the values later without worrying about merge conflicts on key values then UUIDs are for you. This is a surprisingly common problem in distributed computing, especially document systems, persistent messaging and database management.

You don't usually need to know anything about UUIDs other than that they are safe to use as unique values to use them in your programs and databases. Most languages, frameworks, runtimes, operating systems and databases either have UUID support built-in or have robust support available through an external library (like this one).

What's a UUID made of?

There are several UUID generation algorithms, four of which are documented in RFC 4122. The basic principle to all of them is that a UUID should either be:

  • Based on a combination of time and system ID values
  • Strongly randomized

Version 1 values are based on 100 nanosecond time intervals, a "clock sequence" and the generating system's MAC address (or a suitable 48-bit substitute).

Version 2 values are generally similar to version 1, but also include some user and group ID values. (Use of this version is pretty rare, though it may be appropriate if you need the generated values to be distinguishable from one another.)

Version 3 UUIDs are based on the MD5 hash of the input value. MD5 itself has been deprecated, though, so if you need a way to generate keys reproduceably from an input value but do not want them to be reversible or susceptible to hash collisions, use version 5 instead.

Version 4 UUIDs are completely random. Values generated by this library are pulled from the system entropy device (if one is present) by calling crypto:strong_rand_bytes/1.

Version 5 UUIDs are based on a truncated SHA1 hash of the input value. (SHA1 hashes are 160 bytes long, and UUIDs are only 128 bytes; the extra bits are discarded.) This is the same principle as version 3, but carries a much stronger guarantee of resistance to reversal of the hashed value and potential collisions.

Generation of all five types is supported by this library, as is detection of a few other non-RFC UUID variants.

Values generated by zuuid are represented internally as tuples of the form {uuid, <<_:128>>}. The canonical serialization format is a hexadecimal string broken in periods of 6-4-4-4-12. See the example shell session or the documentation site for details and examples of how to generate and convert values among various representations (don't worry, its pretty straight forward).

About this project

An RFC 4122 UUID implementation in Erlang focused on readability, plain coding style and clear documentation.

This is a fully-featured UUID generation utility, despite being an example project. This project implements version 1, 2, 3, 4 and 5 UUIDs, and includes a process-based implementation of a value-checker to guarantee that high-frequency calls to version 1 and 2 generators will not result in accidentally duplicate values.

Links

Documentation

http://zxq9.com/projects/zuuid/docs/

Source

https://github.com/zxq9/zuuid

An Example Shell Session

    ceverett@changa:~/vcs/zuuid$ ./zmake
    up_to_date
    Writing docs...
    ceverett@changa:~/vcs/zuuid$ erl -pa ebin
    Erlang/OTP 19 [erts-8.1] [source] [64-bit] [smp:2:2] [async-threads:10] [kernel-poll:false]
    
    Eshell V8.1  (abort with ^G)
    1> zuuid:start().
    ok
    2> {ok, MAC} = zuuid:get_hw_addr("eth0").
    {ok,<<184,107,35,128,22,24>>}
    3> zuuid:config({node, MAC}).
    ok
    4> UUID = zuuid:v1().
    {uuid,<<210,125,3,51,190,133,17,230,155,227,184,107,35,128,22,24>>}
    5> zuuid:version(UUID).
    {rfc4122,1}
    6> zuuid:string(UUID).
    "D27D0333-BE85-11E6-9BE3-B86B23801618"
    7> zuuid:binary(zuuid:v4()).
    <<"8B3831A6-7BF3-4477-BFEE-3BF54DEA4537">>
    8> UUID2 = zuuid:read_uuid("12345678-90ab-cdef-1234-567890abcdef").     
    {uuid,<<18,52,86,120,144,171,205,239,18,52,86,120,144,171,205,239>>}
    9> zuuid:version(UUID2).
    {ncs,compatibility}
    10> zuuid:string(UUID2).
    "12345678-90AB-CDEF-1234-567890ABCDEF"
    11> NewMAC = zuuid:read_mac("12:34:56:78:90:ab").
    <<18,52,86,120,144,171>>
    12> zuuid:config({node, NewMAC}).
    ok
    13> zuuid:string(zuuid:v1()).
    "1852C4EC-BE86-11E6-9BE3-1234567890AB"

Contributing

Anything missing? Silly? Stupid? Buggy? Want to actually use it in a real project (and so really want some erlang.mk or rebar3 files added)? Send a pull request, file a bug, or just send me an email.