Skip to content

Commit

Permalink
refactor(imt.sol): update quinary imt name and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
cedoor committed Oct 5, 2023
1 parent d28b5c6 commit 936486e
Show file tree
Hide file tree
Showing 6 changed files with 315 additions and 347 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {PoseidonT6} from "poseidon-solidity/PoseidonT6.sol";

// Each incremental tree has certain properties and data that will
// be used to add new leaves.
struct QuinIMTData {
struct QuinaryIMTData {
uint256 depth; // Depth of the tree (levels - 1).
uint256 root; // Root hash of the tree.
uint256 numberOfLeaves; // Number of leaves of the tree.
Expand All @@ -14,25 +14,25 @@ struct QuinIMTData {
mapping(uint256 => uint256[5]) lastSubtrees; // Caching these values is essential to efficient appends.
}

/// @title Incremental quin Merkle tree.
/// @title Incremental quinary Merkle tree.
/// @dev The incremental tree allows to calculate the root hash each time a leaf is added, ensuring
/// the integrity of the tree.
library QuinIMT {
uint8 internal constant MAX_DEPTH = 32;
uint256 internal constant SNARK_SCALAR_FIELD =
library QuinaryIMT {
uint8 public constant MAX_DEPTH = 32;
uint256 public constant SNARK_SCALAR_FIELD =
21888242871839275222246405745257275088548364400416034343698204186575808495617;

/// @dev Initializes a tree.
/// @param self: Tree data.
/// @param depth: Depth of the tree.
/// @param zero: Zero value to be used.
function init(
QuinIMTData storage self,
QuinaryIMTData storage self,
uint256 depth,
uint256 zero
) public {
require(zero < SNARK_SCALAR_FIELD, "QuinIMT: leaf must be < SNARK_SCALAR_FIELD");
require(depth > 0 && depth <= MAX_DEPTH, "QuinIMT: tree depth must be between 1 and 32");
require(zero < SNARK_SCALAR_FIELD, "QuinaryIMT: leaf must be < SNARK_SCALAR_FIELD");
require(depth > 0 && depth <= MAX_DEPTH, "QuinaryIMT: tree depth must be between 1 and 32");

self.depth = depth;

Expand Down Expand Up @@ -60,11 +60,11 @@ library QuinIMT {
/// @dev Inserts a leaf in the tree.
/// @param self: Tree data.
/// @param leaf: Leaf to be inserted.
function insert(QuinIMTData storage self, uint256 leaf) public {
function insert(QuinaryIMTData storage self, uint256 leaf) public {
uint256 depth = self.depth;

require(leaf < SNARK_SCALAR_FIELD, "QuinIMT: leaf must be < SNARK_SCALAR_FIELD");
require(self.numberOfLeaves < 5**depth, "QuinIMT: tree is full");
require(leaf < SNARK_SCALAR_FIELD, "QuinaryIMT: leaf must be < SNARK_SCALAR_FIELD");
require(self.numberOfLeaves < 5**depth, "QuinaryIMT: tree is full");

uint256 index = self.numberOfLeaves;
uint256 hash = leaf;
Expand Down Expand Up @@ -102,15 +102,15 @@ library QuinIMT {
/// @param proofSiblings: Array of the sibling nodes of the proof of membership.
/// @param proofPathIndices: Path of the proof of membership.
function update(
QuinIMTData storage self,
QuinaryIMTData storage self,
uint256 leaf,
uint256 newLeaf,
uint256[4][] calldata proofSiblings,
uint8[] calldata proofPathIndices
) public {
require(newLeaf != leaf, "QuinIMT: new leaf cannot be the same as the old one");
require(newLeaf < SNARK_SCALAR_FIELD, "QuinIMT: new leaf must be < SNARK_SCALAR_FIELD");
require(verify(self, leaf, proofSiblings, proofPathIndices), "QuinIMT: leaf is not part of the tree");
require(newLeaf != leaf, "QuinaryIMT: new leaf cannot be the same as the old one");
require(newLeaf < SNARK_SCALAR_FIELD, "QuinaryIMT: new leaf must be < SNARK_SCALAR_FIELD");
require(verify(self, leaf, proofSiblings, proofPathIndices), "QuinaryIMT: leaf is not part of the tree");

uint256 depth = self.depth;
uint256 hash = newLeaf;
Expand Down Expand Up @@ -143,7 +143,7 @@ library QuinIMT {
++i;
}
}
require(updateIndex < self.numberOfLeaves, "QuinIMT: leaf index out of range");
require(updateIndex < self.numberOfLeaves, "QuinaryIMT: leaf index out of range");

self.root = hash;
}
Expand All @@ -154,7 +154,7 @@ library QuinIMT {
/// @param proofSiblings: Array of the sibling nodes of the proof of membership.
/// @param proofPathIndices: Path of the proof of membership.
function remove(
QuinIMTData storage self,
QuinaryIMTData storage self,
uint256 leaf,
uint256[4][] calldata proofSiblings,
uint8[] calldata proofPathIndices
Expand All @@ -169,30 +169,30 @@ library QuinIMT {
/// @param proofPathIndices: Path of the proof of membership.
/// @return True or false.
function verify(
QuinIMTData storage self,
QuinaryIMTData storage self,
uint256 leaf,
uint256[4][] calldata proofSiblings,
uint8[] calldata proofPathIndices
) private view returns (bool) {
require(leaf < SNARK_SCALAR_FIELD, "QuinIMT: leaf must be < SNARK_SCALAR_FIELD");
require(leaf < SNARK_SCALAR_FIELD, "QuinaryIMT: leaf must be < SNARK_SCALAR_FIELD");
uint256 depth = self.depth;
require(
proofPathIndices.length == depth && proofSiblings.length == depth,
"QuinIMT: length of path is not correct"
"QuinaryIMT: length of path is not correct"
);

uint256 hash = leaf;

for (uint8 i = 0; i < depth; ) {
uint256[5] memory nodes;

require(proofPathIndices[i] >= 0 && proofPathIndices[i] < 5, "QuinIMT: path index is not between 0 and 4");
require(proofPathIndices[i] >= 0 && proofPathIndices[i] < 5, "QuinaryIMT: path index is not between 0 and 4");

for (uint8 j = 0; j < 5; ) {
if (j < proofPathIndices[i]) {
require(
proofSiblings[i][j] < SNARK_SCALAR_FIELD,
"QuinIMT: sibling node must be < SNARK_SCALAR_FIELD"
"QuinaryIMT: sibling node must be < SNARK_SCALAR_FIELD"
);

nodes[j] = proofSiblings[i][j];
Expand All @@ -201,7 +201,7 @@ library QuinIMT {
} else {
require(
proofSiblings[i][j - 1] < SNARK_SCALAR_FIELD,
"QuinIMT: sibling node must be < SNARK_SCALAR_FIELD"
"QuinaryIMT: sibling node must be < SNARK_SCALAR_FIELD"
);

nodes[j] = proofSiblings[i][j - 1];
Expand Down
2 changes: 1 addition & 1 deletion packages/imt.sol/contracts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
## Libraries

✔️ [BinaryIMT](https://github.com/privacy-scaling-explorations/zk-kit/blob/main/packages/imt.sol/contracts/BinaryIMT.sol) (Poseidon)\
✔️ [QuinIMT](https://github.com/privacy-scaling-explorations/zk-kit/blob/main/packages/imt.sol/contracts/QuinIMT.sol) (Poseidon)\
✔️ [QuinaryIMT](https://github.com/privacy-scaling-explorations/zk-kit/blob/main/packages/imt.sol/contracts/QuinaryIMT.sol) (Poseidon)\
✔️ [LazyIMT](https://github.com/privacy-scaling-explorations/zk-kit/blob/main/packages/imt.sol/contracts/LazyIMT.sol) (Poseidon)

---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@

pragma solidity ^0.8.0;

import "../QuinIMT.sol";
import "../QuinaryIMT.sol";

contract QuinIMTTest {
QuinIMTData public data;
contract QuinaryIMTTest {
QuinaryIMTData public data;

function init(uint256 depth) external {
QuinIMT.init(data, depth, 0);
QuinaryIMT.init(data, depth, 0);
}

function insert(uint256 leaf) external {
QuinIMT.insert(data, leaf);
QuinaryIMT.insert(data, leaf);
}

function update(
Expand All @@ -21,14 +21,14 @@ contract QuinIMTTest {
uint256[4][] calldata proofSiblings,
uint8[] calldata proofPathIndices
) external {
QuinIMT.update(data, leaf, newLeaf, proofSiblings, proofPathIndices);
QuinaryIMT.update(data, leaf, newLeaf, proofSiblings, proofPathIndices);
}

function remove(
uint256 leaf,
uint256[4][] calldata proofSiblings,
uint8[] calldata proofPathIndices
) external {
QuinIMT.remove(data, leaf, proofSiblings, proofPathIndices);
QuinaryIMT.remove(data, leaf, proofSiblings, proofPathIndices);
}
}
16 changes: 9 additions & 7 deletions packages/imt.sol/tasks/deploy-imt-test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { task, types } from "hardhat/config"
import { PoseidonT3, proxy } from "poseidon-solidity"
import { PoseidonT3, PoseidonT6, proxy } from "poseidon-solidity"

task("deploy:imt-test", "Deploy an IMT contract for testing a library")
.addParam<string>("library", "The name of the library", undefined, types.string)
.addOptionalParam<boolean>("logs", "Print the logs", true, types.boolean)
.setAction(async ({ logs, library: libraryName }, { ethers }): Promise<any> => {
// Deterministically deploy PoseidonT3.
.addOptionalParam<number>("arity", "The arity of the tree", 2, types.int)
.setAction(async ({ logs, library: libraryName, arity }, { ethers }): Promise<any> => {
// Deterministically deploy Poseidon.
const signer = await ethers.getSigner()
const Poseidon = arity === 5 ? PoseidonT6 : PoseidonT3

if ((await ethers.provider.getCode(proxy.address)) === "0x") {
await signer.sendTransaction({
Expand All @@ -16,20 +18,20 @@ task("deploy:imt-test", "Deploy an IMT contract for testing a library")
await ethers.provider.sendTransaction(proxy.tx)
}

if ((await ethers.provider.getCode(PoseidonT3.address)) === "0x") {
if ((await ethers.provider.getCode(Poseidon.address)) === "0x") {
await signer.sendTransaction({
to: proxy.address,
data: PoseidonT3.data
data: Poseidon.data
})
}

if (logs) {
console.info(`PoseidonT3 library has been deployed to: ${PoseidonT3.address}`)
console.info(`Poseidon library has been deployed to: ${Poseidon.address}`)
}

const LibraryFactory = await ethers.getContractFactory(libraryName, {
libraries: {
PoseidonT3: PoseidonT3.address
[`PoseidonT${arity + 1}`]: Poseidon.address
}
})
const library = await LibraryFactory.deploy()
Expand Down
Loading

0 comments on commit 936486e

Please sign in to comment.