Skip to content

Instantly share code, notes, and snippets.

@jorpic
Created March 24, 2017 20:04
Show Gist options
  • Save jorpic/2b84d5825f8055e224bc5eff9d7aa294 to your computer and use it in GitHub Desktop.
Save jorpic/2b84d5825f8055e224bc5eff9d7aa294 to your computer and use it in GitHub Desktop.
Generate tree of hashes from seed
// This one (with nested arrays) has a bit cleaner code but less gas-efficient.
pragma solidity ^0.4.8;
contract salttree {
// "0x98fe01c92ff2a2fa282b3aba5f8aead0", 28
// Gas usage: ~42k
function gen(bytes16 root, uint size) returns (bytes16[]) {
bytes16[] memory res = new bytes16[](size);
uint height = log2(size);
bytes16[2][] memory stack = new bytes16[2][](height);
stack[height-1] = split(sha256(root));
uint lvl = height - 1;
for(uint i = 0; i < size; ++i) {
while(lvl > 0) {
uint j = i & (1 << lvl) == 0 ? 0 : 1;
stack[lvl-1] = split(sha256(stack[lvl][j]));
lvl--;
}
res[i] = stack[0][i & 1];
lvl = least_significant_bit(i+1);
}
return res;
}
function log2(uint x) private returns (uint res) {
while(x > 0) {
x >>= 1;
res++;
}
}
// NB. x > 0
function least_significant_bit(uint x) private returns (uint res) {
while(x & 1 == 0) {
x >>= 1;
res++;
}
}
function split(bytes32 x) private returns (bytes16[2]) {
bytes16 left;
bytes16 right;
assembly {
let freemem_pointer := mload(0x40)
mstore(freemem_pointer, x)
left := mload(freemem_pointer)
right := mload(add(freemem_pointer,0x10))
}
return [left, right];
}
}
// This one (with structs) uses less gas compared to the version with nested arrays.
pragma solidity ^0.4.8;
contract salttree {
// "0x98fe01c92ff2a2fa282b3aba5f8aead0", 28
// Gas usage: ~37k
struct bytes16x2 {
bytes16 l;
bytes16 r;
}
function gen(bytes16 root, uint size) returns (bytes16[]) {
bytes16[] memory res = new bytes16[](size);
uint height = log2(size);
bytes16x2[] memory stack = new bytes16x2[](height);
stack[height-1] = split(sha256(root));
uint lvl = height - 1;
for(uint i = 0; i < size; ++i) {
while(lvl > 0) {
var xx = i & (1 << lvl) == 0 ? stack[lvl].l : stack[lvl].r;
stack[lvl-1] = split(sha256(xx));
lvl--;
}
res[i] = i & 1 == 0 ? stack[0].l : stack[0].r;
lvl = least_significant_bit(i+1);
}
return res;
}
function log2(uint x) private returns (uint res) {
while(x > 0) {
x >>= 1;
res++;
}
}
// NB. x > 0
function least_significant_bit(uint x) private returns (uint res) {
while(x & 1 == 0) {
x >>= 1;
res++;
}
}
function split(bytes32 x) private returns (bytes16x2) {
bytes16 left;
bytes16 right;
assembly {
let freemem_pointer := mload(0x40)
mstore(freemem_pointer, x)
left := mload(freemem_pointer)
right := mload(add(freemem_pointer,0x10))
}
return bytes16x2(left, right);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment