Skip to content

Commit 0eeadfd

Browse files
authored
Merge pull request #513 from oasisprotocol/CU-8692kbhwx_Storage-IO-Patterns_Xi-Zhang
Start security section for Sapphire/OPL
2 parents c7bda75 + 92586e7 commit 0eeadfd

File tree

3 files changed

+121
-1
lines changed

3 files changed

+121
-1
lines changed

docs/dapp/sapphire/guide.mdx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,10 @@ state encryption key from the Oasis key manager. Both the keys and values of the
183183
items stored in state are encrypted, but the size of either is *not* hidden. You
184184
app may need to pad state items to a constant length, or use other obfuscation.
185185
Observers may also be able to infer computation based on storage access patterns,
186-
so you might need to obfuscate that, too.
186+
so you may need to obfuscate that, too. See [Security chapter] for more
187+
recommendations.
188+
189+
[Security chapter]: ./security.md#storage-access-patterns
187190

188191
:::danger Contract state leaks a fine-grained access pattern
189192

docs/dapp/sapphire/security.md

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
---
2+
description: "Secure dApps: Recipes for Confidentiality"
3+
---
4+
5+
# Security
6+
7+
This page is an ongoing work in progress to support confidential smart contract
8+
development. At the moment we address safeguarding storage variable access
9+
patterns and provide best practices for more secure orderings of error checking
10+
to prevent leaking contract state.
11+
12+
## Storage Access Patterns
13+
14+
You can use a tool such as [hardhat-tracer] to examine the base EVM state
15+
transitions under the hood.
16+
17+
```shell npm2yarn
18+
npm install -D hardhat-tracer
19+
```
20+
21+
and add `hardhat-tracer` to your `config.ts` file,
22+
23+
```typescript
24+
import "hardhat-tracer"
25+
```
26+
27+
in order to test and show call traces.
28+
29+
```shell
30+
npx hardhat test --vvv --opcodes SSTORE,SLOAD
31+
```
32+
33+
You can also trace a particular transaction, once you know its hash.
34+
35+
```shell
36+
npx hardhat trace --hash 0xTransactionHash
37+
```
38+
39+
For both [gas] usage and confidentiality purposes, we **recommend using
40+
non-unique data size**. E.g. 64-byte value will still be distinct from a
41+
128-byte value.
42+
43+
:::caution Inference based on access patterns
44+
45+
`SSTORE` keys from one transaction may be linked to `SLOAD` keys of another
46+
transaction.
47+
48+
:::
49+
50+
## Order of Operations
51+
52+
When handling errors, gas usage patterns not only can reveal the code path
53+
taken, **but sometimes the balance of a user as well** (in the case of a diligent
54+
attacker using binary search).
55+
56+
```solidity
57+
function transferFrom(address who, address to, uint amount)
58+
external
59+
{
60+
require( balances[who] >= amount );
61+
require( allowances[who][msg.sender] >= amount );
62+
// ...
63+
}
64+
```
65+
66+
Modifying the order of error checking can prevent the accidental disclosure of
67+
balance information in the example above.
68+
69+
```solidity
70+
function transferFrom(address who, address to, uint amount)
71+
external
72+
{
73+
require( allowances[who][msg.sender] >= amount );
74+
require( balances[who] >= amount );
75+
// ...
76+
}
77+
```
78+
79+
## Gas Padding
80+
81+
To prevent leaking information about a particular transaction, Sapphire
82+
provides a [precompile] for dApp developers to **pad the amount of gas used
83+
in a transaction**.
84+
85+
```solidity
86+
contract GasExample {
87+
bytes32 tmp;
88+
89+
function constantMath(bool doMath, uint128 padGasAmount) external {
90+
if (doMath) {
91+
bytes32 x;
92+
93+
for (uint256 i = 0; i < 100; i++) {
94+
x = keccak256(abi.encodePacked(x, tmp));
95+
}
96+
97+
tmp = x;
98+
}
99+
100+
Sapphire.padGas(padGasAmount);
101+
}
102+
}
103+
```
104+
105+
Both contract calls below should use the same amount of gas. Sapphire also
106+
provides the precompile to return the gas [used] by the current transaction.
107+
108+
```typescript
109+
await contract.constantMath(true, 100000);
110+
await contract.constantMath(false, 100000);
111+
```
112+
113+
[gas]: https://docs.soliditylang.org/en/latest/internals/layout_in_storage.html
114+
[hardhat-tracer]: https://www.npmjs.com/package/hardhat-tracer
115+
[precompile]: https://api.docs.oasis.io/sol/sapphire-contracts/contracts/Sapphire.sol/library.Sapphire.html#padgas
116+
[used]: https://api.docs.oasis.io/sol/sapphire-contracts/contracts/Sapphire.sol/library.Sapphire.html#gasused

sidebarDapp.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const sidebars = {
2323
'dapp/sapphire/gasless',
2424
'dapp/sapphire/precompiles',
2525
'dapp/sapphire/addresses',
26+
'dapp/sapphire/security',
2627
{
2728
type: 'link',
2829
label: 'TypeScript API',

0 commit comments

Comments
 (0)