l1-lottery-contracts
Version:
This repo contains smart contracts and related scripts for ZkNoid L1 Lottery proposed [here](https://forums.minaprotocol.com/t/zknoid-l1-lottery/6269)
114 lines • 4.62 kB
JavaScript
import { Bool, Field, MerkleTree, MerkleWitness, Poseidon, Provable, Struct, } from 'o1js';
// Copied from https://github.com/o1-labs/o1js/blob/main/src/lib/provable/merkle-map.ts
// With a change of merkle tree height.
const LENGTH20 = 20;
export class MerkleMap20Witness extends Struct({
isLefts: Provable.Array(Bool, LENGTH20 - 1),
siblings: Provable.Array(Field, LENGTH20 - 1),
}) {
/**
* computes the merkle tree root for a given value and the key for this witness
* @param value The value to compute the root for.
* @returns A tuple of the computed merkle root, and the key that is connected to the path updated by this witness.
*/
computeRootAndKey(value) {
let hash = value;
const isLeft = this.isLefts;
const siblings = this.siblings;
let key = Field(0);
for (let i = 0; i < LENGTH20 - 1; i++) {
const left = Provable.if(isLeft[i], hash, siblings[i]);
const right = Provable.if(isLeft[i], siblings[i], hash);
hash = Poseidon.hash([left, right]);
const bit = Provable.if(isLeft[i], Field(0), Field(1));
key = key.mul(2).add(bit);
}
return [hash, key];
}
/**
* Computes the merkle tree root for a given value and the key for this witness
* @param value The value to compute the root for.
* @returns A tuple of the computed merkle root, and the key that is connected to the path updated by this witness.
*/
computeRootAndKeyV2(value) {
// Check that the computed key is less than 2^254, in order to avoid collisions since the Pasta field modulus is smaller than 2^255
this.isLefts[0].assertTrue();
let hash = value;
const isLeft = this.isLefts;
const siblings = this.siblings;
let key = Field(0);
for (let i = 0; i < LENGTH20 - 1; i++) {
const left = Provable.if(isLeft[i], hash, siblings[i]);
const right = Provable.if(isLeft[i], siblings[i], hash);
hash = Poseidon.hash([left, right]);
const bit = Provable.if(isLeft[i], Field(0), Field(1));
key = key.mul(2).add(bit);
}
return [hash, key];
}
}
export class MerkleMap20 {
/**
* Creates a new, empty Merkle Map.
* @returns A new MerkleMap
*/
constructor() {
this.tree = new MerkleTree(LENGTH20);
}
_keyToIndex(key) {
// console.log('Key: ', key.toString());
// the bit map is reversed to make reconstructing the key during proving more convenient
// let bits = BinableFp.toBits(key.toBigInt()).reverse(); // original version
let bits = key.toBits(LENGTH20 - 1).reverse(); // Can we just use BinableFP? It is used for constants anyway
// console.log(bits.map((bit) => bit.toString()));
// console.log(bits.map((bit) => bit.toField().toString()));
let n = 0n;
for (let i = bits.length - 1; i >= 0; i--) {
n = (n << 1n) | BigInt(bits[i].toField().toString());
}
return n;
}
/**
* Sets a key of the merkle map to a given value.
* @param key The key to set in the map.
* @param value The value to set.
*/
set(key, value) {
const index = this._keyToIndex(key);
this.tree.setLeaf(index, value);
}
/**
* Returns a value given a key. Values are by default Field(0).
* @param key The key to get the value from.
* @returns The value stored at the key.
*/
get(key) {
const index = this._keyToIndex(key);
return this.tree.getNode(0, index);
}
/**
* Returns the root of the Merkle Map.
* @returns The root of the Merkle Map.
*/
getRoot() {
return this.tree.getRoot();
}
/**
* Returns a circuit-compatible witness (also known as [Merkle Proof or Merkle Witness](https://computersciencewiki.org/index.php/Merkle_proof)) for the given key.
* @param key The key to make a witness for.
* @returns A MerkleMapWitness, which can be used to assert changes to the MerkleMap, and the witness's key.
*/
getWitness(key) {
const index = this._keyToIndex(key);
class MyMerkleWitness extends MerkleWitness(LENGTH20) {
}
const witness = new MyMerkleWitness(this.tree.getWitness(index));
// console.log('Witness in getWitness: ');
// console.log(witness);
return new MerkleMap20Witness({
isLefts: witness.isLeft,
siblings: witness.path,
});
}
}
//# sourceMappingURL=CustomMerkleMap.js.map