Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/kevincharm/sparse-merkle-tree
Optimised SMT implementation in Solidity & accompanying JS lib
https://github.com/kevincharm/sparse-merkle-tree
cryptography ethereum evm merkle-tree solidity sparse-merkle-tree
Last synced: about 4 hours ago
JSON representation
Optimised SMT implementation in Solidity & accompanying JS lib
- Host: GitHub
- URL: https://github.com/kevincharm/sparse-merkle-tree
- Owner: kevincharm
- License: mit
- Created: 2023-07-31T03:43:48.000Z (over 1 year ago)
- Default Branch: master
- Last Pushed: 2023-08-25T13:18:21.000Z (about 1 year ago)
- Last Synced: 2024-10-29T13:55:24.333Z (10 days ago)
- Topics: cryptography, ethereum, evm, merkle-tree, solidity, sparse-merkle-tree
- Language: TypeScript
- Homepage:
- Size: 131 KB
- Stars: 1
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Sparse Merkle Tree
Sparse Merkle Tree (SMT) implementation in Solidity with accompanying JavaScript library. This SMT implementation uses `bytes32(0)` as the empty node value so that paths representing empty subtrees in the Merkle proof may be omitted. This proof compression technique is described by Vitalik in [Optimizing sparse Merkle trees](https://ethresear.ch/t/optimizing-sparse-merkle-trees/3751).
## Installation
```sh
yarn add @kevincharm/sparse-merkle-tree @noble/hashes
````@noble/hashes` is required as a peer dependency for the JS library.
## Onchain usage
Below is an example contract that keeps track of only the current SMT root, and allows updating any leaf with a new value given the old leaf value and the Merkle proof.
```solidity
import { SparseMerkleTree } from '@kevincharm/sparse-merkle-tree/contracts/SparseMerkleTree.sol';/// @notice Example SparseMerkleTree consumer
contract SMTConsumer {
/// @notice Depth of Merkle tree
uint16 immutable treeDepth;
/// @notice Current Merkle root
bytes32 public root;/// @param treeDepth_ The tree depth determines the capacity of the tree,
/// and must not change. `capacity = 2**treeDepth`
constructor(uint16 treeDepth_) {
treeDepth = treeDepth_;
}function computeRoot(
bytes32 leaf,
uint256 index,
uint256 enables,
bytes32[] calldata path
) public view returns (bytes32) {
return SparseMerkleTree.computeRoot(treeDepth, leaf, index, enables, path);
}/// @notice Update a leaf in the tree, producing a new root.
/// @param newLeaf New value of leaf
/// @param oldLeaf Current leaf
/// @param index Index of leaf in list; determines hashing direction for
/// proof path elements
/// @param enables Each bit determines whether a proof path element should
/// be used (1) or a zero-value hash (0)
/// @param siblings Proof path; elements only need to be defined for non-zero
/// siblings
function updateRoot(
bytes32 newLeaf,
bytes32 oldLeaf,
uint256 index,
uint256 enables,
bytes32[] calldata siblings
) public returns (bytes32) {
if (root != computeRoot(oldLeaf, index, enables, siblings)) {
revert InvalidProof(oldLeaf, index, enables, siblings);
}
// Replace with new leaf and compute new root
return (root = computeRoot(newLeaf, index, enables, siblings));
}
}
```## Offchain usage
Below is an example JavaScript snippet that instantiates an SMT, then inserts a new leaf into the SMT, and finally submits the update to a contract using the generated Merkle proofs.
```ts
import { SparseMerkleTreeKV } from '@kevincharm/sparse-merkle-tree'
import { ZeroHash, keccak256, concat, hashMessage, Wallet, Contract } from 'ethers'// Initialise client representation of an empty SMT
const smt = new SparseMerkleTreeKV()// Insert a new (K,V) entry
const key = keccak256(Wallet.createRandom().address)
const value = hashMessage('Fred Fredburger')
const { newLeaf, leaf: oldLeaf, index, enables, siblings } = smt.insert(key, value)
// Connect to the contract that is consuming the SMT library
const smtConsumer = new Contract(/** ... */)
// We update the SMT onchain by providing:
// - The new value of the leaf
// - The proof of membership of the old leaf value
await smtConsumer.updateRoot(newLeaf, oldLeaf, index, enables, siblings)
// The onchain SMT should now be synced with the client-side
assert((await smtConsumer.root()) === smt.root)
```## Disclaimer
This software is unaudited and probably contains bugs. Use at your own risk.
## License
MIT