Skip to content

Commit 6ac9da6

Browse files
Draft version
1 parent 4fb52ef commit 6ac9da6

File tree

1 file changed

+74
-82
lines changed

1 file changed

+74
-82
lines changed

docs/v3/guidelines/smart-contracts/security/random-number-generation.md

Lines changed: 74 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -12,95 +12,87 @@ These algorithms typically require a _seed_ value to produce a sequence of _pseu
1212

1313
To predict the result of the `random()` function in a smart contract, one would need to know the current `seed` of the block, which is impossible unless you are a validator.
1414

15-
## Simply use randomize_lt()
15+
# Approaches and security considerations
1616

17-
To make random number generation unpredictable, you can add the current [Logical Time](/v3/documentation/smart-contracts/message-management/messages-and-transactions#what-is-a-logical-time) to the seed. This ensures that different transactions produce different seeds and results.
17+
There are multiple methods for generating random values, each with distinct trade-offs between speed, security, and decentralization guarantees.
1818

19-
Add the `randomize_lt()` call before generating random numbers to make them unpredictable:
19+
Below we outline three fundamental approaches:
2020

21-
```func
22-
randomize_lt();
23-
int x = random(); ;; users can't predict this number
24-
```
21+
---
2522

26-
However, validators or collators can still influence the result as they determine the seed of the current block.
23+
## Approach 1: randomize_lt
2724

28-
## Is there a way to protect against manipulation by validators?
25+
**Mechanism**: Generates randomness using block logical time (`lt`) and blockchain entropy.
26+
**Security Model**:
2927

30-
You can use more complex schemes to reduce the risk of validators manipulating the seed. For example, you can skip one block before generating a random number, which changes the seed less predictably.
28+
- ✅ Safe against user manipulation
29+
- ❌ Vulnerable to colluding validators (could theoretically predict/influence values)
3130

32-
Skipping blocks is straightforward. You can achieve this by sending a message to the MasterChain and back to your contract's workchain. Let's explore a simple example!
31+
**Speed**: Fast (single-block operation)
32+
**Use Cases**:
33+
34+
- Non-critical applications, for example gaming & NFTs
35+
- Scenarios where validator trust is assumed
36+
37+
---
38+
39+
## Approach 2: Block skipping
40+
41+
**Mechanism**: Uses entropy from skipped blocks in blockchain history.
42+
**Security Model**:
43+
44+
- ✅ Resistant to user manipulation
45+
- ⚠️ Not fully secure against determined validators (may influence block inclusion timing)
46+
47+
**Speed**: Slow (requires multiple blocks to finalize)
48+
**Use Cases**:
49+
50+
- Medium-stakes applications, for example lottery systems
51+
- Scenarios with partial trust in validator set
52+
53+
---
54+
55+
## Approach 3: Commit-reveal scheme
56+
57+
**Mechanism**:
58+
59+
1. **Commit Phase**: Participants submit hashed secrets
60+
2. **Reveal Phase**: Secrets are disclosed and combined to generate final randomness
61+
62+
**Security Model**:
63+
64+
- ✅ Cryptographically secure when properly implemented
65+
- ✅ Resilient to both users and validators
66+
- ⚠️ Requires protocol-level verification of commitments
67+
68+
**Speed**: Very slow (multi-phase, multi-block process)
69+
**Use Cases**:
70+
71+
- High-value applications, for example decentralized auctions
72+
- Systems requiring Byzantine fault tolerance
73+
74+
---
75+
76+
### **Key Considerations**
77+
78+
| Factor | `randomize_lt` | Block skipping | Commit-reveal |
79+
| ------------------------- | -------------- | -------------- | ------------- |
80+
| Speed | Fast | Moderate | Slow |
81+
| User Resistance | High | High | Highest |
82+
| Validator Resistance | Low | Medium | Highest |
83+
| Implementation Complexity | Low | Medium | High |
84+
85+
---
86+
87+
:::caution
88+
No method is universally perfect – choose based on:
89+
90+
- Value-at-risk in your application
91+
- Required time-to-finality
92+
- Trust assumptions about validators
3393

34-
:::caution
35-
Do not use this example contract in real projects. Write your own instead.
3694
:::
3795

38-
### Main contract in any workchain
39-
40-
Let's create a simple lottery contract. A user sends 1 TON and, with a 50% chance, receives 2 TON back.
41-
42-
```func
43-
;; set the echo-contract address
44-
const echo_address = "Ef8Nb7157K5bVxNKAvIWreRcF0RcUlzcCA7lwmewWVNtqM3s"a;
45-
46-
() recv_internal (int msg_value, cell in_msg_full, slice in_msg_body) impure {
47-
var cs = in_msg_full.begin_parse();
48-
var flags = cs~load_uint(4);
49-
if (flags & 1) { ;; ignore bounced messages
50-
return ();
51-
}
52-
slice sender = cs~load_msg_addr();
53-
54-
int op = in_msg_body~load_uint(32);
55-
if ((op == 0) & equal_slice_bits(in_msg_body, "bet")) { ;; bet from user
56-
throw_unless(501, msg_value == 1000000000); ;; 1 TON
57-
58-
send_raw_message(
59-
begin_cell()
60-
.store_uint(0x18, 6)
61-
.store_slice(echo_address)
62-
.store_coins(0)
63-
.store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1) ;; default message headers (see sending messages page)
64-
.store_uint(1, 32) ;; let 1 be echo opcode in our contract
65-
.store_slice(sender) ;; forward user address
66-
.end_cell(),
67-
64 ;; send the remaining value of an incoming msg
68-
);
69-
}
70-
elseif (op == 1) { ;; echo
71-
throw_unless(502, equal_slice_bits(sender, echo_address)); ;; only accept echoes from our echo-contract
72-
73-
slice user = in_msg_body~load_msg_addr();
74-
75-
{-
76-
at this point, we have skipped 1+ blocks
77-
so, let's generate the random number
78-
-}
79-
randomize_lt();
80-
int x = rand(2); ;; generate a random number (either 0 or 1)
81-
if (x == 1) { ;; user won
82-
send_raw_message(
83-
begin_cell()
84-
.store_uint(0x18, 6)
85-
.store_slice(user)
86-
.store_coins(2000000000) ;; 2 TON
87-
.store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1) ;; default message headers (see sending messages page)
88-
.end_cell(),
89-
3 ;; ignore errors & pay fees separately
90-
);
91-
}
92-
}
93-
}
94-
```
95-
96-
Deploy this contract in any workchain (likely Basechain), and you're done!
97-
98-
## Is this method 100% secure?
99-
100-
While this method improves security, there is still a tiny chance of manipulation if an attacker controls multiple validators. In such cases, they might influence the _seed_, which affects the random number. Even though the probability is extremely low, it is worth considering.
101-
102-
With the latest TVM upgrade, introducing new values to the `c7` register enhances the security of random number generation. Specifically, the upgrade adds information about the last 16 MasterChain blocks to the `c7` register.
103-
104-
The MasterChain block information, due to its dynamic nature, serves as an additional source of entropy for random number generation. By incorporating this data into your randomness algorithm, you can create even harder numbers for potential adversaries to predict.
105-
106-
For more details on this TVM upgrade, refer to [TVM Upgrade](/v3/documentation/tvm/changelog/tvm-upgrade-2023-07).
96+
Always audit implementations through formal verification where possible.
97+
98+
For working examples, refer to [randomization contracts example](https://github.com/puppycats/ton-random).

0 commit comments

Comments
 (0)