Skip to content

Commit 90e64b8

Browse files
committed
Added unconstrained values to hashlist
1 parent 8baeee9 commit 90e64b8

File tree

4 files changed

+84
-2
lines changed

4 files changed

+84
-2
lines changed

packages/protocol/src/utils/ProvableHashList.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,26 @@
11
import { Field, Poseidon, Bool, Provable, ProvablePure } from "o1js";
2+
import { NonMethods } from "./utils";
23

34
/**
45
* Utilities for creating a hash list from a given value type.
56
*/
67
export abstract class ProvableHashList<Value> {
8+
private readonly unconstrainedList: NonMethods<Value>[] = [];
9+
710
public constructor(
811
protected readonly valueType: ProvablePure<Value>,
912
public commitment: Field = Field(0)
1013
) {}
1114

1215
protected abstract hash(elements: Field[]): Field;
1316

17+
private pushUnconstrained(value: Value) {
18+
const valueConstant = this.valueType.fromFields(
19+
this.valueType.toFields(value).map((field) => field.toConstant())
20+
);
21+
this.unconstrainedList.push(valueConstant);
22+
}
23+
1424
/**
1525
* Converts the provided value to Field[] and appends it to
1626
* the current hashlist.
@@ -23,6 +33,11 @@ export abstract class ProvableHashList<Value> {
2333
this.commitment,
2434
...this.valueType.toFields(value),
2535
]);
36+
37+
Provable.asProver(() => {
38+
this.pushUnconstrained(value);
39+
});
40+
2641
return this;
2742
}
2843

@@ -32,6 +47,13 @@ export abstract class ProvableHashList<Value> {
3247
...this.valueType.toFields(value),
3348
]);
3449
this.commitment = Provable.if(condition, newCommitment, this.commitment);
50+
51+
Provable.asProver(() => {
52+
if (condition.toBoolean()) {
53+
this.pushUnconstrained(value);
54+
}
55+
});
56+
3557
return this;
3658
}
3759

@@ -41,6 +63,10 @@ export abstract class ProvableHashList<Value> {
4163
public toField() {
4264
return this.commitment;
4365
}
66+
67+
public getUnconstrainedValues(): NonMethods<Value>[] {
68+
return this.unconstrainedList;
69+
}
4470
}
4571

4672
export class DefaultProvableHashList<Value> extends ProvableHashList<Value> {

packages/protocol/src/utils/ProvableReductionHashList.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1-
import { Bool, Field, Poseidon, Provable } from "o1js";
1+
import { Bool, Field, Poseidon, Provable, ProvablePure } from "o1js";
22

33
import { ProvableHashList } from "./ProvableHashList";
4+
import { NonMethods } from "./utils";
5+
6+
export class ProvableReductionHashList<Value>{
7+
public constructor(
8+
protected readonly valueType: ProvablePure<Value>,
9+
public commitment: Field = Field(0)
10+
) {}
411

5-
export class ProvableReductionHashList<Value> extends ProvableHashList<Value> {
612
public unconstrainedList: Value[] = [];
713

814
private constrainedLastValue: Value | undefined = undefined;
@@ -65,4 +71,8 @@ export class ProvableReductionHashList<Value> extends ProvableHashList<Value> {
6571
public hash(elements: Field[]): Field {
6672
return Poseidon.hash(elements);
6773
}
74+
75+
public getUnconstrainedValues(): NonMethods<Value>[] {
76+
return this.unconstrainedList;
77+
}
6878
}

packages/protocol/src/utils/utils.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,8 @@ export function singleFieldToString(value: Field | bigint): string {
7373
}
7474
return fieldValue.toString();
7575
}
76+
77+
type NonMethodKeys<T> = {
78+
[K in keyof T]: T[K] extends Function ? never : K;
79+
}[keyof T];
80+
export type NonMethods<T> = Pick<T, NonMethodKeys<T>>;
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { Bool, Field, Poseidon } from "o1js";
2+
import { DefaultProvableHashList } from "../../src";
3+
4+
describe("defaultProvableHashList", () => {
5+
describe.each([
6+
[0, [{ value: 1n, push: true }]],
7+
// [
8+
// 10,
9+
// [
10+
// { value: 1n, push: true },
11+
// { value: 5n, push: false },
12+
// ],
13+
// ],
14+
// [
15+
// 10,
16+
// [
17+
// { value: 1n, push: true },
18+
// { value: 5n, push: false },
19+
// { value: 6n, push: true },
20+
// ],
21+
// ],
22+
])("should correctly append and save", (start, elements) => {
23+
it("Using only pushIf", () => {
24+
const hashList = new DefaultProvableHashList(Field, Field(start));
25+
26+
const appended: bigint[] = [];
27+
let hash = Field(start);
28+
29+
for (let element of elements) {
30+
hashList.pushIf(Field(element.value), Bool(element.push));
31+
if (element.push) {
32+
appended.push(element.value);
33+
34+
hash = Poseidon.hash([hash, Field(element.value)]);
35+
}
36+
}
37+
38+
expect([hash]).equalProvable([hashList.commitment]);
39+
});
40+
});
41+
});

0 commit comments

Comments
 (0)