export-ton-verifier
Version:
Tool for generating a Groth16 verifier code for the TON blockchain from SnarkJS .zkey files.
124 lines (111 loc) • 3.68 kB
text/typescript
import {
Address,
beginCell,
Cell,
Contract,
contractAddress,
ContractProvider,
Sender,
SendMode,
TupleItem,
Dictionary,
} from '@ton/core';
export type VerifierConfig = {};
export function verifierConfigToCell(config: VerifierConfig): Cell {
return beginCell().endCell();
}
export const Opcodes = {
verify: 0x3b3cca17,
};
export class Verifier implements Contract {
constructor(
readonly address: Address,
readonly init?: { code: Cell; data: Cell },
) {}
static createFromAddress(address: Address) {
return new Verifier(address);
}
static createFromConfig(config: VerifierConfig, code: Cell, workchain = 0) {
const data = verifierConfigToCell(config);
const init = { code, data };
return new Verifier(contractAddress(workchain, init), init);
}
async sendDeploy(provider: ContractProvider, via: Sender, value: bigint) {
await provider.internal(via, {
value,
sendMode: SendMode.PAY_GAS_SEPARATELY,
body: beginCell().endCell(),
});
}
async sendVerify(
provider: ContractProvider,
via: Sender,
opts: {
pi_a: Buffer;
pi_b: Buffer;
pi_c: Buffer;
pubInputs: bigint[];
value: bigint;
queryID?: number;
},
) {
await provider.internal(via, {
value: opts.value,
sendMode: SendMode.PAY_GAS_SEPARATELY,
body: this.verifyBody(opts),
});
}
dictFromInputList(list: bigint[]): Dictionary<bigint, bigint> {
const dict: Dictionary<bigint, bigint> = Dictionary.empty(
Dictionary.Keys.BigUint(32),
Dictionary.Values.BigInt(256),
);
for (let i = 0; i < list.length; i++) {
dict.set(BigInt(i), list[i]);
}
return dict;
}
verifyBody(opts: {
pi_a: Buffer;
pi_b: Buffer;
pi_c: Buffer;
pubInputs: bigint[];
value: bigint;
queryID?: number;
}): Cell {
return beginCell()
.storeUint(Opcodes.verify, 32)
.storeUint(opts.queryID ?? 0, 64)
.storeRef(
beginCell()
.storeBuffer(opts.pi_a)
.storeRef(
beginCell()
.storeBuffer(opts.pi_b)
.storeRef(
beginCell().storeBuffer(opts.pi_c).storeDict(this.dictFromInputList(opts.pubInputs)),
),
),
)
.endCell();
}
async getVerify(
provider: ContractProvider,
opts: {
pi_a: Buffer;
pi_b: Buffer;
pi_c: Buffer;
pubInputs: bigint[];
},
): Promise<boolean> {
const pi_a = { type: 'slice', cell: beginCell().storeBuffer(opts.pi_a).endCell() } as TupleItem;
const pi_b = { type: 'slice', cell: beginCell().storeBuffer(opts.pi_b).endCell() } as TupleItem;
const pi_c = { type: 'slice', cell: beginCell().storeBuffer(opts.pi_c).endCell() } as TupleItem;
const pubInputs = {
type: 'slice',
cell: beginCell().storeDict(this.dictFromInputList(opts.pubInputs)).endCell(),
} as TupleItem;
const result = await provider.get('get_verify', [pi_a, pi_b, pi_c, pubInputs]);
return result.stack.readBoolean();
}
}