diff --git a/docs/dapp/sapphire/guide.mdx b/docs/dapp/sapphire/guide.mdx index e1bc50e82b..b7689b5aae 100644 --- a/docs/dapp/sapphire/guide.mdx +++ b/docs/dapp/sapphire/guide.mdx @@ -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 diff --git a/docs/dapp/sapphire/security.md b/docs/dapp/sapphire/security.md index 702bf2f4bc..e9f869e050 100644 --- a/docs/dapp/sapphire/security.md +++ b/docs/dapp/sapphire/security.md @@ -1,18 +1,21 @@ --- -description: Security recommendations for Sapphire +description: "Secure dApps: Recipes for Confidentiality" --- # Security -Work in Progress +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 I/O patterns +## Storage Access Patterns -You can also use a tool such as [hardhat-tracer] to examine the base EVM state +You can use a tool such as [hardhat-tracer] to examine the base EVM state transitions under the hood. -```shell -pnpm add -D hardhat-tracer +```shell npm2yarn +npm install -D hardhat-tracer ``` and add `hardhat-tracer` to your `config.ts` file, @@ -27,16 +30,17 @@ in order to test and show call traces. npx hardhat test --vvv --opcodes SSTORE,SLOAD ``` -You can also trace a particular transaction. +You can also trace a particular transaction, once you know its hash. ```shell npx hardhat trace --hash 0xTransactionHash ``` -For both [gas] usage and confidentiality, non-unique data sizes are -recommended. E.g. 64 byte value will still be distinct from a 128 byte value. +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 of Related Transactions +:::caution Inference based on access patterns `SSTORE` keys from one transaction may be linked to `SLOAD` keys of another transaction. @@ -45,8 +49,8 @@ transaction. ## Order of Operations -With regards to 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 +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 @@ -55,6 +59,7 @@ function transferFrom(address who, address to, uint amount) { require( balances[who] >= amount ); require( allowances[who][msg.sender] >= amount ); + // ... } ``` @@ -67,8 +72,45 @@ function transferFrom(address who, address to, uint amount) { require( allowances[who][msg.sender] >= amount ); require( balances[who] >= amount ); + // ... } ``` +## 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 \ No newline at end of file +[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