Module 0x1::randomness
This module provides access to instant secure randomness generated by the Aptos validators, as documented in AIP-41.
Secure randomness means (1) the randomness cannot be predicted ahead of time by validators, developers or users and (2) the randomness cannot be biased in any way by validators, developers or users.
Security holds under the same proof-of-stake assumption that secures the Aptos network.
- Resource
PerBlockRandomness - Struct
RandomnessGeneratedEvent - Resource
Ghost$var - Constants
- Function
initialize - Function
on_new_block - Function
next_32_bytes - Function
bytes - Function
u8_integer - Function
u16_integer - Function
u32_integer - Function
u64_integer - Function
u128_integer - Function
u256_integer - Function
u256_integer_internal - Function
u8_range - Function
u16_range - Function
u32_range - Function
u64_range - Function
u64_range_internal - Function
u128_range - Function
u256_range - Function
permutation - Function
safe_add_mod - Function
take_first - Function
fetch_and_increment_txn_counter - Function
is_unbiasable - Specification
- Function
initialize - Function
on_new_block - Function
next_32_bytes - Function
u8_integer - Function
u16_integer - Function
u32_integer - Function
u64_integer - Function
u128_integer - Function
u256_integer - Function
u256_integer_internal - Function
u8_range - Function
u64_range - Function
u64_range_internal - Function
u256_range - Function
permutation - Function
fetch_and_increment_txn_counter - Function
is_unbiasable
- Function
use 0x1::event;
use 0x1::hash;
use 0x1::option;
use 0x1::system_addresses;
use 0x1::transaction_context;
use 0x1::vector;
Resource PerBlockRandomness
32-byte randomness seed unique to every block. This resource is updated in every block prologue.
struct PerBlockRandomness has drop, key
Fields
-
epoch: u64 -
round: u64 -
seed: option::Option<vector<u8>>
Struct RandomnessGeneratedEvent
Event emitted every time a public randomness API in this module is called.
#[event]
struct RandomnessGeneratedEvent has drop, store
Fields
-
dummy_field: bool
Resource Ghost$var
struct Ghost$var has copy, drop, store, key
Fields
-
v: vector<u8>
Constants
const MAX_U256: u256 = 115792089237316195423570985008687907853269984665640564039457584007913129639935;
const DST: vector<u8> = [65, 80, 84, 79, 83, 95, 82, 65, 78, 68, 79, 77, 78, 69, 83, 83];
Randomness APIs calls must originate from a private entry function with
#[randomness] annotation. Otherwise, malicious users can bias randomness result.
const E_API_USE_IS_BIASIBLE: u64 = 1;
Function initialize
Called in genesis.move.
Must be called in tests to initialize the PerBlockRandomness resource.
public fun initialize(framework: &signer)
Implementation
public fun initialize(framework: &signer) {
system_addresses::assert_aptos_framework(framework);
if (!exists<PerBlockRandomness>(@aptos_framework)) {
move_to(
framework,
PerBlockRandomness { epoch: 0, round: 0, seed: option::none() }
);
}
}
Function on_new_block
Invoked in block prologues to update the block-level randomness seed.
public(friend) fun on_new_block(vm: &signer, epoch: u64, round: u64, seed_for_new_block: option::Option<vector<u8>>)
Implementation
public(friend) fun on_new_block(
vm: &signer,
epoch: u64,
round: u64,
seed_for_new_block: Option<vector<u8>>
) acquires PerBlockRandomness {
system_addresses::assert_vm(vm);
if (exists<PerBlockRandomness>(@aptos_framework)) {
let randomness = borrow_global_mut<PerBlockRandomness>(@aptos_framework);
randomness.epoch = epoch;
randomness.round = round;
randomness.seed = seed_for_new_block;
}
}
Function next_32_bytes
Generate the next 32 random bytes. Repeated calls will yield different results (assuming the collision-resistance of the hash function).
fun next_32_bytes(): vector<u8>
Implementation
fun next_32_bytes(): vector<u8> acquires PerBlockRandomness {
assert!(is_unbiasable(), E_API_USE_IS_BIASIBLE);
let input = DST;
let randomness = borrow_global<PerBlockRandomness>(@aptos_framework);
let seed = *randomness.seed.borrow();
input.append(seed);
input.append(transaction_context::get_transaction_hash());
input.append(fetch_and_increment_txn_counter());
hash::sha3_256(input)
}
Function bytes
Generates a sequence of bytes uniformly at random
public fun bytes(n: u64): vector<u8>
Implementation
public fun bytes(n: u64): vector<u8> acquires PerBlockRandomness {
let v = vector[];
let c = 0;
while (c < n) {
let blob = next_32_bytes();
v.reverse_append(blob);
c += 32;
};
if (c > n) {
v.trim(n);
};
event::emit(RandomnessGeneratedEvent {});
v
}
Function u8_integer
Generates an u8 uniformly at random.
public fun u8_integer(): u8
Implementation
public fun u8_integer(): u8 acquires PerBlockRandomness {
let raw = next_32_bytes();
let ret: u8 = raw.pop_back();
event::emit(RandomnessGeneratedEvent {});
ret
}
Function u16_integer
Generates an u16 uniformly at random.
public fun u16_integer(): u16
Implementation
public fun u16_integer(): u16 acquires PerBlockRandomness {
let raw = next_32_bytes();
let i = 0;
let ret: u16 = 0;
while (i < 2) {
ret = ret * 256 + (raw.pop_back() as u16);
i += 1;
};
event::emit(RandomnessGeneratedEvent {});
ret
}
Function u32_integer
Generates an u32 uniformly at random.
public fun u32_integer(): u32
Implementation
public fun u32_integer(): u32 acquires PerBlockRandomness {
let raw = next_32_bytes();
let i = 0;
let ret: u32 = 0;
while (i < 4) {
ret = ret * 256 + (raw.pop_back() as u32);
i += 1;
};
event::emit(RandomnessGeneratedEvent {});
ret
}
Function u64_integer
Generates an u64 uniformly at random.
public fun u64_integer(): u64
Implementation
public fun u64_integer(): u64 acquires PerBlockRandomness {
let raw = next_32_bytes();
let i = 0;
let ret: u64 = 0;
while (i < 8) {
ret = ret * 256 + (raw.pop_back() as u64);
i += 1;
};
event::emit(RandomnessGeneratedEvent {});
ret
}
Function u128_integer
Generates an u128 uniformly at random.
public fun u128_integer(): u128
Implementation
public fun u128_integer(): u128 acquires PerBlockRandomness {
let raw = next_32_bytes();
let i = 0;
let ret: u128 = 0;
while (i < 16) {
ret = ret * 256 + (raw.pop_back() as u128);
i += 1;
};
event::emit(RandomnessGeneratedEvent {});
ret
}
Function u256_integer
Generates a u256 uniformly at random.
public fun u256_integer(): u256
Implementation
public fun u256_integer(): u256 acquires PerBlockRandomness {
event::emit(RandomnessGeneratedEvent {});
u256_integer_internal()
}
Function u256_integer_internal
Generates a u256 uniformly at random.
fun u256_integer_internal(): u256
Implementation
fun u256_integer_internal(): u256 acquires PerBlockRandomness {
let raw = next_32_bytes();
let i = 0;
let ret: u256 = 0;
while (i < 32) {
ret = ret * 256 + (raw.pop_back() as u256);
i += 1;
};
ret
}
Function u8_range
Generates a number $n \in [min_incl, max_excl)$ uniformly at random.
NOTE: The uniformity is not perfect, but it can be proved that the bias is negligible. If you need perfect uniformity, consider implement your own via rejection sampling.
public fun u8_range(min_incl: u8, max_excl: u8): u8
Implementation
public fun u8_range(min_incl: u8, max_excl: u8): u8 acquires PerBlockRandomness {
let range = ((max_excl - min_incl) as u256);
let sample = ((u256_integer_internal() % range) as u8);
event::emit(RandomnessGeneratedEvent {});
min_incl + sample
}
Function u16_range
Generates a number $n \in [min_incl, max_excl)$ uniformly at random.
NOTE: The uniformity is not perfect, but it can be proved that the bias is negligible. If you need perfect uniformity, consider implement your own via rejection sampling.
public fun u16_range(min_incl: u16, max_excl: u16): u16
Implementation
public fun u16_range(min_incl: u16, max_excl: u16): u16 acquires PerBlockRandomness {
let range = ((max_excl - min_incl) as u256);
let sample = ((u256_integer_internal() % range) as u16);
event::emit(RandomnessGeneratedEvent {});
min_incl + sample
}
Function u32_range
Generates a number $n \in [min_incl, max_excl)$ uniformly at random.
NOTE: The uniformity is not perfect, but it can be proved that the bias is negligible. If you need perfect uniformity, consider implement your own via rejection sampling.
public fun u32_range(min_incl: u32, max_excl: u32): u32
Implementation
public fun u32_range(min_incl: u32, max_excl: u32): u32 acquires PerBlockRandomness {
let range = ((max_excl - min_incl) as u256);
let sample = ((u256_integer_internal() % range) as u32);
event::emit(RandomnessGeneratedEvent {});
min_incl + sample
}
Function u64_range
Generates a number $n \in [min_incl, max_excl)$ uniformly at random.
NOTE: The uniformity is not perfect, but it can be proved that the bias is negligible. If you need perfect uniformity, consider implement your own via rejection sampling.
public fun u64_range(min_incl: u64, max_excl: u64): u64
Implementation
public fun u64_range(min_incl: u64, max_excl: u64): u64 acquires PerBlockRandomness {
event::emit(RandomnessGeneratedEvent {});
u64_range_internal(min_incl, max_excl)
}
Function u64_range_internal
public fun u64_range_internal(min_incl: u64, max_excl: u64): u64
Implementation
public fun u64_range_internal(min_incl: u64, max_excl: u64): u64 acquires PerBlockRandomness {
let range = ((max_excl - min_incl) as u256);
let sample = ((u256_integer_internal() % range) as u64);
min_incl + sample
}
Function u128_range
Generates a number $n \in [min_incl, max_excl)$ uniformly at random.
NOTE: The uniformity is not perfect, but it can be proved that the bias is negligible. If you need perfect uniformity, consider implement your own via rejection sampling.
public fun u128_range(min_incl: u128, max_excl: u128): u128
Implementation
public fun u128_range(min_incl: u128, max_excl: u128): u128 acquires PerBlockRandomness {
let range = ((max_excl - min_incl) as u256);
let sample = ((