From adc1b7c6dcdada13deb5cda892a0d3f33882768e Mon Sep 17 00:00:00 2001 From: Raphael Panic Date: Sun, 18 Jan 2026 19:03:32 +0100 Subject: [PATCH 1/2] Added provable unions --- packages/common/src/union/union.ts | 33 ++++++++++++++++++++++++ packages/common/test/union/union.test.ts | 16 ++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 packages/common/src/union/union.ts create mode 100644 packages/common/test/union/union.test.ts diff --git a/packages/common/src/union/union.ts b/packages/common/src/union/union.ts new file mode 100644 index 00000000..34142b4a --- /dev/null +++ b/packages/common/src/union/union.ts @@ -0,0 +1,33 @@ +import { Provable, Struct, Field, InferProvable } from "o1js"; + +import { padArray } from "../utils"; + +export function createUnion[]>(provables: T) { + const maxLength = Math.max( + ...provables.map((provable) => provable.sizeInFields()) + ); + + class ProvableUnion extends Struct({ + array: Provable.Array(Field, maxLength), + }) { + static from( + provable: Type, + value: InferProvable + ) { + const fields = provable.toFields(value); + const fullFields = padArray(fields, maxLength, () => Field(0)); + return new ProvableUnion({ array: fullFields }); + } + + into(provable: Type): InferProvable { + const size = provable.sizeInFields(); + const fields = this.array.slice(0, size); + + this.array.slice(size).forEach((field) => field.assertEquals(0)); + + return provable.fromFields(fields, []); + } + } + + return ProvableUnion; +} diff --git a/packages/common/test/union/union.test.ts b/packages/common/test/union/union.test.ts new file mode 100644 index 00000000..9351bcdc --- /dev/null +++ b/packages/common/test/union/union.test.ts @@ -0,0 +1,16 @@ +import { Field, UInt64 } from "o1js"; + +import { createUnion } from "../../src/union/union"; + +describe("union", () => { + it("should serialize correctly", () => { + const provable = createUnion([Field, UInt64]); + const p = provable.from(UInt64, UInt64.from(1)); + // const p2 = provable.from(UInt32, UInt32.from(1)); + + const uint = p.into(UInt64); + const x = uint.add(UInt64.from(2)).toString(); + + expect(x).toBe("3"); + }); +}); From c273db5a7a24b79edec500f6eb46615d5c6b0bb0 Mon Sep 17 00:00:00 2001 From: Raphael Panic Date: Sun, 18 Jan 2026 19:12:49 +0100 Subject: [PATCH 2/2] Made unions qualified --- packages/common/src/union/union.ts | 22 +++++++++++++++++----- packages/common/test/union/union.test.ts | 4 ++-- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/packages/common/src/union/union.ts b/packages/common/src/union/union.ts index 34142b4a..22a5345c 100644 --- a/packages/common/src/union/union.ts +++ b/packages/common/src/union/union.ts @@ -1,30 +1,42 @@ -import { Provable, Struct, Field, InferProvable } from "o1js"; +import { Provable, Struct, Field, InferProvable, Unconstrained } from "o1js"; import { padArray } from "../utils"; -export function createUnion[]>(provables: T) { +export function createQualifiedUnion< + T extends (Provable & { name: string })[], +>(provables: T) { const maxLength = Math.max( ...provables.map((provable) => provable.sizeInFields()) ); + const typeMap = Object.fromEntries( + provables.map(({ name }, index) => [name, index]) + ); + class ProvableUnion extends Struct({ array: Provable.Array(Field, maxLength), + type: Field, }) { - static from( + public static from( provable: Type, value: InferProvable ) { const fields = provable.toFields(value); const fullFields = padArray(fields, maxLength, () => Field(0)); - return new ProvableUnion({ array: fullFields }); + return new ProvableUnion({ + array: fullFields, + type: Field(typeMap[provable.name]), + }); } - into(provable: Type): InferProvable { + public into(provable: Type): InferProvable { const size = provable.sizeInFields(); const fields = this.array.slice(0, size); this.array.slice(size).forEach((field) => field.assertEquals(0)); + this.type.assertEquals(typeMap[provable.name]); + return provable.fromFields(fields, []); } } diff --git a/packages/common/test/union/union.test.ts b/packages/common/test/union/union.test.ts index 9351bcdc..4c3c5085 100644 --- a/packages/common/test/union/union.test.ts +++ b/packages/common/test/union/union.test.ts @@ -1,10 +1,10 @@ import { Field, UInt64 } from "o1js"; -import { createUnion } from "../../src/union/union"; +import { createQualifiedUnion } from "../../src/union/union"; describe("union", () => { it("should serialize correctly", () => { - const provable = createUnion([Field, UInt64]); + const provable = createQualifiedUnion([Field, UInt64]); const p = provable.from(UInt64, UInt64.from(1)); // const p2 = provable.from(UInt32, UInt32.from(1));