diff --git a/aptos-framework/doc/randomness.md b/aptos-framework/doc/randomness.md index 36969528f..057c243ea 100644 --- a/aptos-framework/doc/randomness.md +++ b/aptos-framework/doc/randomness.md @@ -38,7 +38,7 @@ Security holds under the same proof-of-stake assumption that secures the Aptos n - [Function `safe_add_mod`](#0x1_randomness_safe_add_mod) - [Function `safe_add_mod_for_verification`](#0x1_randomness_safe_add_mod_for_verification) - [Function `fetch_and_increment_txn_counter`](#0x1_randomness_fetch_and_increment_txn_counter) -- [Function `is_safe_call`](#0x1_randomness_is_safe_call) +- [Function `is_unbiasable`](#0x1_randomness_is_unbiasable) - [Specification](#@Specification_1) - [Function `initialize`](#@Specification_1_initialize) - [Function `on_new_block`](#@Specification_1_on_new_block) @@ -55,7 +55,7 @@ Security holds under the same proof-of-stake assumption that secures the Aptos n - [Function `permutation`](#@Specification_1_permutation) - [Function `safe_add_mod_for_verification`](#@Specification_1_safe_add_mod_for_verification) - [Function `fetch_and_increment_txn_counter`](#@Specification_1_fetch_and_increment_txn_counter) - - [Function `is_safe_call`](#@Specification_1_is_safe_call) + - [Function `is_unbiasable`](#@Specification_1_is_unbiasable)
use 0x1::event;
@@ -190,7 +190,8 @@ Event emitted every time a public randomness API in this module is called.
 
 
 
-Randomness APIs calls must originate from a private entry function. Otherwise, test-and-abort attacks are possible.
+Randomness APIs calls must originate from a private entry function with
+#[randomness] annotation. Otherwise, test-and-abort attacks are possible.
 
 
 
const E_API_USE_SUSCEPTIBLE_TO_TEST_AND_ABORT: u64 = 1;
@@ -278,7 +279,7 @@ of the hash function).
 
 
 
fun next_32_bytes(): vector<u8> acquires PerBlockRandomness {
-    assert!(is_safe_call(), E_API_USE_SUSCEPTIBLE_TO_TEST_AND_ABORT);
+    assert!(is_unbiasable(), E_API_USE_SUSCEPTIBLE_TO_TEST_AND_ABORT);
 
     let input = DST;
     let randomness = borrow_global<PerBlockRandomness>(@aptos_framework);
@@ -946,6 +947,7 @@ Compute (a + b) % m, assuming m >= 1, 0 <= a < m, 0&
 ## Function `fetch_and_increment_txn_counter`
 
 Fetches and increments a transaction-specific 32-byte randomness-related counter.
+Aborts with E_API_USE_SUSCEPTIBLE_TO_TEST_AND_ABORT if randomness is not unbiasable.
 
 
 
fun fetch_and_increment_txn_counter(): vector<u8>
@@ -964,16 +966,17 @@ Fetches and increments a transaction-specific 32-byte randomness-related counter
 
 
 
-
+
 
-## Function `is_safe_call`
+## Function `is_unbiasable`
 
-Called in each randomness generation function to ensure certain safety invariants.
-1. Ensure that the TXN that led to the call of this function had a private (or friend) entry function as its TXN payload.
-2. TBA
+Called in each randomness generation function to ensure certain safety invariants, namely:
+1. The transaction that led to the call of this function had a private (or friend) entry
+function as its payload.
+2. The entry function had #[randomness] annotation.
 
 
-
fun is_safe_call(): bool
+
fun is_unbiasable(): bool
 
@@ -982,7 +985,7 @@ Called in each randomness generation function to ensure certain safety invariant Implementation -
native fun is_safe_call(): bool;
+
native fun is_unbiasable(): bool;
 
@@ -1071,7 +1074,7 @@ Called in each randomness generation function to ensure certain safety invariant
schema NextBlobAbortsIf {
     let randomness = global<PerBlockRandomness>(@aptos_framework);
     aborts_if option::spec_is_none(randomness.seed);
-    aborts_if !spec_is_safe_call();
+    aborts_if !spec_is_unbiasable();
     aborts_if !exists<PerBlockRandomness>(@aptos_framework);
 }
 
@@ -1323,12 +1326,12 @@ Called in each randomness generation function to ensure certain safety invariant - + -### Function `is_safe_call` +### Function `is_unbiasable` -
fun is_safe_call(): bool
+
fun is_unbiasable(): bool
 
@@ -1336,16 +1339,16 @@ Called in each randomness generation function to ensure certain safety invariant
pragma opaque;
 aborts_if [abstract] false;
-ensures [abstract] result == spec_is_safe_call();
+ensures [abstract] result == spec_is_unbiasable();
 
- + -
fun spec_is_safe_call(): bool;
+
fun spec_is_unbiasable(): bool;
 
diff --git a/aptos-framework/sources/randomness.move b/aptos-framework/sources/randomness.move index 4679146cd..8873ce72d 100644 --- a/aptos-framework/sources/randomness.move +++ b/aptos-framework/sources/randomness.move @@ -22,7 +22,8 @@ module aptos_framework::randomness { const DST: vector = b"APTOS_RANDOMNESS"; - /// Randomness APIs calls must originate from a private entry function. Otherwise, test-and-abort attacks are possible. + /// Randomness APIs calls must originate from a private entry function with + /// `#[randomness]` annotation. Otherwise, test-and-abort attacks are possible. const E_API_USE_SUSCEPTIBLE_TO_TEST_AND_ABORT: u64 = 1; const MAX_U256: u256 = 115792089237316195423570985008687907853269984665640564039457584007913129639935; @@ -71,7 +72,7 @@ module aptos_framework::randomness { /// 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 acquires PerBlockRandomness { - assert!(is_safe_call(), E_API_USE_SUSCEPTIBLE_TO_TEST_AND_ABORT); + assert!(is_unbiasable(), E_API_USE_SUSCEPTIBLE_TO_TEST_AND_ABORT); let input = DST; let randomness = borrow_global(@aptos_framework); @@ -377,12 +378,14 @@ module aptos_framework::randomness { } /// Fetches and increments a transaction-specific 32-byte randomness-related counter. + /// Aborts with `E_API_USE_SUSCEPTIBLE_TO_TEST_AND_ABORT` if randomness is not unbiasable. native fun fetch_and_increment_txn_counter(): vector; - /// Called in each randomness generation function to ensure certain safety invariants. - /// 1. Ensure that the TXN that led to the call of this function had a private (or friend) entry function as its TXN payload. - /// 2. TBA - native fun is_safe_call(): bool; + /// Called in each randomness generation function to ensure certain safety invariants, namely: + /// 1. The transaction that led to the call of this function had a private (or friend) entry + /// function as its payload. + /// 2. The entry function had `#[randomness]` annotation. + native fun is_unbiasable(): bool; #[test] fun test_safe_add_mod() { @@ -403,8 +406,8 @@ module aptos_framework::randomness { fun randomness_smoke_test(fx: signer) acquires PerBlockRandomness { initialize(&fx); set_seed(x"0000000000000000000000000000000000000000000000000000000000000000"); - // Test cases should always be a safe place to do a randomness call from. - assert!(is_safe_call(), 0); + // Test cases should always have no bias for any randomness call. + assert!(is_unbiasable(), 0); let num = u64_integer(); debug::print(&num); } diff --git a/aptos-framework/sources/randomness.spec.move b/aptos-framework/sources/randomness.spec.move index b0b060005..ded9df973 100644 --- a/aptos-framework/sources/randomness.spec.move +++ b/aptos-framework/sources/randomness.spec.move @@ -15,13 +15,13 @@ spec aptos_framework::randomness { spec fun spec_fetch_and_increment_txn_counter(): vector; - spec is_safe_call(): bool { + spec is_unbiasable(): bool { pragma opaque; aborts_if [abstract] false; - ensures [abstract] result == spec_is_safe_call(); + ensures [abstract] result == spec_is_unbiasable(); } - spec fun spec_is_safe_call(): bool; + spec fun spec_is_unbiasable(): bool; spec initialize(framework: &signer) { use std::option; @@ -55,7 +55,7 @@ spec aptos_framework::randomness { spec schema NextBlobAbortsIf { let randomness = global(@aptos_framework); aborts_if option::spec_is_none(randomness.seed); - aborts_if !spec_is_safe_call(); + aborts_if !spec_is_unbiasable(); aborts_if !exists(@aptos_framework); }