diff --git a/src/lib/PackingPlant.ts b/src/lib/PackingPlant.ts
index e61161b..b20906b 100644
--- a/src/lib/PackingPlant.ts
+++ b/src/lib/PackingPlant.ts
@@ -25,32 +25,22 @@ export function PackingPlant = InferProvable>(
static type = provable({ packed: Field }, {});
static l: number = l;
packed: Field;
- aux: Array;
bitSize: bigint = bitSize;
- constructor(packed: Field, aux: Array) {
- if (aux.length > l) {
- throw new Error(
- `Length of aux data is too long, input of size ${aux.length} is larger than max allowed ${l}`
- );
- }
+ constructor(packed: Field) {
super({ packed });
- this.aux = aux;
}
- static toAuxiliary(value?: { packed: Field } | undefined): Array {
- throw new Error('Must implement toAuxiliary');
- return [];
- }
-
- static pack(aux: Array): Field {
+ static pack(unpacked: Array): Field {
throw new Error('Must implement pack');
let f = Field(0);
return f;
}
static unpack(f: Field) {
- return this.toAuxiliary({ packed: f });
+ const unpacked = this.toAuxiliary({ packed: f });
+ f.assertEquals(this.pack(unpacked));
+ return unpacked;
}
assertEquals(other: Packed_) {
@@ -88,19 +78,14 @@ export function MultiPackingPlant<
this.aux = aux;
}
- static toAuxiliary(value?: { packed: Array } | undefined): Array {
- throw new Error('Must implement toAuxiliary');
- return [];
- }
-
static pack(aux: Array): Array {
throw new Error('Must implement pack');
let f = [Field(0)];
return f;
}
- static unpack(fields: Array) {
- return this.toAuxiliary({ packed: fields });
+ static unpack(fields: Array): Array {
+ throw new Error('Must implement pack');
}
assertEquals(other: Packed_) {
diff --git a/src/lib/packed-types/PackedBool.test.ts b/src/lib/packed-types/PackedBool.test.ts
index 6a548b3..3f70691 100644
--- a/src/lib/packed-types/PackedBool.test.ts
+++ b/src/lib/packed-types/PackedBool.test.ts
@@ -1,8 +1,7 @@
import { Bool, Provable } from 'o1js';
-import { PackedBoolFactory } from './PackedBool';
+import { PackedBool } from './PackedBool';
describe('PackedBool', () => {
- class PackedBool extends PackedBoolFactory(254) {}
const booleans = new Array(127).fill([true, false]).flat();
const bools = booleans.map((x) => Bool(x));
describe('Outside of the circuit', () => {
@@ -21,19 +20,10 @@ describe('PackedBool', () => {
});
describe('Provable Properties', () => {
it('#sizeInFields', () => {
- class one extends PackedBoolFactory(1) {}
- class two_five_four extends PackedBoolFactory(254) {}
-
- expect(one.sizeInFields()).toBe(1);
- expect(two_five_four.sizeInFields()).toBe(1);
+ expect(PackedBool.sizeInFields()).toBe(1);
});
});
describe('Defensive Cases', () => {
- it('throws for input >= 255 bools', () => {
- expect(() => PackedBoolFactory(254)).not.toThrow();
- expect(() => PackedBoolFactory(255)).toThrow();
- });
-
it('initalizes with more input than allowed', () => {
const tooMany = [...booleans].concat(false);
@@ -59,10 +49,7 @@ describe('PackedBool', () => {
it('Initializes', () => {
expect(() => {
Provable.runAndCheck(() => {
- const packedBool = new PackedBool(
- outsidePackedBool.packed,
- outsidePackedBool.aux
- );
+ const packedBool = new PackedBool(outsidePackedBool.packed);
PackedBool.check({ packed: packedBool.packed });
});
@@ -71,17 +58,14 @@ describe('PackedBool', () => {
it('#assertEquals', () => {
expect(() => {
Provable.runAndCheck(() => {
- const packedBool = new PackedBool(
- outsidePackedBool.packed,
- outsidePackedBool.aux
- );
+ const packedBool = new PackedBool(outsidePackedBool.packed);
packedBool.assertEquals(outsidePackedBool);
});
}).not.toThrow();
expect(() => {
Provable.runAndCheck(() => {
const fakePacked = outsidePackedBool.packed.add(32);
- const packedBool = new PackedBool(fakePacked, outsidePackedBool.aux);
+ const packedBool = new PackedBool(fakePacked);
packedBool.assertEquals(outsidePackedBool);
});
}).toThrow();
diff --git a/src/lib/packed-types/PackedBool.ts b/src/lib/packed-types/PackedBool.ts
index ad7cdb4..fd50000 100644
--- a/src/lib/packed-types/PackedBool.ts
+++ b/src/lib/packed-types/PackedBool.ts
@@ -1,52 +1,50 @@
import { Field, Provable, Bool } from 'o1js';
import { PackingPlant } from '../PackingPlant.js';
+const L = 254; // 254 1-byte uints fit in one Field
const SIZE_IN_BITS = 1n;
-export function PackedBoolFactory(l: number) {
- class PackedBool_ extends PackingPlant(Bool, l, SIZE_IN_BITS) {
- static toAuxiliary(value?: { packed: Field } | undefined): Array {
- const auxiliary = Provable.witness(Provable.Array(Bool, l), () => {
- let bools_ = new Array(l);
- bools_.fill(0n);
- let packedN;
- if (value && value.packed) {
- packedN = value.packed.toBigInt();
- } else {
- throw new Error('No Packed Value Provided');
- }
- for (let i = 0; i < l; i++) {
- bools_[i] = packedN & ((1n << SIZE_IN_BITS) - 1n);
- packedN >>= SIZE_IN_BITS;
- }
- return bools_.map((x) => Bool.fromJSON(Boolean(x)));
- });
- return auxiliary;
+export class PackedBool extends PackingPlant(Bool, L, SIZE_IN_BITS) {
+ static pack(aux: Array): Field {
+ let f = aux[0].toField();
+ const n = Math.min(aux.length, L);
+ for (let i = 1; i < n; i++) {
+ const c = Field((2n ** SIZE_IN_BITS) ** BigInt(i));
+ f = f.add(aux[i].toField().mul(c));
}
+ return f;
+ }
- static pack(aux: Array): Field {
- let f = aux[0].toField();
- const n = Math.min(aux.length, l);
- for (let i = 1; i < n; i++) {
- const c = Field((2n ** SIZE_IN_BITS) ** BigInt(i));
- f = f.add(aux[i].toField().mul(c));
+ static unpack(f: Field): Bool[] {
+ const unpacked = Provable.witness(Provable.Array(Bool, L), () => {
+ let bools_ = new Array(L);
+ bools_.fill(0n);
+ let packedN;
+ if (f) {
+ packedN = f.toBigInt();
+ } else {
+ throw new Error('No Packed Value Provided');
}
- return f;
- }
+ for (let i = 0; i < L; i++) {
+ bools_[i] = packedN & ((1n << SIZE_IN_BITS) - 1n);
+ packedN >>= SIZE_IN_BITS;
+ }
+ return bools_.map((x) => Bool.fromJSON(Boolean(x)));
+ });
+ return unpacked;
+ }
- static fromAuxiliary(aux: Array): PackedBool_ {
- const packed = PackedBool_.pack(aux);
- return new PackedBool_(packed, aux);
- }
+ static fromBools(bools: Array): PackedBool {
+ const packed = PackedBool.pack(bools);
+ return new PackedBool(packed);
+ }
- static fromBooleans(bigints: Array): PackedBool_ {
- const uint32s = bigints.map((x) => Bool(x));
- return this.fromAuxiliary(uint32s);
- }
+ static fromBooleans(booleans: Array): PackedBool {
+ const bools = booleans.map((x) => Bool(x));
+ return PackedBool.fromBools(bools);
+ }
- toBooleans(): Array {
- return PackedBool_.unpack(this.packed).map((x) => x.toBoolean());
- }
+ toBooleans(): Array {
+ return PackedBool.unpack(this.packed).map((x) => x.toBoolean());
}
- return PackedBool_;
}
diff --git a/src/lib/packed-types/PackedUInt32.test.ts b/src/lib/packed-types/PackedUInt32.test.ts
index 54459f9..db68ca8 100644
--- a/src/lib/packed-types/PackedUInt32.test.ts
+++ b/src/lib/packed-types/PackedUInt32.test.ts
@@ -1,8 +1,7 @@
import { Provable, UInt32 } from 'o1js';
-import { PackedUInt32Factory } from './PackedUInt32';
+import { PackedUInt32 } from './PackedUInt32';
describe('PackedUInt32', () => {
- class PackedUInt32 extends PackedUInt32Factory(7) {}
describe('Outside of the circuit', () => {
const bigints = [10n, 2n ** 32n - 1n, 0n, 10n, 2n ** 32n - 100n, 42n, 0n];
const uints = bigints.map((x) => UInt32.from(x));
@@ -22,17 +21,13 @@ describe('PackedUInt32', () => {
});
describe('Provable Properties', () => {
it('#sizeInFields', () => {
- class one extends PackedUInt32Factory(1) {}
- class seven extends PackedUInt32Factory(7) {}
-
- expect(one.sizeInFields()).toBe(1);
- expect(seven.sizeInFields()).toBe(1);
+ expect(PackedUInt32.sizeInFields()).toBe(1);
});
});
describe('Defensive Cases', () => {
it('throws for input >= 8 uints', () => {
- expect(() => PackedUInt32Factory(7)).not.toThrow();
- expect(() => PackedUInt32Factory(8)).toThrow();
+ expect(() => PackedUInt32).not.toThrow();
+ expect(() => PackedUInt32).toThrow();
});
it('initalizes with more input than allowed', () => {
@@ -69,10 +64,7 @@ describe('PackedUInt32', () => {
it('Initializes', () => {
expect(() => {
Provable.runAndCheck(() => {
- const packedUInt32 = new PackedUInt32(
- outsidePackedUInt.packed,
- outsidePackedUInt.aux
- );
+ const packedUInt32 = new PackedUInt32(outsidePackedUInt.packed);
PackedUInt32.check({ packed: packedUInt32.packed });
});
@@ -81,20 +73,14 @@ describe('PackedUInt32', () => {
it('#assertEquals', () => {
expect(() => {
Provable.runAndCheck(() => {
- const packedUInt32 = new PackedUInt32(
- outsidePackedUInt.packed,
- outsidePackedUInt.aux
- );
+ const packedUInt32 = new PackedUInt32(outsidePackedUInt.packed);
packedUInt32.assertEquals(outsidePackedUInt);
});
}).not.toThrow();
expect(() => {
Provable.runAndCheck(() => {
const fakePacked = outsidePackedUInt.packed.add(32);
- const packedUInt32 = new PackedUInt32(
- fakePacked,
- outsidePackedUInt.aux
- );
+ const packedUInt32 = new PackedUInt32(fakePacked);
packedUInt32.assertEquals(outsidePackedUInt);
});
}).toThrow();
diff --git a/src/lib/packed-types/PackedUInt32.ts b/src/lib/packed-types/PackedUInt32.ts
index 6837a10..a5b1e72 100644
--- a/src/lib/packed-types/PackedUInt32.ts
+++ b/src/lib/packed-types/PackedUInt32.ts
@@ -1,52 +1,50 @@
import { Field, Provable, UInt32 } from 'o1js';
import { PackingPlant } from '../PackingPlant.js';
+const L = 7; // 7 32-byte uints fit in one Field
const SIZE_IN_BITS = 32n;
-export function PackedUInt32Factory(l: number) {
- class PackedUInt32_ extends PackingPlant(UInt32, l, SIZE_IN_BITS) {
- static toAuxiliary(value?: { packed: Field } | undefined): Array {
- const auxiliary = Provable.witness(Provable.Array(UInt32, l), () => {
- let uints_ = new Array(l);
- uints_.fill(0n);
- let packedN;
- if (value && value.packed) {
- packedN = value.packed.toBigInt();
- } else {
- throw new Error('No Packed Value Provided');
- }
- for (let i = 0; i < l; i++) {
- uints_[i] = packedN & ((1n << SIZE_IN_BITS) - 1n);
- packedN >>= SIZE_IN_BITS;
- }
- return uints_.map((x) => UInt32.from(x));
- });
- return auxiliary;
+export class PackedUInt32 extends PackingPlant(UInt32, L, SIZE_IN_BITS) {
+ static pack(unpacked: Array): Field {
+ let f = unpacked[0].value;
+ const n = Math.min(unpacked.length, L);
+ for (let i = 1; i < n; i++) {
+ const c = Field((2n ** SIZE_IN_BITS) ** BigInt(i));
+ f = f.add(unpacked[i].value.mul(c));
}
+ return f;
+ }
- static pack(aux: Array): Field {
- let f = aux[0].value;
- const n = Math.min(aux.length, l);
- for (let i = 1; i < n; i++) {
- const c = Field((2n ** SIZE_IN_BITS) ** BigInt(i));
- f = f.add(aux[i].value.mul(c));
+ static unpack(f: Field): UInt32[] {
+ const auxiliary = Provable.witness(Provable.Array(UInt32, L), () => {
+ let uints_ = new Array(L);
+ uints_.fill(0n);
+ let packedN;
+ if (f) {
+ packedN = f.toBigInt();
+ } else {
+ throw new Error('No Packed Value Provided');
}
- return f;
- }
+ for (let i = 0; i < L; i++) {
+ uints_[i] = packedN & ((1n << SIZE_IN_BITS) - 1n);
+ packedN >>= SIZE_IN_BITS;
+ }
+ return uints_.map((x) => UInt32.from(x));
+ });
+ return auxiliary;
+ }
- static fromAuxiliary(aux: Array): PackedUInt32_ {
- const packed = PackedUInt32_.pack(aux);
- return new PackedUInt32_(packed, aux);
- }
+ static fromUInt32s(uint32s: Array): PackedUInt32 {
+ const packed = PackedUInt32.pack(uint32s);
+ return new PackedUInt32(packed);
+ }
- static fromBigInts(bigints: Array): PackedUInt32_ {
- const uint32s = bigints.map((x) => UInt32.from(x));
- return this.fromAuxiliary(uint32s);
- }
+ static fromBigInts(bigints: Array): PackedUInt32 {
+ const uint32s = bigints.map((x) => UInt32.from(x));
+ return PackedUInt32.fromUInt32s(uint32s);
+ }
- toBigInts(): Array {
- return PackedUInt32_.unpack(this.packed).map((x) => x.toBigint());
- }
+ toBigInts(): Array {
+ return PackedUInt32.unpack(this.packed).map((x) => x.toBigint());
}
- return PackedUInt32_;
}
diff --git a/tests/provable/end_to_end.test.ts b/tests/provable/end_to_end.test.ts
index b6cd25c..9308768 100644
--- a/tests/provable/end_to_end.test.ts
+++ b/tests/provable/end_to_end.test.ts
@@ -19,8 +19,9 @@ describe('End to End Votes Test', () => {
});
it('Increments the 0th index', async () => {
+ initProof.verify();
const proofAux = [1n, 0n];
- const proofVotes = Votes.fromAuxiliary(Votes.fromBigInts(proofAux).aux);
+ const proofVotes = Votes.fromBigInts(proofAux);
const proof = await VotesProgram.incrementIndex0(proofVotes, initProof);
proof.verify();
proofVotes.packed.assertEquals(proof.publicInput.packed);
diff --git a/tests/provable/example_circuit.ts b/tests/provable/example_circuit.ts
index 592200e..a3c0e6d 100644
--- a/tests/provable/example_circuit.ts
+++ b/tests/provable/example_circuit.ts
@@ -1,7 +1,7 @@
import { Experimental, SelfProof } from 'o1js';
-import { PackedUInt32Factory } from '../../src/lib/packed-types/PackedUInt32';
+import { PackedUInt32 } from '../../src/lib/packed-types/PackedUInt32';
-export class Votes extends PackedUInt32Factory(2) {}
+export class Votes extends PackedUInt32 {}
export const VotesProgram = Experimental.ZkProgram({
publicInput: Votes,
@@ -10,7 +10,7 @@ export const VotesProgram = Experimental.ZkProgram({
init: {
privateInputs: [],
method(state: Votes) {
- const initState = Votes.fromAuxiliary(Votes.fromBigInts([0n, 0n]).aux);
+ const initState = Votes.fromBigInts([0n, 0n]);
state.assertEquals(initState);
},
},
@@ -19,19 +19,22 @@ export const VotesProgram = Experimental.ZkProgram({
method(newState: Votes, oldProof: SelfProof) {
oldProof.verify();
const expectedAux = Votes.unpack(oldProof.publicInput.packed);
+ oldProof.publicInput.packed.assertEquals(
+ Votes.fromUInt32s(expectedAux).packed
+ );
expectedAux[0] = expectedAux[0].add(1);
- newState.packed.assertEquals(Votes.fromAuxiliary(expectedAux).packed);
- },
- },
- incrementIndex1: {
- privateInputs: [SelfProof],
- method(newState: Votes, oldProof: SelfProof) {
- oldProof.verify();
- const expectedAux = Votes.unpack(oldProof.publicInput.packed);
- expectedAux[1] = expectedAux[1].add(1);
- newState.assertEquals(Votes.fromAuxiliary(expectedAux));
+ newState.packed.assertEquals(Votes.fromUInt32s(expectedAux).packed);
},
},
+ // incrementIndex1: {
+ // privateInputs: [SelfProof],
+ // method(newState: Votes, oldProof: SelfProof) {
+ // oldProof.verify();
+ // const expectedAux = Votes.unpack(oldProof.publicInput.packed);
+ // expectedAux[1] = expectedAux[1].add(1);
+ // newState.packed.assertEquals(Votes.fromAuxiliary(expectedAux).packed);
+ // },
+ // },
},
});