Skip to main content

How to generate random numbers using Rell

In blockchain applications like games, lotteries, and cryptographic protocols, it is essential to generate random numbers that are both unpredictable and reproducible. In Chromia, you can achieve this using custom Rell functions. These functions utilize various blockchain context elements, such as block height, timestamp, and block IDs, ensuring the generation of unpredictable random numbers while maintaining reproducibility with identical inputs.

warning

Please note that the random numbers generated by these functions are pseudo-random. While they rely on variables like block time and block height, which add some unpredictability, they are not truly random and could be vulnerable to predictability or manipulation in specific contexts. If your application requires true randomness for security-critical purposes, consider using an external oracle to provide random data.

We will utilize op_context in the following functions. However, note that op_context is only available within operations. For more details, refer to the documentation.

To achieve pseudo-random number generation in Rell, you can use the following functions:

  • get_random_number(high): Generates a random number between 0 (inclusive) and the specified high value (inclusive). It leverages elements such as block time, block height, and operation index for randomness.

    function get_random_number(high: integer = 100): integer {
    if (high == 0) return 0; // avoid division by zero
    return (op_context.last_block_time - op_context.block_height - op_context.op_index) % high + 1;
    }
  • get_random_number_in_range(from, to): Generates a random number within a specified range (from and to inclusive).

    function get_random_number_in_range(from: integer, to: integer): integer {
    require(from <= to, "To must be higher than from");
    return from + get_random_number(to - from);
    }
  • get_random_number_with_seed(high, seed): Generates a random number with an additional seed parameter. If multiple random numbers are needed within the same operation, provide a different seed each time. For instance, use the iterator index as the seed in a loop. This function combines a random hexadecimal number with block time, block height, and row ID for randomness. The block_dto struct and get_last_block_data function are used to retrieve the latest block data.

    function get_random_number_with_seed(high: integer, seed: integer = 0) {
    if (high == 0) return 0;
    val key = seed % 32;
    val last_block_data = get_last_block_data();
    val random_value = integer.from_hex(last_block_data.block_rid.to_hex()[key]) + (
    last_block_data.block_timestamp - last_block_data.block_height - last_block_data.rowid
    );
    return random_value % high + 1;
    }

    struct block_dto {
    timestamp;
    block_rid: byte_array;
    block_height: integer;
    rowid: integer;
    }

    function get_last_block_data(): (
    rowid: integer,
    block_height: integer,
    block_timestamp: integer,
    block_rid: byte_array
    ) {
    // Ensure the chain has at least 2 blocks written, as the last block may not have block_rid yet
    val blocks = block @* { } (
    block_dto(
    timestamp = $.timestamp,
    block_rid = $.block_rid,
    block_height = $.block_height,
    rowid = $.rowid.to_integer()
    )
    ) limit 2;

    return when (blocks.size()) {
    1 -> (
    rowid = blocks[0].rowid,
    block_height = blocks[0].block_height,
    block_timestamp = blocks[0].timestamp,
    block_rid = blocks[0].block_rid
    );
    2 -> (
    rowid = blocks[1].rowid,
    block_height = blocks[1].block_height,
    block_timestamp = blocks[1].timestamp,
    block_rid = blocks[1].block_rid
    );
    else -> (
    rowid = 88,
    block_height = 32253,
    block_timestamp = 55554444333,
    block_rid = chain_context.blockchain_rid
    );
    };
    }

Using these functions will help generate pseudo-random numbers for your blockchain applications. However, keep in mind the limitations of pseudo-randomness and consider using more secure methods if true randomness is required. Happy coding with Rell!