diff --git a/package-lock.json b/package-lock.json index 7403a5e..30a5a0d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@auxo-dev/auxo-libs", - "version": "1.0.4", + "version": "1.0.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@auxo-dev/auxo-libs", - "version": "1.0.4", + "version": "1.0.5", "license": "Apache-2.0", "dependencies": { "o1js": "1.8.0" diff --git a/package.json b/package.json index 8906c56..3de6eda 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@auxo-dev/auxo-libs", - "version": "1.0.4", + "version": "1.0.5", "description": "", "author": "", "license": "Apache-2.0", diff --git a/src/utils/index.ts b/src/utils/index.ts index c952942..d3d7f22 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -14,7 +14,7 @@ export { FetchedEvents, } from './constants.js'; -export { fromUInt64ToScalar } from './math.js'; +export { divExact, fromUInt64ToScalar, getBitLength } from './math.js'; export { randomAccounts, @@ -32,12 +32,16 @@ export { } from './network.js'; export { - updateActionState, - packNumberArray, - unpackNumberArray, + assertRollupActions, + assertRollupField, + assertRollupFields, buildAssertMessage, + buildInvalidActionMessage, + checkCondition, checkInvalidAction, - requireSignature, + packNumberArray, requireCaller, - checkCondition, + requireSignature, + updateActionState, + unpackNumberArray, } from './zkApp.js'; diff --git a/src/utils/math.ts b/src/utils/math.ts index 0054f22..9cd81fd 100644 --- a/src/utils/math.ts +++ b/src/utils/math.ts @@ -1,7 +1,18 @@ -import { Scalar, UInt64 } from 'o1js'; +import { Bool, Field, Scalar, UInt64 } from 'o1js'; -export { fromUInt64ToScalar }; +export { divExact, fromUInt64ToScalar, getBitLength }; +/** + * @deprecated Use `Scalar.fromField` instead. + */ function fromUInt64ToScalar(number: UInt64): Scalar { return Scalar.fromBits(number.value.toBits()); } + +function getBitLength(N: number): number { + return Math.floor(Math.log2(N)) + 1; +} + +function divExact(a: Field, b: Field): Bool { + return a.div(b).lessThanOrEqual(a); +} diff --git a/src/utils/zkApp.ts b/src/utils/zkApp.ts index f174589..7f20c51 100644 --- a/src/utils/zkApp.ts +++ b/src/utils/zkApp.ts @@ -2,6 +2,7 @@ import { AccountUpdate, Bool, Field, + MerkleList, Provable, PublicKey, SmartContract, @@ -10,14 +11,18 @@ import { } from 'o1js'; export { - updateActionState, - packNumberArray, - unpackNumberArray, + assertRollupActions, + assertRollupField, + assertRollupFields, buildAssertMessage, + buildInvalidActionMessage, + checkCondition, checkInvalidAction, - requireSignature, + packNumberArray, requireCaller, - checkCondition, + requireSignature, + updateActionState, + unpackNumberArray, }; function updateActionState(state: Field, action: Field[][]) { @@ -51,6 +56,14 @@ function buildAssertMessage( return `${circuit}::${method}: ${errorMsg}`; } +function buildInvalidActionMessage( + circuit: string, + method: string, + errorMsg: string +): string { + return `${circuit}::${method}: Skipping invalid action: ${errorMsg}`; +} + function checkInvalidAction(flag: Bool, check: Bool, message?: string) { Provable.witness(Void, () => { if (check.not().toBoolean()) { @@ -82,3 +95,61 @@ function checkCondition(condition: Bool, message?: string) { }); return condition; } + +function assertRollupField( + proofValue: Field, + stateValue: Field, + message?: string +) { + proofValue.assertEquals( + stateValue, + message || 'Incorrect initial rollup value' + ); +} + +function assertRollupFields( + proofValue: Array, + stateValue: Array, + numFields: number +) { + for (let i = 0; i < numFields; i++) { + assertRollupField(proofValue[i], stateValue[i]); + } +} + +function assertRollupActions( + proof: { + initialActionState: Field; + nextActionState: Field; + }, + curActionState: Field, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + actions: MerkleList>, + MAX_ROLLUP_ACTIONS: number, + message?: string +) { + assertRollupField(proof.initialActionState, curActionState); + let checkActionStateExists = Bool(false); + let nextActionState = curActionState; + let iter = actions.startIterating(); + for (let i = 0; i < MAX_ROLLUP_ACTIONS; i++) { + let isEmpty = iter.isAtEnd(); + let merkleActions = iter.next(); + nextActionState = Provable.if( + isEmpty, + nextActionState, + AccountUpdate.Actions.updateSequenceState( + nextActionState, + merkleActions.hash + ) + ); + checkActionStateExists = checkActionStateExists.or( + Provable.if( + isEmpty, + Bool(false), + nextActionState.equals(proof.nextActionState) + ) + ); + } + checkActionStateExists.assertTrue(message || 'Incorrect next rollup state'); +}