UNPKG

@nori-zk/mina-token-bridge

Version:

A Mina zk-program contract allowing users to mint tokens on Nori Bridge.

114 lines 6.95 kB
import { buildContractDepositLeaves, ContractDeposit, ContractDepositAttestor, ContractDepositAttestorInput, getContractDepositWitness, NodeProofLeft, } from '@nori-zk/o1js-zk-utils'; import { computeMerkleTreeDepthAndSize, decodeConsensusMptProof, EthInput, EthVerifier, foldMerkleLeft, getMerkleZeros, } from '@nori-zk/o1js-zk-utils'; import { Bytes20, Bytes32 } from '@nori-zk/o1js-zk-utils'; import { UInt64 } from 'o1js'; export async function compileDepositAttestationPreRequisites() { console.time('ContractDepositAttestor compile'); const { verificationKey: contractDepositAttestorVerificationKey } = await ContractDepositAttestor.compile({ forceRecompile: true }); console.timeEnd('ContractDepositAttestor compile'); console.log(`ContractDepositAttestor contract compiled vk: '${contractDepositAttestorVerificationKey.hash}'.`); console.time('EthVerifier compile'); const { verificationKey: ethVerifierVerificationKey } = await EthVerifier.compile({ forceRecompile: true }); console.timeEnd('EthVerifier compile'); console.log(`EthVerifier compiled vk: '${ethVerifierVerificationKey.hash}'.`); } async function proofConversionServiceRequest(depositBlockNumber, domain = 'https://pcs.nori.it.com') { const fetchResponse = await fetch(`${domain}/converted-consensus-mpt-proofs/${depositBlockNumber}`); console.log('fetchResponse GET', fetchResponse); const json = await fetchResponse.json(); console.log('parsedjson', json, typeof json); if ('error' in json) throw new Error(json.error); return json; } async function fetchContractWindowSlotProofs(depositBlockNumber) { console.log(`Fetching proof bundle for deposit with block number: ${depositBlockNumber}`); console.time('proofConversionServiceRequest'); const { consensusMPTProof: { proof: consensusMPTProofProof, contract_storage_slots: consensusMPTProofContractStorageSlots, }, consensusMPTProofVerification: consensusMPTProofVerification, } = await proofConversionServiceRequest(depositBlockNumber); console.timeEnd('proofConversionServiceRequest'); console.log('consensusMPTProofVerification, consensusMPTProofProof, consensusMPTProofContractStorageSlots', consensusMPTProofVerification, consensusMPTProofProof, consensusMPTProofContractStorageSlots); return { consensusMPTProofProof, consensusMPTProofContractStorageSlots, consensusMPTProofVerification, }; } export async function computeDepositAttestation(depositBlockNumber, ethAddressLowerHex, attestationBEHex) { const { consensusMPTProofProof, consensusMPTProofContractStorageSlots, consensusMPTProofVerification, } = await fetchContractWindowSlotProofs(depositBlockNumber); // Find deposit console.log(`Finding deposit within bundle.consensusMPTProof.contract_storage_slots`); const paddedConsensusMPTProofContractStorageSlots = consensusMPTProofContractStorageSlots.map((slot) => { return { //prettier-ignore slot_key_address: `0x${slot.slot_key_address.slice(2).padStart(40, '0')}`, //prettier-ignore slot_nested_key_attestation_hash: `0x${slot.slot_nested_key_attestation_hash.slice(2).padStart(64, '0')}`, //prettier-ignore value: `0x${slot.value.slice(2).padStart(64, '0')}`, }; }); const depositIndex = paddedConsensusMPTProofContractStorageSlots.findIndex((slot) => slot.slot_key_address === ethAddressLowerHex && slot.slot_nested_key_attestation_hash === attestationBEHex); if (depositIndex === -1) throw new Error(`Could not find deposit index with attestationBEHex: ${attestationBEHex}, ethAddressLowerHex:${ethAddressLowerHex} in slots ${JSON.stringify(paddedConsensusMPTProofContractStorageSlots, null, 4)}`); console.log(`Found deposit within bundle.consensusMPTProof.contract_storage_slots`); const despositSlotRaw = paddedConsensusMPTProofContractStorageSlots[depositIndex]; const totalDespositedValue = despositSlotRaw.value; // this is a hex // would be nice here to print a bigint console.log(`Total deposited to date (hex): ${totalDespositedValue}`); // Build contract storage slots (to be hashed) const contractStorageSlots = paddedConsensusMPTProofContractStorageSlots.map((slot) => { const addr = slot.slot_key_address; const attr = slot.slot_nested_key_attestation_hash; const value = slot.value; console.log({ addr, attr, value }); return new ContractDeposit({ address: Bytes20.fromHex(addr.slice(2)), attestationHash: Bytes32.fromHex(attr.slice(2)), value: Bytes32.fromHex(value.slice(2)) }); }); // Select our deposit const depositSlot = contractStorageSlots[depositIndex]; // Build deposit witness // Build leaves console.time('buildContractDepositLeaves'); const leaves = buildContractDepositLeaves(contractStorageSlots); console.timeEnd('buildContractDepositLeaves'); // Compute path console.time('getContractDepositWitness'); const path = getContractDepositWitness([...leaves], depositIndex); console.timeEnd('getContractDepositWitness'); // Compute root const { depth, paddedSize } = computeMerkleTreeDepthAndSize(leaves.length); console.time('foldMerkleLeft'); const rootHash = foldMerkleLeft(leaves, paddedSize, depth, getMerkleZeros(depth)); console.timeEnd('foldMerkleLeft'); console.log(`Computed Merkle root: ${rootHash.toString()}`); // Build ZK input const depositProofInput = new ContractDepositAttestorInput({ rootHash, path, index: UInt64.from(depositIndex), value: depositSlot, }); console.log('Prepared ContractDepositAttestorInput'); // Prove deposit console.time('ContractDepositAttestor.compute'); // Retype because of erasure at package level :( const depositAttestationProof = (await ContractDepositAttestor.compute(depositProofInput)).proof; console.timeEnd('ContractDepositAttestor.compute'); // Verify consensus mpt proof console.log('Loaded sp1PlonkProof and conversionOutputProof'); const ethVerifierInput = new EthInput(decodeConsensusMptProof(consensusMPTProofProof)); console.log('Decoded EthInput from MPT proof'); console.log('Parsing raw SP1 proof using NodeProofLeft.fromJSON'); const rawProof = await NodeProofLeft.fromJSON(consensusMPTProofVerification.proofData); console.log('Parsed raw SP1 proof using NodeProofLeft.fromJSON'); console.log('Computing EthVerifier'); console.time('EthVerifier.compute'); const ethVerifierProof = (await EthVerifier.compute(ethVerifierInput, rawProof)).proof; console.timeEnd('EthVerifier.compute'); console.log(`All proofs built needed to compute mint proof!`); return { depositAttestationProof, ethVerifierProof, despositSlotRaw }; } //# sourceMappingURL=depositAttestation.js.map