#id #block #opaque #unique #integer #string #unsigned #short #fn

bin+lib block-id

Library for generating opaque, unique, and short string values from (unsigned) integers

3 releases

0.1.2 Apr 9, 2022
0.1.1 Apr 1, 2022
0.1.0 Apr 1, 2022
Download history 156/week @ 2022-11-29 68/week @ 2022-12-06 98/week @ 2022-12-13 61/week @ 2022-12-20 16/week @ 2022-12-27 59/week @ 2023-01-03 42/week @ 2023-01-10 34/week @ 2023-01-17 33/week @ 2023-01-24 39/week @ 2023-01-31 160/week @ 2023-02-07 57/week @ 2023-02-14 86/week @ 2023-02-21 91/week @ 2023-02-28 125/week @ 2023-03-07 63/week @ 2023-03-14

373 downloads per month
Used in prisoner


568 lines


GitHub Repo stars wokflow state crates.io docs.rs dependency status

block-id is a Rust library for generating opaque, unique, and short string values from (unsigned) integers.


use block_id::{Alphabet, BlockId};

fn main() {
    // Random seed.
    let seed = 9876;
    // Code length.
    let length = 5;

    let generator = BlockId::new(Alphabet::alphanumeric(), seed, length);
    // Number to string.
    assert_eq!("wjweA", &generator.encode_string(0));
    assert_eq!("ZxJrE", &generator.encode_string(1));
    assert_eq!("3e0IT", &generator.encode_string(2));

    // String to number.
    assert_eq!(2, generator.decode_string("3e0IT"));


Random-looking alphanumeric strings are often used in place of sequential numeric IDs for user-facing purposes. This has several advantages:

  • String identifiers are usually visually distinct, even if they were generated adjacently in sequence.
  • The higher information density of a larger alphabet allows for shorter codes.
  • Sequential identifiers reveal unnecessary information about ordering and object creation rate that you may not want to reveal.

block-id is the successor to tiny_id, which allows the creation of tightly-packed alphanumeric strings. tiny_id turned out to be difficult to use in a distributed environment because its state needs to be synchronized across every node that needs to generate IDs. Rather than building distributed functionality into a short ID generator, block-id provides a way of turning a sequential ID generator into a string ID generator by creating a one-to-one mapping between integers and random-looking short strings. That way, any system of generating sequential numeric IDs (for example, a database's sequence generator) can be turned into a system for generating random-looking string IDs.

use block_id::{Alphabet, BlockId};

fn main() {
    // The alphabet determines the set of valid characters in an ID.
    // For convenience, we include some common alphabets like `alphanumeric`. 
    let alphabet = Alphabet::alphanumeric();
    // The generator takes a u128 as a seed.
    let seed = 1234;

    // The length of a generated code. This is really a _minimum_ length; larger numbers
    // will be converted to longer codes since that's the only way to avoid collisions.
    let length = 4;

    // A small amount of pre-caching work happens when we create the BlockId instance,
    // so it's good to re-use the same generator where possible.
    let generator = BlockId::new(alphabet, seed, length);
    // Now that we have a generator, we can turn numbers into short IDs.
    assert_eq!("In4R", &generator.encode_string(0));

    assert_eq!("4A7N", &generator.encode_string(440));
    assert_eq!("tSp9", &generator.encode_string(441));
    assert_eq!("6z6y", &generator.encode_string(442));
    assert_eq!("ft0M", &generator.encode_string(443));

    // When we've exhausted all 4-digit codes, we simply move on to 5-digit codes.
    assert_eq!("YeyKs", &generator.encode_string(123456789));

    // ...and so on.
    assert_eq!("pFbrRf", &generator.encode_string(1234567890));

    // Codes are reversible, assuming we have the seed they were generated with.
    assert_eq!(1234567890, generator.decode_string("pFbrRf"));

How it works

block-id applies a pipeline of reversible transformations on a data in order to turn it into a string.

  • Base conversion turns the input integer into a base-N representation where N is the number of characters in the desired output alphabet.
  • Rounds consisting of:
    • Permutation applies an N-to-N map to every digit of the base-N representation. The permutation is generated from the random seed passed in the BlockId constructor.
    • Cascade applies a left-to-right cumulative sum, modulo N, to the base-N representation.
    • Rotate takes the first digit of the base-N representation and moves it to the last digit, shifting all of the other digits left by one.
  • Alphabetization translates every digit of the base-N representation to a “letter” in the alphabet provided at construction.

The number of rounds is the same as the number of digits in the base-N representation. This gives every digit a chance to influence every other digit.


block-id is designed to make it easy for a human to distinguish between two sequential codes, not to make it impossible for an adversary to reverse. It should not be considered cryptographically secure.