o1js-pack 0.4.1 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (28) hide show
  1. package/.husky/pre-commit +0 -0
  2. package/README.md +8 -2
  3. package/build/src/index.d.ts +5 -5
  4. package/build/src/index.js +5 -5
  5. package/build/src/index.js.map +1 -1
  6. package/build/src/lib/PackingPlant.d.ts +132 -132
  7. package/build/src/lib/PackingPlant.js +190 -190
  8. package/build/src/lib/packed-types/PackedBool.d.ts +85 -85
  9. package/build/src/lib/packed-types/PackedBool.js +49 -49
  10. package/build/src/lib/packed-types/PackedBool.test.d.ts +1 -1
  11. package/build/src/lib/packed-types/PackedBool.test.js +75 -75
  12. package/build/src/lib/packed-types/PackedString.d.ts +181 -181
  13. package/build/src/lib/packed-types/PackedString.js +127 -127
  14. package/build/src/lib/packed-types/PackedString.test.d.ts +1 -1
  15. package/build/src/lib/packed-types/PackedString.test.js +100 -100
  16. package/build/src/lib/packed-types/PackedUInt32.d.ts +85 -85
  17. package/build/src/lib/packed-types/PackedUInt32.js +49 -49
  18. package/build/src/lib/packed-types/PackedUInt32.test.d.ts +1 -1
  19. package/build/src/lib/packed-types/PackedUInt32.test.js +83 -83
  20. package/examples/smart_contract/election/README.md +3 -0
  21. package/examples/smart_contract/election/contract.ts +79 -0
  22. package/examples/smart_contract/election/run.ts +98 -0
  23. package/examples/zk_program/age_gate/README.md +7 -0
  24. package/examples/zk_program/age_gate/circuit.ts +75 -0
  25. package/examples/zk_program/age_gate/non-packed-circuit.ts +68 -0
  26. package/examples/zk_program/age_gate/non-packed-run.ts +36 -0
  27. package/examples/zk_program/age_gate/run.ts +35 -0
  28. package/package.json +1 -1
@@ -1,50 +1,50 @@
1
- import { Provable, UInt32 } from 'o1js';
2
- import { PackingPlant } from '../PackingPlant.js';
3
- const L = 7; // 7 32-bit uints fit in one Field
4
- const SIZE_IN_BITS = 32n;
5
- export function PackedUInt32Factory(l = L) {
6
- class PackedUInt32_ extends PackingPlant(UInt32, l, SIZE_IN_BITS) {
7
- static extractField(input) {
8
- return input.value;
9
- }
10
- static sizeInBits() {
11
- return SIZE_IN_BITS;
12
- }
13
- /**
14
- *
15
- * @param f Field, packed with the information, as returned by #pack
16
- * @returns Array of UInt32
17
- */
18
- static unpack(f) {
19
- const unpacked = Provable.witness(Provable.Array(UInt32, l), () => {
20
- const unpacked = this.unpackToBigints(f);
21
- return unpacked.map((x) => UInt32.from(x));
22
- });
23
- f.assertEquals(PackedUInt32_.pack(unpacked));
24
- return unpacked;
25
- }
26
- /**
27
- *
28
- * @param uint32s Array of UInt32s to be packed
29
- * @returns Instance of the implementing class
30
- */
31
- static fromUInt32s(uint32s) {
32
- const packed = PackedUInt32_.pack(uint32s);
33
- return new PackedUInt32_(packed);
34
- }
35
- /**
36
- *
37
- * @param bigints Array of bigints to be packed
38
- * @returns Instance of the implementing class
39
- */
40
- static fromBigInts(bigints) {
41
- const uint32s = bigints.map((x) => UInt32.from(x));
42
- return PackedUInt32_.fromUInt32s(uint32s);
43
- }
44
- toBigInts() {
45
- return PackedUInt32_.unpack(this.packed).map((x) => x.toBigint());
46
- }
47
- }
48
- return PackedUInt32_;
49
- }
1
+ import { Provable, UInt32 } from 'o1js';
2
+ import { PackingPlant } from '../PackingPlant.js';
3
+ const L = 7; // 7 32-bit uints fit in one Field
4
+ const SIZE_IN_BITS = 32n;
5
+ export function PackedUInt32Factory(l = L) {
6
+ class PackedUInt32_ extends PackingPlant(UInt32, l, SIZE_IN_BITS) {
7
+ static extractField(input) {
8
+ return input.value;
9
+ }
10
+ static sizeInBits() {
11
+ return SIZE_IN_BITS;
12
+ }
13
+ /**
14
+ *
15
+ * @param f Field, packed with the information, as returned by #pack
16
+ * @returns Array of UInt32
17
+ */
18
+ static unpack(f) {
19
+ const unpacked = Provable.witness(Provable.Array(UInt32, l), () => {
20
+ const unpacked = this.unpackToBigints(f);
21
+ return unpacked.map((x) => UInt32.from(x));
22
+ });
23
+ f.assertEquals(PackedUInt32_.pack(unpacked));
24
+ return unpacked;
25
+ }
26
+ /**
27
+ *
28
+ * @param uint32s Array of UInt32s to be packed
29
+ * @returns Instance of the implementing class
30
+ */
31
+ static fromUInt32s(uint32s) {
32
+ const packed = PackedUInt32_.pack(uint32s);
33
+ return new PackedUInt32_(packed);
34
+ }
35
+ /**
36
+ *
37
+ * @param bigints Array of bigints to be packed
38
+ * @returns Instance of the implementing class
39
+ */
40
+ static fromBigInts(bigints) {
41
+ const uint32s = bigints.map((x) => UInt32.from(x));
42
+ return PackedUInt32_.fromUInt32s(uint32s);
43
+ }
44
+ toBigInts() {
45
+ return PackedUInt32_.unpack(this.packed).map((x) => x.toBigint());
46
+ }
47
+ }
48
+ return PackedUInt32_;
49
+ }
50
50
  //# sourceMappingURL=PackedUInt32.js.map
@@ -1 +1 @@
1
- export {};
1
+ export {};
@@ -1,84 +1,84 @@
1
- import { Provable, UInt32 } from 'o1js';
2
- import { PackedUInt32Factory } from './PackedUInt32';
3
- describe('PackedUInt32', () => {
4
- class PackedUInt32 extends PackedUInt32Factory() {
5
- }
6
- describe('Outside of the circuit', () => {
7
- const bigints = [10n, 2n ** 32n - 1n, 0n, 10n, 2n ** 32n - 100n, 42n, 0n];
8
- const uints = bigints.map((x) => UInt32.from(x));
9
- it('#fromBigInts', () => {
10
- const myPackedUInt32 = PackedUInt32.fromBigInts(bigints);
11
- expect(myPackedUInt32.toBigInts()).toMatchObject(bigints);
12
- });
13
- it('#pack and #unPack', () => {
14
- const packed = PackedUInt32.pack(uints);
15
- const unpacked = PackedUInt32.unpack(packed);
16
- expect(unpacked.length).toBe(uints.length);
17
- expect(unpacked).toMatchObject(uints);
18
- });
19
- });
20
- describe('Provable Properties', () => {
21
- it('#sizeInFields', () => {
22
- class one extends PackedUInt32Factory(1) {
23
- }
24
- class seven extends PackedUInt32Factory(7) {
25
- }
26
- expect(one.sizeInFields()).toBe(1);
27
- expect(seven.sizeInFields()).toBe(1);
28
- });
29
- });
30
- describe('Defensive Cases', () => {
31
- it('throws for input >= 8 uints', () => {
32
- expect(() => PackedUInt32Factory(7)).not.toThrow();
33
- expect(() => PackedUInt32Factory(8)).toThrow();
34
- });
35
- it('initalizes with more input than allowed', () => {
36
- const bigints = [
37
- 10n,
38
- 2n ** 32n - 1n,
39
- 0n,
40
- 10n,
41
- 2n ** 32n - 100n,
42
- 42n,
43
- 0n,
44
- 0n,
45
- ];
46
- expect(() => {
47
- PackedUInt32.fromBigInts(bigints);
48
- }).toThrow();
49
- });
50
- it('initalizes with less input than specified', () => {
51
- const bigints = [10n];
52
- const expected = [10n, 0n, 0n, 0n, 0n, 0n, 0n];
53
- expect(PackedUInt32.fromBigInts(bigints).toBigInts()).toMatchObject(expected);
54
- });
55
- });
56
- describe('In the circuit', () => {
57
- const bigints = [10n, 2n ** 32n - 1n, 0n, 10n, 2n ** 32n - 100n, 42n, 0n];
58
- const outsidePackedUInt = PackedUInt32.fromBigInts(bigints);
59
- it('Initializes', () => {
60
- expect(() => {
61
- Provable.runAndCheck(() => {
62
- const packedUInt32 = new PackedUInt32(outsidePackedUInt.packed);
63
- PackedUInt32.check({ packed: packedUInt32.packed });
64
- });
65
- }).not.toThrow();
66
- });
67
- it('#assertEquals', () => {
68
- expect(() => {
69
- Provable.runAndCheck(() => {
70
- const packedUInt32 = new PackedUInt32(outsidePackedUInt.packed);
71
- packedUInt32.assertEquals(outsidePackedUInt);
72
- });
73
- }).not.toThrow();
74
- expect(() => {
75
- Provable.runAndCheck(() => {
76
- const fakePacked = outsidePackedUInt.packed.add(32);
77
- const packedUInt32 = new PackedUInt32(fakePacked);
78
- packedUInt32.assertEquals(outsidePackedUInt);
79
- });
80
- }).toThrow();
81
- });
82
- });
83
- });
1
+ import { Provable, UInt32 } from 'o1js';
2
+ import { PackedUInt32Factory } from './PackedUInt32';
3
+ describe('PackedUInt32', () => {
4
+ class PackedUInt32 extends PackedUInt32Factory() {
5
+ }
6
+ describe('Outside of the circuit', () => {
7
+ const bigints = [10n, 2n ** 32n - 1n, 0n, 10n, 2n ** 32n - 100n, 42n, 0n];
8
+ const uints = bigints.map((x) => UInt32.from(x));
9
+ it('#fromBigInts', () => {
10
+ const myPackedUInt32 = PackedUInt32.fromBigInts(bigints);
11
+ expect(myPackedUInt32.toBigInts()).toMatchObject(bigints);
12
+ });
13
+ it('#pack and #unPack', () => {
14
+ const packed = PackedUInt32.pack(uints);
15
+ const unpacked = PackedUInt32.unpack(packed);
16
+ expect(unpacked.length).toBe(uints.length);
17
+ expect(unpacked).toMatchObject(uints);
18
+ });
19
+ });
20
+ describe('Provable Properties', () => {
21
+ it('#sizeInFields', () => {
22
+ class one extends PackedUInt32Factory(1) {
23
+ }
24
+ class seven extends PackedUInt32Factory(7) {
25
+ }
26
+ expect(one.sizeInFields()).toBe(1);
27
+ expect(seven.sizeInFields()).toBe(1);
28
+ });
29
+ });
30
+ describe('Defensive Cases', () => {
31
+ it('throws for input >= 8 uints', () => {
32
+ expect(() => PackedUInt32Factory(7)).not.toThrow();
33
+ expect(() => PackedUInt32Factory(8)).toThrow();
34
+ });
35
+ it('initalizes with more input than allowed', () => {
36
+ const bigints = [
37
+ 10n,
38
+ 2n ** 32n - 1n,
39
+ 0n,
40
+ 10n,
41
+ 2n ** 32n - 100n,
42
+ 42n,
43
+ 0n,
44
+ 0n,
45
+ ];
46
+ expect(() => {
47
+ PackedUInt32.fromBigInts(bigints);
48
+ }).toThrow();
49
+ });
50
+ it('initalizes with less input than specified', () => {
51
+ const bigints = [10n];
52
+ const expected = [10n, 0n, 0n, 0n, 0n, 0n, 0n];
53
+ expect(PackedUInt32.fromBigInts(bigints).toBigInts()).toMatchObject(expected);
54
+ });
55
+ });
56
+ describe('In the circuit', () => {
57
+ const bigints = [10n, 2n ** 32n - 1n, 0n, 10n, 2n ** 32n - 100n, 42n, 0n];
58
+ const outsidePackedUInt = PackedUInt32.fromBigInts(bigints);
59
+ it('Initializes', () => {
60
+ expect(() => {
61
+ Provable.runAndCheck(() => {
62
+ const packedUInt32 = new PackedUInt32(outsidePackedUInt.packed);
63
+ PackedUInt32.check({ packed: packedUInt32.packed });
64
+ });
65
+ }).not.toThrow();
66
+ });
67
+ it('#assertEquals', () => {
68
+ expect(() => {
69
+ Provable.runAndCheck(() => {
70
+ const packedUInt32 = new PackedUInt32(outsidePackedUInt.packed);
71
+ packedUInt32.assertEquals(outsidePackedUInt);
72
+ });
73
+ }).not.toThrow();
74
+ expect(() => {
75
+ Provable.runAndCheck(() => {
76
+ const fakePacked = outsidePackedUInt.packed.add(32);
77
+ const packedUInt32 = new PackedUInt32(fakePacked);
78
+ packedUInt32.assertEquals(outsidePackedUInt);
79
+ });
80
+ }).toThrow();
81
+ });
82
+ });
83
+ });
84
84
  //# sourceMappingURL=PackedUInt32.test.js.map
@@ -0,0 +1,3 @@
1
+ ## Election Smart Contract
2
+
3
+ An election has multiple ballots, and a ballot has multiple options. We want to build an app that can track the state of the election, but there are more than 8 pieces of state. We'll have to use packing to store all of the results on chain.
@@ -0,0 +1,79 @@
1
+ import { SmartContract, state, State, method, UInt32 } from 'o1js';
2
+ import { PackedUInt32Factory } from '../../../src/index.js';
3
+
4
+ export class Ballot extends PackedUInt32Factory() {}
5
+
6
+ export class Election extends SmartContract {
7
+ @state(Ballot) ballot1 = State<Ballot>();
8
+ @state(Ballot) ballot2 = State<Ballot>();
9
+ @state(Ballot) ballot3 = State<Ballot>();
10
+ @state(Ballot) ballot4 = State<Ballot>();
11
+
12
+ init() {
13
+ super.init();
14
+ this.ballot1.set(Ballot.fromBigInts([0n, 0n, 0n, 0n, 0n, 0n, 0n]));
15
+ this.ballot2.set(Ballot.fromBigInts([0n, 0n, 0n, 0n, 0n, 0n, 0n]));
16
+ this.ballot3.set(Ballot.fromBigInts([0n, 0n, 0n, 0n, 0n, 0n, 0n]));
17
+ this.ballot4.set(Ballot.fromBigInts([0n, 0n, 0n, 0n, 0n, 0n, 0n]));
18
+ }
19
+
20
+ @method
21
+ castBallot1(vote: Ballot) {
22
+ const unpackedVote = Ballot.unpack(vote.packed);
23
+ const ballot1 = this.ballot1.getAndAssertEquals();
24
+ const unpackedBallot1 = Ballot.unpack(ballot1.packed);
25
+
26
+ let voteSum = UInt32.from(0);
27
+ for (let i = 0; i < Ballot.l; i++) {
28
+ voteSum = voteSum.add(unpackedVote[i]);
29
+ unpackedBallot1[i] = unpackedBallot1[i].add(unpackedVote[i]);
30
+ }
31
+ voteSum.value.assertEquals(1); // vote must be exactly one vote for one choice
32
+ this.ballot1.set(Ballot.fromUInt32s(unpackedBallot1));
33
+ }
34
+
35
+ @method
36
+ castBallot2(vote: Ballot) {
37
+ const unpackedVote = Ballot.unpack(vote.packed);
38
+ const ballot2 = this.ballot2.getAndAssertEquals();
39
+ const unpackedBallot2 = Ballot.unpack(ballot2.packed);
40
+
41
+ let voteSum = UInt32.from(0);
42
+ for (let i = 0; i < Ballot.l; i++) {
43
+ voteSum = voteSum.add(unpackedVote[i]);
44
+ unpackedBallot2[i] = unpackedBallot2[i].add(unpackedVote[i]);
45
+ }
46
+ voteSum.value.assertEquals(1); // vote must be exactly one vote for one choice
47
+ this.ballot2.set(Ballot.fromUInt32s(unpackedBallot2));
48
+ }
49
+
50
+ @method
51
+ castBallot3(vote: Ballot) {
52
+ const unpackedVote = Ballot.unpack(vote.packed);
53
+ const ballot3 = this.ballot3.getAndAssertEquals();
54
+ const unpackedBallot3 = Ballot.unpack(ballot3.packed);
55
+
56
+ let voteSum = UInt32.from(0);
57
+ for (let i = 0; i < Ballot.l; i++) {
58
+ voteSum = voteSum.add(unpackedVote[i]);
59
+ unpackedBallot3[i] = unpackedBallot3[i].add(unpackedVote[i]);
60
+ }
61
+ voteSum.value.assertEquals(1); // vote must be exactly one vote for one choice
62
+ this.ballot3.set(Ballot.fromUInt32s(unpackedBallot3));
63
+ }
64
+
65
+ @method
66
+ castBallot4(vote: Ballot) {
67
+ const unpackedVote = Ballot.unpack(vote.packed);
68
+ const ballot4 = this.ballot4.getAndAssertEquals();
69
+ const unpackedBallot4 = Ballot.unpack(ballot4.packed);
70
+
71
+ let voteSum = UInt32.from(0);
72
+ for (let i = 0; i < Ballot.l; i++) {
73
+ voteSum = voteSum.add(unpackedVote[i]);
74
+ unpackedBallot4[i] = unpackedBallot4[i].add(unpackedVote[i]);
75
+ }
76
+ voteSum.value.assertEquals(1); // vote must be exactly one vote for one choice
77
+ this.ballot4.set(Ballot.fromUInt32s(unpackedBallot4));
78
+ }
79
+ }
@@ -0,0 +1,98 @@
1
+ import { AccountUpdate, Mina, PrivateKey } from 'o1js';
2
+ import { Ballot, Election } from './contract.js';
3
+
4
+ let Local = Mina.LocalBlockchain({ proofsEnabled: true });
5
+ Mina.setActiveInstance(Local);
6
+
7
+ // a test account that pays all the fees, and puts additional funds into the zkapp
8
+ let { privateKey: senderKey, publicKey: sender } = Local.testAccounts[0];
9
+
10
+ // the zkapp account
11
+ let zkappKey = PrivateKey.random();
12
+ let zkappAddress = zkappKey.toPublicKey();
13
+
14
+ // a special account that is allowed to pull out half of the zkapp balance, once
15
+ let privilegedKey = PrivateKey.random();
16
+ let privilegedAddress = privilegedKey.toPublicKey();
17
+
18
+ let initialBalance = 10_000_000_000;
19
+ let zkapp = new Election(zkappAddress);
20
+
21
+ console.time('compile');
22
+ await Election.compile();
23
+ console.timeEnd('compile');
24
+
25
+ console.time('deploy');
26
+ let tx = await Mina.transaction(sender, () => {
27
+ let senderUpdate = AccountUpdate.fundNewAccount(sender);
28
+ senderUpdate.send({ to: zkappAddress, amount: initialBalance });
29
+ zkapp.deploy({ zkappKey });
30
+ });
31
+ await tx.prove();
32
+ await tx.sign([senderKey]).send();
33
+ console.timeEnd('deploy');
34
+
35
+ console.log(
36
+ 'initial state: ',
37
+ zkapp.ballot1.get().toBigInts(),
38
+ zkapp.ballot2.get().toBigInts(),
39
+ zkapp.ballot3.get().toBigInts(),
40
+ zkapp.ballot4.get().toBigInts()
41
+ );
42
+
43
+ console.time('vote on ballot 1');
44
+ tx = await Mina.transaction(sender, () => {
45
+ const myVote = Ballot.fromBigInts([0n, 0n, 1n, 0n, 0n, 0n, 0n]);
46
+ zkapp.castBallot1(myVote);
47
+ });
48
+ await tx.prove();
49
+ await tx.sign([senderKey]).send();
50
+ console.timeEnd('vote on ballot 1');
51
+
52
+ console.time('vote on ballot 3');
53
+ tx = await Mina.transaction(sender, () => {
54
+ const myVote = Ballot.fromBigInts([0n, 0n, 0n, 0n, 0n, 0n, 1n]);
55
+ zkapp.castBallot3(myVote);
56
+ });
57
+ await tx.prove();
58
+ await tx.sign([senderKey]).send();
59
+ console.timeEnd('vote on ballot 3');
60
+
61
+ console.log(
62
+ 'final state: ',
63
+ zkapp.ballot1.get().toBigInts(),
64
+ zkapp.ballot2.get().toBigInts(),
65
+ zkapp.ballot3.get().toBigInts(),
66
+ zkapp.ballot4.get().toBigInts()
67
+ );
68
+
69
+ // compile: 28.710s
70
+ // deploy: 1.848s
71
+ // initial state: [
72
+ // 0n, 0n, 0n, 0n,
73
+ // 0n, 0n, 0n
74
+ // ] [
75
+ // 0n, 0n, 0n, 0n,
76
+ // 0n, 0n, 0n
77
+ // ] [
78
+ // 0n, 0n, 0n, 0n,
79
+ // 0n, 0n, 0n
80
+ // ] [
81
+ // 0n, 0n, 0n, 0n,
82
+ // 0n, 0n, 0n
83
+ // ]
84
+ // vote on ballot 1: 24.752s
85
+ // vote on ballot 3: 23.132s
86
+ // final state: [
87
+ // 0n, 0n, 1n, 0n,
88
+ // 0n, 0n, 0n
89
+ // ] [
90
+ // 0n, 0n, 0n, 0n,
91
+ // 0n, 0n, 0n
92
+ // ] [
93
+ // 0n, 0n, 0n, 0n,
94
+ // 0n, 0n, 1n
95
+ // ] [
96
+ // 0n, 0n, 0n, 0n,
97
+ // 0n, 0n, 0n
98
+ // ]
@@ -0,0 +1,7 @@
1
+ ## Age Gate
2
+
3
+ This example Zk Program stores a counter of accepted, a counter of rejected, and a method to check an input age.
4
+
5
+ If the age is above a required limit, the accepted counter is incremented, else the rejected counter is incremented.
6
+
7
+ The 2 counters are stored in a single packed UInt, and the data type for age is a packed string.
@@ -0,0 +1,75 @@
1
+ import {
2
+ Field,
3
+ Experimental,
4
+ UInt32,
5
+ Provable,
6
+ Poseidon,
7
+ SelfProof,
8
+ Character,
9
+ Bool,
10
+ Empty,
11
+ } from 'o1js';
12
+ import {
13
+ PackedUInt32Factory,
14
+ PackedStringFactory,
15
+ } from '../../../src/index.js';
16
+
17
+ export class PackedCounters extends PackedUInt32Factory(2) {}
18
+
19
+ export class PackedString extends PackedStringFactory(8) {}
20
+
21
+ const isOlderThan = (reference: PackedString, toVerify: PackedString): Bool => {
22
+ let ref = Field(0);
23
+ let ver = Field(0);
24
+
25
+ const referenceDate = PackedString.unpack(reference.packed);
26
+ const dateToVerify = PackedString.unpack(toVerify.packed);
27
+
28
+ for (let i = 0; i < PackedString.l; i++) {
29
+ const exp = PackedString.l - i;
30
+ ref = ref.add(referenceDate[i].value.mul(10 ** exp));
31
+ ver = ver.add(dateToVerify[i].value.mul(10 ** exp));
32
+ }
33
+
34
+ return ver.greaterThan(ref);
35
+ };
36
+
37
+ export const AgeGateCircuit = Experimental.ZkProgram({
38
+ publicOutput: PackedCounters,
39
+
40
+ methods: {
41
+ init: {
42
+ privateInputs: [],
43
+ method() {
44
+ return PackedCounters.fromBigInts([0n, 0n]);
45
+ },
46
+ },
47
+ verifyAge: {
48
+ privateInputs: [SelfProof, PackedString],
49
+ method(
50
+ oldProof: SelfProof<Empty, PackedCounters>,
51
+ dateToVerify: PackedString
52
+ ) {
53
+ oldProof.verify();
54
+ const counters = PackedCounters.unpack(oldProof.publicOutput.packed);
55
+ const referenceDate = PackedString.fromString('20000101'); // hard-coded - date to verify must be older than new years in the year 2000
56
+ const isOlder = isOlderThan(referenceDate, dateToVerify);
57
+ const deltaCounter0 = Provable.if(
58
+ isOlder,
59
+ UInt32.from(1),
60
+ UInt32.from(0)
61
+ );
62
+ const deltaCounter1 = Provable.if(
63
+ isOlder,
64
+ UInt32.from(0),
65
+ UInt32.from(1)
66
+ );
67
+ counters[0] = counters[0].add(deltaCounter0);
68
+ counters[1] = counters[1].add(deltaCounter1);
69
+ return PackedCounters.fromUInt32s(counters);
70
+ },
71
+ },
72
+ },
73
+ });
74
+
75
+ export const AgeGateCircuitProof = Experimental.ZkProgram.Proof(AgeGateCircuit);
@@ -0,0 +1,68 @@
1
+ import {
2
+ Field,
3
+ Experimental,
4
+ UInt32,
5
+ Provable,
6
+ Poseidon,
7
+ SelfProof,
8
+ Character,
9
+ Bool,
10
+ Empty,
11
+ CircuitString,
12
+ } from 'o1js';
13
+
14
+ const isOlderThan = (
15
+ reference: CircuitString,
16
+ toVerify: CircuitString
17
+ ): Bool => {
18
+ let ref = Field(0);
19
+ let ver = Field(0);
20
+
21
+ for (let i = 0; i < 8; i++) {
22
+ const exp = 8 - i;
23
+ ref = ref.add(reference.values[i].value.mul(10 ** exp));
24
+ ver = ver.add(toVerify.values[i].value.mul(10 ** exp));
25
+ }
26
+
27
+ return ver.greaterThan(ref);
28
+ };
29
+
30
+ export const AgeGateCircuit = Experimental.ZkProgram({
31
+ publicOutput: Provable.Array(UInt32, 2),
32
+
33
+ methods: {
34
+ init: {
35
+ privateInputs: [],
36
+ method() {
37
+ return [UInt32.from(0), UInt32.from(0)];
38
+ },
39
+ },
40
+ verifyAge: {
41
+ privateInputs: [SelfProof, CircuitString],
42
+ method(
43
+ oldProof: SelfProof<Empty, Array<UInt32>>,
44
+ dateToVerify: CircuitString
45
+ ) {
46
+ oldProof.verify();
47
+ const counters = oldProof.publicOutput;
48
+ const referenceDate = CircuitString.fromString('20000101'); // hard-coded - date to verify must be older than new years in the year 2000
49
+ const isOlder = isOlderThan(referenceDate, dateToVerify);
50
+ const deltaCounter0 = Provable.if(
51
+ isOlder,
52
+ UInt32.from(1),
53
+ UInt32.from(0)
54
+ );
55
+ const deltaCounter1 = Provable.if(
56
+ isOlder,
57
+ UInt32.from(0),
58
+ UInt32.from(1)
59
+ );
60
+ counters[0] = counters[0].add(deltaCounter0);
61
+ counters[1] = counters[1].add(deltaCounter1);
62
+ return counters;
63
+ },
64
+ },
65
+ },
66
+ });
67
+
68
+ export const AgeGateCircuitProof = Experimental.ZkProgram.Proof(AgeGateCircuit);
@@ -0,0 +1,36 @@
1
+ import { AgeGateCircuit } from './non-packed-circuit.js';
2
+ import { CircuitString } from 'o1js';
3
+
4
+ console.time('Compiling...');
5
+ await AgeGateCircuit.compile();
6
+ console.timeEnd('Compiling...');
7
+
8
+ console.time('Running...');
9
+ let old_proof = await AgeGateCircuit.init();
10
+ old_proof = await AgeGateCircuit.verifyAge(
11
+ old_proof,
12
+ CircuitString.fromString('20210927')
13
+ );
14
+ old_proof = await AgeGateCircuit.verifyAge(
15
+ old_proof,
16
+ CircuitString.fromString('19011225')
17
+ );
18
+ old_proof = await AgeGateCircuit.verifyAge(
19
+ old_proof,
20
+ CircuitString.fromString('20071031')
21
+ );
22
+ console.timeEnd('Running...');
23
+
24
+ // Now we expect old_proof to have a counter of [2, 1] - 2 dates were older than 2000-01-01, 1 date was younger
25
+ const counters = old_proof.publicOutput;
26
+ console.log(counters.toString());
27
+
28
+ const circuitAnalysis = AgeGateCircuit.analyzeMethods();
29
+ console.log('Number of gates in method 0: ', circuitAnalysis[0].rows);
30
+ console.log('Number of gates in method 1: ', circuitAnalysis[1].rows);
31
+
32
+ // Compiling...: 1:00.331 (m:ss.mmm)
33
+ // Running...: 3:31.711 (m:ss.mmm)
34
+ // 2,1
35
+ // Number of gates in method 0: 0
36
+ // Number of gates in method 1: 651
@@ -0,0 +1,35 @@
1
+ import { AgeGateCircuit, PackedCounters, PackedString } from './circuit.js';
2
+
3
+ console.time('Compiling...');
4
+ await AgeGateCircuit.compile();
5
+ console.timeEnd('Compiling...');
6
+
7
+ console.time('Running...');
8
+ let old_proof = await AgeGateCircuit.init();
9
+ old_proof = await AgeGateCircuit.verifyAge(
10
+ old_proof,
11
+ PackedString.fromString('20210927')
12
+ );
13
+ old_proof = await AgeGateCircuit.verifyAge(
14
+ old_proof,
15
+ PackedString.fromString('19011225')
16
+ );
17
+ old_proof = await AgeGateCircuit.verifyAge(
18
+ old_proof,
19
+ PackedString.fromString('20071031')
20
+ );
21
+ console.timeEnd('Running...');
22
+
23
+ // Now we expect old_proof to have a counter of [2, 1] - 2 dates were older than 2000-01-01, 1 date was younger
24
+ const counters = PackedCounters.unpack(old_proof.publicOutput.packed);
25
+ console.log(counters.toString());
26
+
27
+ const circuitAnalysis = AgeGateCircuit.analyzeMethods();
28
+ console.log('Number of gates in method 0: ', circuitAnalysis[0].rows);
29
+ console.log('Number of gates in method 1: ', circuitAnalysis[1].rows);
30
+
31
+ // Compiling...: 59.405s
32
+ // Running...: 3:31.839 (m:ss.mmm)
33
+ // 2,1
34
+ // Number of gates in method 0: 0
35
+ // Number of gates in method 1: 551