From d8d230dd37dab8266da18ca10c4fb972989f5942 Mon Sep 17 00:00:00 2001 From: phn210 Date: Sun, 13 Oct 2024 17:07:49 +0200 Subject: [PATCH] update rollup actions and add math utils --- package-lock.json | 4 +-- package.json | 2 +- src/index.ts | 6 ---- src/utils/index.ts | 7 +++- src/utils/math.ts | 20 +++++++++-- src/utils/utils.test.ts | 75 ++++++++++++++++++++++++++++++++++------- src/utils/zkApp.ts | 18 +++++++--- 7 files changed, 101 insertions(+), 31 deletions(-) diff --git a/package-lock.json b/package-lock.json index 30a5a0d..cc76e72 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@auxo-dev/auxo-libs", - "version": "1.0.5", + "version": "1.0.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@auxo-dev/auxo-libs", - "version": "1.0.5", + "version": "1.0.6", "license": "Apache-2.0", "dependencies": { "o1js": "1.8.0" diff --git a/package.json b/package.json index 3de6eda..8b60887 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@auxo-dev/auxo-libs", - "version": "1.0.5", + "version": "1.0.6", "description": "", "author": "", "license": "Apache-2.0", diff --git a/src/index.ts b/src/index.ts index 8b9c000..f580136 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,9 +1,6 @@ export { ActionMask } from './ActionMask.js'; - export { Bit255 } from './Bit255.js'; - export { CustomScalar } from './CustomScalar.js'; - export { Bit255DynamicArray, BoolDynamicArray, @@ -13,9 +10,6 @@ export { PublicKeyDynamicArray, DynamicArray, } from './DynamicArray.js'; - export { IpfsHash } from './IpfsHash.js'; - export { StaticArray } from './StaticArray.js'; - export * as Utils from './utils/index.js'; diff --git a/src/utils/index.ts b/src/utils/index.ts index d3d7f22..582e858 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -14,7 +14,12 @@ export { FetchedEvents, } from './constants.js'; -export { divExact, fromUInt64ToScalar, getBitLength } from './math.js'; +export { + divExact, + fieldXOR, + fromUInt64ToScalar, + getBitLength, +} from './math.js'; export { randomAccounts, diff --git a/src/utils/math.ts b/src/utils/math.ts index 9cd81fd..4742df1 100644 --- a/src/utils/math.ts +++ b/src/utils/math.ts @@ -1,6 +1,6 @@ -import { Bool, Field, Scalar, UInt64 } from 'o1js'; +import { Bool, Field, Gadgets, Scalar, UInt64 } from 'o1js'; -export { divExact, fromUInt64ToScalar, getBitLength }; +export { divExact, fieldXOR, fromUInt64ToScalar, getBitLength }; /** * @deprecated Use `Scalar.fromField` instead. @@ -10,9 +10,23 @@ function fromUInt64ToScalar(number: UInt64): Scalar { } function getBitLength(N: number): number { - return Math.floor(Math.log2(N)) + 1; + return N == 0 ? 1 : Math.floor(Math.log2(N)) + 1; } function divExact(a: Field, b: Field): Bool { + b.assertNotEquals(Field(0)); return a.div(b).lessThanOrEqual(a); } + +function fieldXOR(a: Field, b: Field): Field { + let a240 = Field.fromBits(a.toBits().slice(0, 240)); + let b240 = Field.fromBits(b.toBits().slice(0, 240)); + let a14 = Field.fromBits(a.toBits().slice(240)); + let b14 = Field.fromBits(b.toBits().slice(240)); + let xor240 = Gadgets.xor(a240, b240, 240); + let xor14 = Gadgets.xor(a14, b14, 14); + return Field.fromBits([ + ...xor240.toBits().slice(0, 240), + ...xor14.toBits().slice(0, 14), + ]); +} diff --git a/src/utils/utils.test.ts b/src/utils/utils.test.ts index 552f54a..45bb12f 100644 --- a/src/utils/utils.test.ts +++ b/src/utils/utils.test.ts @@ -30,21 +30,14 @@ import { } from './network.js'; import { FeePayer, TX_FEE, ZkApp } from './constants.js'; import { getProfiler } from './benchmark.js'; -import { fromUInt64ToScalar } from './math.js'; +import { + divExact, + fieldXOR, + fromUInt64ToScalar, + getBitLength, +} from './math.js'; import { checkInvalidAction, updateActionState } from './zkApp.js'; -describe('Math', () => { - it('Should convert UInt64 to Scalar', async () => { - expect(fromUInt64ToScalar(UInt64.from(0)).toBigInt()).toEqual(0n); - expect(fromUInt64ToScalar(UInt64.from(123456789)).toBigInt()).toEqual( - 123456789n - ); - expect( - fromUInt64ToScalar(UInt64.from(UInt64.MAXINT())).toBigInt() - ).toEqual(UInt64.MAXINT().toBigInt()); - }); -}); - describe('Network', () => { class TestContract extends SmartContract { @state(Field) num = State(); @@ -326,3 +319,59 @@ describe('Network', () => { profiler.store(); }); }); + +describe('Math', () => { + it('Should convert UInt64 to Scalar', async () => { + expect(fromUInt64ToScalar(UInt64.from(0)).toBigInt()).toEqual(0n); + expect(fromUInt64ToScalar(UInt64.from(123456789)).toBigInt()).toEqual( + 123456789n + ); + expect( + fromUInt64ToScalar(UInt64.from(UInt64.MAXINT())).toBigInt() + ).toEqual(UInt64.MAXINT().toBigInt()); + }); + it('Should convert UInt64 to Scalar', async () => { + expect(fromUInt64ToScalar(UInt64.from(0)).toBigInt()).toEqual(0n); + expect(fromUInt64ToScalar(UInt64.from(123456789)).toBigInt()).toEqual( + 123456789n + ); + expect( + fromUInt64ToScalar(UInt64.from(UInt64.MAXINT())).toBigInt() + ).toEqual(UInt64.MAXINT().toBigInt()); + }); + + it('Should get correct bit length', async () => { + expect(getBitLength(0)).toEqual(1); + expect(getBitLength(1)).toEqual(1); + expect(getBitLength(2)).toEqual(2); + expect(getBitLength(3)).toEqual(2); + expect(getBitLength(4)).toEqual(3); + expect(getBitLength(255)).toEqual(8); + expect(getBitLength(256)).toEqual(9); + }); + + it('Should perform exact division', async () => { + expect(divExact(Field(10), Field(2)).toBoolean()).toBe(true); + expect(divExact(Field(10), Field(3)).toBoolean()).toBe(false); + expect(divExact(Field(0), Field(1)).toBoolean()).toBe(true); + expect(() => divExact(Field(1), Field(0)).toBoolean()).toThrow(); + }); + + it('Should perform field XOR', async () => { + expect(fieldXOR(Field(0), Field(0)).toBigInt()).toEqual(0n); + expect(fieldXOR(Field(1), Field(0)).toBigInt()).toEqual(1n); + expect(fieldXOR(Field(1), Field(1)).toBigInt()).toEqual(0n); + expect(fieldXOR(Field(123456789), Field(987654321)).toBigInt()).toEqual( + BigInt(123456789) ^ BigInt(987654321) + ); + let f1 = Field.random(); + let f2 = Field.random(); + expect(fieldXOR(f1, f2).toBigInt()).toEqual( + f1.toBigInt() ^ f2.toBigInt() + ); + expect(fieldXOR(f1, f1).toBigInt()).toEqual(0n); + expect(fieldXOR(fieldXOR(f1, f2), f2).toBigInt()).toEqual( + f1.toBigInt() + ); + }); +}); diff --git a/src/utils/zkApp.ts b/src/utils/zkApp.ts index 7f20c51..7928e5c 100644 --- a/src/utils/zkApp.ts +++ b/src/utils/zkApp.ts @@ -103,17 +103,18 @@ function assertRollupField( ) { proofValue.assertEquals( stateValue, - message || 'Incorrect initial rollup value' + (message || '') + ' incorrect initial rollup value' ); } function assertRollupFields( proofValue: Array, stateValue: Array, - numFields: number + numFields: number, + message?: string ) { for (let i = 0; i < numFields; i++) { - assertRollupField(proofValue[i], stateValue[i]); + assertRollupField(proofValue[i], stateValue[i], message); } } @@ -123,12 +124,13 @@ function assertRollupActions( nextActionState: Field; }, curActionState: Field, + latestActionState: Field, // eslint-disable-next-line @typescript-eslint/no-explicit-any actions: MerkleList>, MAX_ROLLUP_ACTIONS: number, message?: string ) { - assertRollupField(proof.initialActionState, curActionState); + assertRollupField(proof.initialActionState, curActionState, message); let checkActionStateExists = Bool(false); let nextActionState = curActionState; let iter = actions.startIterating(); @@ -151,5 +153,11 @@ function assertRollupActions( ) ); } - checkActionStateExists.assertTrue(message || 'Incorrect next rollup state'); + checkActionStateExists.assertTrue( + (message || '') + ' incorrect next rollup state' + ); + nextActionState.assertEquals( + latestActionState, + (message || '') + ' incorrect action list' + ); }