Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add security section for Sapphire/OPL #513

Merged
merged 2 commits into from
Nov 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion docs/dapp/sapphire/guide.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,10 @@ state encryption key from the Oasis key manager. Both the keys and values of the
items stored in state are encrypted, but the size of either is *not* hidden. You
app may need to pad state items to a constant length, or use other obfuscation.
Observers may also be able to infer computation based on storage access patterns,
so you might need to obfuscate that, too.
so you may need to obfuscate that, too. See [Security chapter] for more
recommendations.

[Security chapter]: ./security.md#storage-access-patterns

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

Expand Down
116 changes: 116 additions & 0 deletions docs/dapp/sapphire/security.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
---
description: "Secure dApps: Recipes for Confidentiality"
---

# Security

This page is an ongoing work in progress to support confidential smart contract
development. At the moment we address safeguarding storage variable access
patterns and provide best practices for more secure orderings of error checking
to prevent leaking contract state.

## Storage Access Patterns

aefhm marked this conversation as resolved.
Show resolved Hide resolved
You can use a tool such as [hardhat-tracer] to examine the base EVM state
transitions under the hood.

```shell npm2yarn
npm install -D hardhat-tracer
```

and add `hardhat-tracer` to your `config.ts` file,

```typescript
import "hardhat-tracer"
```

in order to test and show call traces.

```shell
npx hardhat test --vvv --opcodes SSTORE,SLOAD
```

You can also trace a particular transaction, once you know its hash.

```shell
npx hardhat trace --hash 0xTransactionHash
```

For both [gas] usage and confidentiality purposes, we **recommend using
non-unique data size**. E.g. 64-byte value will still be distinct from a
128-byte value.

:::caution Inference based on access patterns

`SSTORE` keys from one transaction may be linked to `SLOAD` keys of another
transaction.

:::

## Order of Operations

When handling errors, gas usage patterns not only can reveal the code path
taken, **but sometimes the balance of a user as well** (in the case of a diligent
attacker using binary search).

```solidity
function transferFrom(address who, address to, uint amount)
external
{
require( balances[who] >= amount );
require( allowances[who][msg.sender] >= amount );
// ...
}
aefhm marked this conversation as resolved.
Show resolved Hide resolved
```

Modifying the order of error checking can prevent the accidental disclosure of
balance information in the example above.

```solidity
function transferFrom(address who, address to, uint amount)
external
{
require( allowances[who][msg.sender] >= amount );
require( balances[who] >= amount );
// ...
}
aefhm marked this conversation as resolved.
Show resolved Hide resolved
```

## Gas Padding

To prevent leaking information about a particular transaction, Sapphire
provides a [precompile] for dApp developers to **pad the amount of gas used
in a transaction**.

```solidity
contract GasExample {
bytes32 tmp;

function constantMath(bool doMath, uint128 padGasAmount) external {
if (doMath) {
bytes32 x;

for (uint256 i = 0; i < 100; i++) {
x = keccak256(abi.encodePacked(x, tmp));
}

tmp = x;
}

Sapphire.padGas(padGasAmount);
}
}
```

Both contract calls below should use the same amount of gas. Sapphire also
provides the precompile to return the gas [used] by the current transaction.

```typescript
await contract.constantMath(true, 100000);
await contract.constantMath(false, 100000);
```

[gas]: https://docs.soliditylang.org/en/latest/internals/layout_in_storage.html
[hardhat-tracer]: https://www.npmjs.com/package/hardhat-tracer
[precompile]: https://api.docs.oasis.io/sol/sapphire-contracts/contracts/Sapphire.sol/library.Sapphire.html#padgas
[used]: https://api.docs.oasis.io/sol/sapphire-contracts/contracts/Sapphire.sol/library.Sapphire.html#gasused
1 change: 1 addition & 0 deletions sidebarDapp.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const sidebars = {
'dapp/sapphire/gasless',
'dapp/sapphire/precompiles',
'dapp/sapphire/addresses',
'dapp/sapphire/security',
aefhm marked this conversation as resolved.
Show resolved Hide resolved
{
type: 'link',
label: 'TypeScript API',
Expand Down
Loading