You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: .github/agents/agent-docs/BITE.md
+17-15Lines changed: 17 additions & 15 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,12 +1,14 @@
1
1
# BITE on SKALE — Auditor's Context
2
2
3
-
This document is written for a Solidity audit agent reviewing contracts that import `@skalenetwork/bite-solidity`. It describes how a BITE-enabled SKALE chain differs from Ethereum, what Conditional Transactions (CTXs) are, and the invariants an auditor must keep in mind when reasoning about confidentiality, re-entrancy, gas accounting, and the callback trust boundary.
3
+
<!-- cspell:words ciphertext ECIES -->
4
+
5
+
This document is written for a Solidity audit agent reviewing contracts that import `@skalenetwork/bite-solidity`. It describes how a BITE-enabled SKALE chain differs from Ethereum, what Conditional Transactions (CTXs) are, and the invariants an auditor must keep in mind when reasoning about confidentiality, reentrancy, gas accounting, and the callback trust boundary.
4
6
5
7
---
6
8
7
9
## 1. How SKALE (with BITE) differs from Ethereum
8
10
9
-
SKALE chains are EVM-compatible, but several runtime assumptions that hold on Ethereum do not hold on SKALE — and some new ones are introduced by BITE. An auditor should keep these in mind when analysing any contract deployed to a BITE-enabled SKALE chain.
11
+
SKALE chains are EVM-compatible, but several runtime assumptions that hold on Ethereum do not hold on SKALE — and some new ones are introduced by BITE. An auditor should keep these in mind when analyzing any contract deployed to a BITE-enabled SKALE chain.
10
12
11
13
### 1.1 Chain-level differences (SKALE, independent of BITE)
12
14
@@ -22,7 +24,7 @@ SKALE chains are EVM-compatible, but several runtime assumptions that hold on Et
22
24
-**Conditional Transactions (CTXs).** A contract can submit a transaction that will be executed by the chain itself after the BITE network threshold-decrypts payloads off-chain. The callback that delivers the decrypted data is a **system-originated transaction**, not a normal user tx. See §4.
23
25
-**Encrypted storage.** The intended design is that sensitive data exists on-chain only as TE or ECIES ciphertext; decryption happens transiently during a CTX callback or off-chain if ECIES encrypted. `onDecrypt` execution trace is protected - only saved memory will be "revealed".
24
26
-**Freshly generated callback senders.** Each CTX callback is delivered from a newly generated, CTX-unique EOA-like address (`ctxSender`). Trust of `msg.sender` inside `onDecrypt` is established by whitelisting this address at submission time — never by any other means.
25
-
-**Asynchronous execution in separate transactions.**`submitCTX` returns synchronously, but `onDecrypt` fires in a *later* block. Any invariant that a reviewer would normally check with "this happens atomically within one tx" does NOT hold across a CTX boundary - should watchout close for Atomicity issues.
27
+
-**Asynchronous execution in separate transactions.**`submitCTX` returns synchronously, but `onDecrypt` fires in a *later* block. Any invariant that a reviewer would normally check with "this happens atomically within one tx" does NOT hold across a CTX boundary - watch out closely for atomicity issues.
26
28
27
29
---
28
30
@@ -58,7 +60,7 @@ This is the entry point the BITE network invokes from `ctxSender` in a later blo
Encrypts arbitrary bytes under the **network public threshold key**. Only the BITE network (via a threshold of nodes) can decrypt. When an account submits the request, it's address is saved in the cyphertext. Only that account is allowed to schedule decryption of such values - otherwise anyone could write a contract to decrypt any value encrypted by another account.
63
+
Encrypts arbitrary bytes under the **network public threshold key**. Only the BITE network (via a threshold of nodes) can decrypt. When an account submits the request, it's address is saved in the ciphertext. Only that account is allowed to schedule decryption of such values - otherwise anyone could write a contract to decrypt any value encrypted by another account.
_canCallOnDecrypt[ctxSender] = true; // authorise exactly this ctxSender
116
+
_canCallOnDecrypt[ctxSender] = true; // authorize exactly this ctxSender
115
117
ctxSender.sendValue(msg.value); // fund the callback
116
118
}
117
119
```
@@ -121,7 +123,7 @@ Step-by-step semantics during this transaction:
121
123
1.`BITE.submitCTX` performs a low-level `call` to `0x1B` with ABI-encoded `(gasLimit, abi.encode(encryptedArgs, plaintextArgs))`.
122
124
2. The precompile validates: shape, encoded offsets, TE-ciphertext sizes, destination (the calling contract), signature/transaction construction internals. Any failure reverts with a typed `CTX*` error from `SubmitCTXErrors`.
123
125
3. On success, the precompile returns a 20-byte `ctxSender` address and emits `CTXSubmitted(ctxSender)` (from the library, not the precompile).
124
-
4. The supplicant contract **must** record authorisation of this `ctxSender` before the transaction ends (typically `_canCallOnDecrypt[ctxSender] = true`). It **must** also transfer enough value to `ctxSender` to cover `gasLimit * tx.gasprice`.
126
+
4. The supplicant contract **must** record authorization of this `ctxSender` before the transaction ends (typically `_canCallOnDecrypt[ctxSender] = true`). It **must** also transfer enough value to `ctxSender` to cover `gasLimit * tx.gasprice`.
125
127
5. Transaction 1 ends. No decryption has happened yet. Nothing has been revealed. It is essential that state-changes remain atomic - if a transaction depends on a CTX, make all state changes during the `onDecrypt` callback.
126
128
127
129
### 4.2 Between transactions — BITE network work
@@ -131,7 +133,7 @@ The network observes the CTX, performs threshold decryption of each `encryptedAr
131
133
This happens in a later block. The guarantees are as follows:
132
134
- CTXs are scheduled for the **next block** (N+1).
133
135
- Each block still verifies gasLimit, thus if for some reason the amount of CTXs scheduled for block N+1 is too much, the remaining CTXs are re-scheduled for block N+2, and so on. decrypted CTXs take precedence over regular transactions - when picking transactions for a block, first the block is filled with CTXs.
134
-
- Order is guaranteed - CTXs are executed by the same order they are scheduled. However, between CTX submission and execution, other state changes can occurr by other transactions.
136
+
- Order is guaranteed - CTXs are executed by the same order they are scheduled. However, between CTX submission and execution, other state changes can occur by other transactions.
135
137
136
138
### 4.3 Transaction 2 — Callback (`onDecrypt`)
137
139
@@ -159,19 +161,19 @@ function onDecrypt(
159
161
}
160
162
```
161
163
162
-
NOTE: This pattern does not clear senders from failed transactions. This is considered safe because it is considered *impossible* to get the key for such address to re-sign a transaction. The state is changed to `false` on successfull ones to minimze used storage.
164
+
NOTE: This pattern does not clear senders from failed transactions. This is considered safe because it is considered *impossible* to get the key for such address to re-sign a transaction. The state is changed to `false` on successful ones to minimize used storage.
163
165
164
166
165
-
### 4.5 Re-entrancy and state consistency
167
+
### 4.5 Reentrancy and state consistency
166
168
167
-
-`submitCTX` is a `call` to a system precompile. The precompile is trusted and performs no external calls back into user contracts. **Re-entrancy from the precompile itself is not possible.**
169
+
-`submitCTX` is a `call` to a system precompile. The precompile is trusted and performs no external calls back into user contracts. **Reentrancy from the precompile itself is not possible.**
168
170
- However, `onDecrypt` runs in a **later transaction** with arbitrary contract state evolved in between. Anything a normal tx can do (price changes, role changes, pauses, upgrades) can have happened between submission and callback. Treat the callback as a fresh, adversarially-scheduled tx with respect to every state variable that is not explicitly snapshotted into `plaintextArguments`, storage keyed on `ctxSender`, or the encrypted payload.
169
-
- Multiple CTXs can be in flight simultaneously. `onDecrypt` may be invoked with interleavings unrelated to submission order. Per-CTX state should be keyed on `ctxSender`, not on globals.
171
+
- Multiple CTXs can be in flight simultaneously. `onDecrypt` may be interleaved and is not guaranteed to match the submission order. Per-CTX state should be keyed on `ctxSender`, not on globals.
170
172
-`onDecrypt` itself may call `submitCTX` (self-referential CTX chains). This means a callback can submit further CTXs whose callbacks will fire later. Audit for unbounded recursion / gas griefing and for correct termination conditions.
171
173
172
174
### 4.6 Gas accounting inside `onDecrypt`
173
175
174
-
The callback is executed with exactly `GAS_LIMIT` gas (the value passed to `submitCTX`). If `onDecrypt` runs out of gas, the callback reverts, and (depending on chain behaviour and the refund policy) the CTX may be dropped.
176
+
The callback is executed with exactly `GAS_LIMIT` gas (the value passed to `submitCTX`). If `onDecrypt` runs out of gas, the callback reverts, and (depending on chain behavior and the refund policy) the CTX may be dropped.
175
177
176
178
### 4.7 What can go wrong with the plaintext once it is inside `onDecrypt`
177
179
@@ -180,16 +182,16 @@ The plaintext exists in memory for the duration of the callback. Audit for:
180
182
- Writing plaintext to storage (makes it world-readable forever).
181
183
- Emitting plaintext in events (events are public).
182
184
- Don't trust passing plaintext to other (arbitrary) contracts in non-view functions.
183
-
- Verify re-encryption of said sensitive texts (usualy via ECIES), and what Public Key is used
185
+
- Verify re-encryption of said sensitive texts (usually via ECIES), and what Public Key is used
184
186
185
187
A correctly-written supplicant either (a) re-encrypts the plaintext under ECIES for a specific viewer and stores the ECIES ciphertext, or (b) uses the plaintext to drive a single decision (e.g. "did this bidder offer >= reserve?") and discards it without persistence.
186
188
187
189
---
188
190
189
-
## 5. Consensus and block-rule behaviour of CTXs
191
+
## 5. Consensus and block-rule behavior of CTXs
190
192
191
193
- SKALE networks have a fixed block limit.
192
-
- CTXs, once scheduled, are saved to be executed in the first available block after the one they're scheduled in. They take priority over regular transactions, thus if there are pending CTXs for a given block, other transactions are put on hold untill a block has space for them.
194
+
- CTXs, once scheduled, are saved to be executed in the first available block after the one they're scheduled in. They take priority over regular transactions, thus if there are pending CTXs for a given block, other transactions are put on hold until a block has space for them.
193
195
- We can assume execution context (trace) of CTXs (onDecrypt) is hidden, only saved storage/events are revealed as usual.
194
196
- CTXs are executed in the exact same order they are scheduled.
195
197
- For each CTX, a random address is generated to be the sender of such CTX. This address is known upon CTX scheduling, and should be topped up with gas enough to pay for the CTX, otherwise it fails (CTX may not appear in the block)
0 commit comments