o1js
Version:
TypeScript framework for zk-SNARKs and zkApps
128 lines (109 loc) • 3.81 kB
text/typescript
import { Field } from '../../../provable/field.js';
import { Provable } from '../../../provable/provable.js';
import { HashInput } from '../../../provable/types/provable-derivers.js';
import { expect } from 'expect';
export function stripPrototypes(x: any): any {
if (typeof x === 'object') {
if (x instanceof Array) {
return [...x].map(stripPrototypes);
} else {
const obj: { [key: string]: any } = {};
for (const key in Object.keys(obj)) {
obj[key] = x[key];
}
return obj;
}
} else {
return x;
}
}
export function v1FetchLayout(root: any, path: string[]): any {
let here = root;
for (const key of path) {
switch (here.type) {
case 'object':
if (!(key in here.entries))
throw new Error(`invalid layout path: object type ${here.name} does not have key ${key}`);
here = here.entries[key];
break;
case 'array':
case 'option':
if (key !== 'inner')
throw new Error(
`invalid layout path: found ${here.type}, and expected the key to be inner, but path had a key of ${key}`
);
here = here.inner;
break;
default:
throw new Error(`invalid layout path: reached ${here.type} before end of path`);
}
}
return here;
}
export type ProvableTypeDef<T> = Provable<T> & {
empty(): T;
toInput(x: T): HashInput;
};
export type V1Type<T> = ProvableTypeDef<T> & {
toJSON(x: T): any;
};
export type V2Type<InternalReprArg, V1, V2 extends V2Value<any, V1>> = ProvableTypeDef<V2> & {
fromInternalRepr(x: V1): V2;
toJSON(x: V2, arg: InternalReprArg): any;
toAuxiliary(x: V2, arg?: InternalReprArg): any;
};
export interface V2Value<InternalReprArg, V1> {
toInternalRepr(arg: InternalReprArg): V1;
toJSON(arg: InternalReprArg): any;
toFields(): Field[];
}
export function testV2Encoding<V2 extends V2Value<any, any>>(
Type: V2Type<any, any, V2>,
value: V2
) {
const fields = Type.toFields(value);
expect(fields.length).toBe(Type.sizeInFields());
expect(Type.fromFields(fields, Type.toAuxiliary(value))).toEqual(value);
}
export function testV1V2ClassEquivalence<
InternalReprArg,
V1,
V2 extends V2Value<InternalReprArg, V1>
>(V1Type: V1Type<V1>, V2Type: V2Type<InternalReprArg, V1, V2>, v2InternalReprArg: InternalReprArg) {
expect(V2Type.sizeInFields()).toBe(V1Type.sizeInFields());
testV1V2ValueEquivalence(V1Type, V2Type, V1Type.empty(), V2Type.empty(), v2InternalReprArg);
}
export function testV1V2ValueEquivalence<
InternalReprArg,
V1,
V2 extends V2Value<InternalReprArg, V1>
>(
V1Type: V1Type<V1>,
V2Type: V2Type<InternalReprArg, V1, V2>,
v1Value: V1,
v2Value: V2,
v2InternalReprArg: InternalReprArg
) {
// v2 instance and class methods match
expect(v2Value.toJSON(v2InternalReprArg)).toEqual(V2Type.toJSON(v2Value, v2InternalReprArg));
expect(v2Value.toFields()).toEqual(V2Type.toFields(v2Value));
// conversion
expect(stripPrototypes(v2Value.toInternalRepr(v2InternalReprArg))).toEqual(
stripPrototypes(v1Value)
);
expect(V2Type.fromInternalRepr(v1Value)).toEqual(v2Value);
// json equality
expect(v2Value.toJSON(v2InternalReprArg)).toEqual(V1Type.toJSON(v1Value));
// fields equality
expect(v2Value.toFields()).toEqual(V1Type.toFields(v1Value));
// auxiliary equality
expect(V2Type.toAuxiliary(v2Value, v2InternalReprArg)).toEqual(V1Type.toAuxiliary(v1Value));
// v1 -> v2 via fields
expect(V2Type.fromFields(V1Type.toFields(v1Value), V1Type.toAuxiliary(v1Value))).toEqual(v2Value);
// v1 -> v2 via fields
expect(
V1Type.fromFields(V2Type.toFields(v2Value), V2Type.toAuxiliary(v2Value, v2InternalReprArg))
).toEqual(v1Value);
// input equality
expect(V1Type.toInput(v1Value)).toEqual(V2Type.toInput(v2Value));
}