@nori-zk/o1js-zk-utils
Version:
o1js-zk-utils supporting Nori Bridge
114 lines • 5.3 kB
JavaScript
import { Bytes, Field, Poseidon, Struct, UInt8 } from 'o1js';
import { Bytes20, Bytes32 } from '../types.js';
export function dummyAddress(i) {
const arr = new Uint8Array(20).fill(0);
const view = new DataView(arr.buffer);
view.setUint32(16, i, true); // little-endian, last 4 bytes
return Bytes20.from(arr);
}
export function dummyAttestation(i) {
const arr = new Uint8Array(32).fill(0);
const view = new DataView(arr.buffer);
view.setUint32(0, i, true); // little-endian, first 4 bytes
return Bytes32.from(arr);
}
export function dummyValue(i) {
const arr = new Uint8Array(32).fill(0);
const view = new DataView(arr.buffer);
view.setUint32(0, i, true); // little-endian, first 4 bytes
return Bytes32.from(arr);
}
export function nonProvableStorageSlotLeafHash(addr, attestation, value) {
const addrBytes = addr.toBytes();
const attBytes = attestation.toBytes();
const valueBytes = value.toBytes();
const firstFieldBytes = new Uint8Array(32);
firstFieldBytes.set(addrBytes, 0); // first 20 bytes from address
firstFieldBytes[20] = attBytes[0]; // first byte from attBytes
firstFieldBytes[21] = valueBytes[0]; // first byte from value
const secondFieldBytes = new Uint8Array(32);
secondFieldBytes.set(attBytes.slice(1, 32), 0); // remaining 31 bytes from attBytes
const thirdFieldBytes = new Uint8Array(32);
thirdFieldBytes.set(valueBytes.slice(1, 32), 0); // remaining 31 bytes from value
/*console.log('firstFieldBytes', firstFieldBytes);
console.log('secondFieldBytes', secondFieldBytes);
console.log('thirdFieldBytes', thirdFieldBytes);*/
const firstField = Field.fromBytes(Array.from(firstFieldBytes));
const secondField = Field.fromBytes(Array.from(secondFieldBytes));
const thirdField = Field.fromBytes(Array.from(thirdFieldBytes));
/*console.log('firstField', firstField.toBigInt().toString());
console.log('secondField', secondField.toBigInt().toString());
console.log('thirdField', thirdField.toBigInt().toString());*/
return Poseidon.hash([firstField, secondField, thirdField]);
}
// Build leaf hashes from pairs of (Address, FixedBytes32)
export function buildLeavesNonProvable(triples) {
return triples.map(([addr, att, val]) => nonProvableStorageSlotLeafHash(addr, att, val));
}
export class ProvableLeafObject extends Struct({
address: Bytes20.provable,
attestation: Bytes32.provable,
value: Bytes32.provable,
}) {
}
export function provableLeafContentsHash(leafContents) {
const addressBytes = leafContents.address.bytes; // UInt8[]
const attBytes = leafContents.attestation.bytes; // UInt8[]
const valueBytes = leafContents.value.bytes; // UInt8[]
/*Provable.asProver(() => {
Provable.log('addressBytes', addressBytes);
Provable.log('attBytes', attBytes);
Provable.log('valueBytes', valueBytes);
});*/
// We want 20 bytes from addrBytes (+ 1 byte from attBytes and 1 byte from valueBytes), remaining 31 bytes from attBytes, remaining 31 bytes from valueBytes
// firstFieldBytes: 20 bytes from addressBytes + 1 byte from attBytes and 1 byte from valueBytes
const firstFieldBytes = [];
for (let i = 0; i < 20; i++) {
firstFieldBytes.push(addressBytes[i]);
}
firstFieldBytes.push(attBytes[0]);
firstFieldBytes.push(valueBytes[0]);
for (let i = 22; i < 32; i++) {
firstFieldBytes.push(UInt8.zero); // static pad to 32
}
// secondFieldBytes: remaining 31 bytes from attBytes (1 to 31)
const secondFieldBytes = [];
for (let i = 1; i < 32; i++) {
secondFieldBytes.push(attBytes[i]);
}
// already 31 elements; add 1 zero to reach 32
secondFieldBytes.push(UInt8.zero);
// secondFieldBytes: remaining 31 bytes from valueBytes (1 to 31)
const thirdFieldBytes = [];
for (let i = 1; i < 32; i++) {
thirdFieldBytes.push(valueBytes[i]);
}
// already 31 elements; add 1 zero to reach 32
thirdFieldBytes.push(UInt8.zero);
// Convert UInt8[] to Bytes (provable bytes)
const firstBytes = Bytes.from(firstFieldBytes);
const secondBytes = Bytes.from(secondFieldBytes);
const thirdBytes = Bytes.from(thirdFieldBytes);
// Extract the first field (there should only ever be one here)
/*Provable.asProver(() => {
Provable.log('firstBytes.toFields()', firstBytes.toFields());
Provable.log('secondBytes.toFields()', secondBytes.toFields());
Provable.log('thirdBytes.toFields()', thirdBytes.toFields());
});*/
let firstField = new Field(0);
let secondField = new Field(0);
let thirdField = new Field(0);
// Little endian
for (let i = 31; i >= 0; i--) {
firstField = firstField.mul(256).add(firstBytes.bytes[i].value);
secondField = secondField.mul(256).add(secondBytes.bytes[i].value);
thirdField = thirdField.mul(256).add(thirdBytes.bytes[i].value);
}
/*Provable.asProver(() => {
Provable.log('(provable)firstField', firstField.toBigInt());
Provable.log('(provable)secondField', secondField.toBigInt());
Provable.log('(provable)thirdField', thirdField.toBigInt());
});*/
return Poseidon.hash([firstField, secondField, thirdField]);
}
//# sourceMappingURL=testUtils.js.map