UNPKG

@nori-zk/ethprocessor

Version:

zkApp for verifying SP1 Helios Nori proof and storing latest execution state root on Mina

175 lines 9.32 kB
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; import { Field, SmartContract, State, method, state, Poseidon, UInt64, PublicKey, Permissions, Provable, assert, AccountUpdate, } from 'o1js'; // VerificationKey must be a value import for @method decorator runtime validation // eslint-disable-next-line @typescript-eslint/consistent-type-imports import { VerificationKey } from 'o1js'; import { EthProof, Bytes32, Bytes32FieldPair } from '@nori-zk/o1js-zk-utils'; export class EthProofType extends EthProof { } export class EthProcessor extends SmartContract { constructor() { super(...arguments); this.admin = State(); this.verifiedStateRoot = State(); // todo make PackedString this.latestHead = State(); this.latestHeliusStoreInputHashHighByte = State(); this.latestHeliusStoreInputHashLowerBytes = State(); this.latestVerifiedContractDepositsRootHighByte = State(); this.latestVerifiedContractDepositsRootLowerBytes = State(); } //todo // events = { 'executionStateRoot-set': Bytes32.provable };//todo change type, if events even possible init() { // Init smart contract state (all zeros) super.init(); // Set account permissions this.account.permissions.set({ ...Permissions.default(), // Allow VK updates setVerificationKey: Permissions.VerificationKey.proofDuringCurrentVersion(), }); } async ensureAdminSignature() { const admin = await Provable.witnessAsync(PublicKey, async () => { let pk = await this.admin.fetch(); assert(pk !== undefined, 'could not fetch admin public key'); return pk; }); Provable.asProver(() => { Provable.log('ensureAdminSignature', this.admin.get().toBase58(), admin.toBase58()); }); this.admin.requireEquals(admin); return AccountUpdate.createSigned(admin); } async setVerificationKey(vk) { await this.ensureAdminSignature(); this.account.verificationKey.set(vk); } async initialize(adminPublicKey, newStoreHash) { const isInitialized = this.account.provedState.getAndRequireEquals(); isInitialized.assertFalse('EthProcessor has already been initialized!'); this.admin.set(adminPublicKey); // Set initial state (TODO set these to real values!) this.latestHead.set(UInt64.from(0)); this.verifiedStateRoot.set(Field(1)); // Set inital state of store hash. // await this.updateStoreHash(newStoreHash); // Reintroduce this instead of the immediate below when we can // verify that this.admin.getAndRequireEquals() == adminPublicKey immediately after this.admin.set(adminPublicKey); this.latestHeliusStoreInputHashHighByte.set(newStoreHash.highByteField); this.latestHeliusStoreInputHashLowerBytes.set(newStoreHash.lowerBytesField); } async updateStoreHash(newStoreHash) { await this.ensureAdminSignature(); this.latestHeliusStoreInputHashHighByte.set(newStoreHash.highByteField); this.latestHeliusStoreInputHashLowerBytes.set(newStoreHash.lowerBytesField); } async update(ethProof) { const proofHead = ethProof.publicInput.outputSlot; const executionStateRoot = ethProof.publicInput.executionStateRoot; const currentSlot = this.latestHead.getAndRequireEquals(); const newStoreHash = Bytes32FieldPair.fromBytes32(ethProof.publicInput.outputStoreHash); Provable.asProver(() => { Provable.log('Proof input store hash values were:'); Provable.log(ethProof.publicInput.outputStoreHash.bytes[0].value); Provable.log(ethProof.publicInput.outputStoreHash.bytes .slice(1, 33) .map((b) => b.value)); Provable.log('Public outputs created:', newStoreHash.highByteField, newStoreHash.lowerBytesField); }); Provable.asProver(() => { Provable.log('Current slot', currentSlot); }); const prevStoreHash = Bytes32FieldPair.fromBytes32(ethProof.publicInput.inputStoreHash); // Verification of the previous store hash higher byte. prevStoreHash.highByteField.assertEquals(this.latestHeliusStoreInputHashHighByte.getAndRequireEquals(), "The latest transition proofs' input helios store hash higher byte, must match the contracts' helios store hash higher byte."); Provable.asProver(() => { Provable.log('ethProof.prevStoreHashHighByteField vs this.latestHeliusStoreInputHashHighByte', prevStoreHash.highByteField.toString(), this.latestHeliusStoreInputHashHighByte.get().toString()); }); // Verification of previous store hash lower bytes. prevStoreHash.lowerBytesField.assertEquals(this.latestHeliusStoreInputHashLowerBytes.getAndRequireEquals(), "The latest transition proofs' input helios store hash lower bytes, must match the contracts' helios store hash lower bytes."); Provable.asProver(() => { Provable.log('ethProof.prevStoreHashLowerBytesField vs this.latestHeliusStoreInputHashLowerBytes', prevStoreHash.lowerBytesField.toString(), this.latestHeliusStoreInputHashLowerBytes.get().toString()); }); // Verification of slot progress. Moved to the bottom to allow us to test hash mismatches do indeed yield validation errors. proofHead.assertGreaterThan(currentSlot, 'Proof head must be greater than current head.'); // Verification that next sync commitee is non zero (could brick the bridge head otherwise) let nextSyncCommitteeZeroAcc = new Field(0); for (let i = 0; i < 32; i++) { nextSyncCommitteeZeroAcc = nextSyncCommitteeZeroAcc.add(ethProof.publicInput.nextSyncCommitteeHash.bytes[i].value); } nextSyncCommitteeZeroAcc.assertNotEquals(new Field(0)); // Verify transition proof. ethProof.verify(); // Pack the verifiedContractDepositsRoot into a pair of fields const verifiedContractDepositsRoot = Bytes32FieldPair.fromBytes32(ethProof.publicInput.verifiedContractDepositsRoot); // Update contract values this.latestHead.set(proofHead); this.verifiedStateRoot.set(Poseidon.hashPacked(Bytes32.provable, executionStateRoot)); this.latestHeliusStoreInputHashHighByte.set(newStoreHash.highByteField); this.latestHeliusStoreInputHashLowerBytes.set(newStoreHash.lowerBytesField); this.latestVerifiedContractDepositsRootHighByte.set(verifiedContractDepositsRoot.highByteField); this.latestVerifiedContractDepositsRootLowerBytes.set(verifiedContractDepositsRoot.lowerBytesField); } } __decorate([ state(PublicKey), __metadata("design:type", Object) ], EthProcessor.prototype, "admin", void 0); __decorate([ state(Field), __metadata("design:type", Object) ], EthProcessor.prototype, "verifiedStateRoot", void 0); __decorate([ state(UInt64), __metadata("design:type", Object) ], EthProcessor.prototype, "latestHead", void 0); __decorate([ state(Field), __metadata("design:type", Object) ], EthProcessor.prototype, "latestHeliusStoreInputHashHighByte", void 0); __decorate([ state(Field), __metadata("design:type", Object) ], EthProcessor.prototype, "latestHeliusStoreInputHashLowerBytes", void 0); __decorate([ state(Field), __metadata("design:type", Object) ], EthProcessor.prototype, "latestVerifiedContractDepositsRootHighByte", void 0); __decorate([ state(Field), __metadata("design:type", Object) ], EthProcessor.prototype, "latestVerifiedContractDepositsRootLowerBytes", void 0); __decorate([ method, __metadata("design:type", Function), __metadata("design:paramtypes", [VerificationKey]), __metadata("design:returntype", Promise) ], EthProcessor.prototype, "setVerificationKey", null); __decorate([ method, __metadata("design:type", Function), __metadata("design:paramtypes", [PublicKey, Bytes32FieldPair]), __metadata("design:returntype", Promise) ], EthProcessor.prototype, "initialize", null); __decorate([ method, __metadata("design:type", Function), __metadata("design:paramtypes", [Bytes32FieldPair]), __metadata("design:returntype", Promise) ], EthProcessor.prototype, "updateStoreHash", null); __decorate([ method, __metadata("design:type", Function), __metadata("design:paramtypes", [EthProofType]), __metadata("design:returntype", Promise) ], EthProcessor.prototype, "update", null); //# sourceMappingURL=ethProcessor.js.map