UNPKG

@unirep/contracts

Version:

Client library for contracts related functions which are used in UniRep protocol.

143 lines (142 loc) 5.69 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.tryPath = exports.compileVerifier = exports.genVerifier = exports.createVerifierName = exports.linkLibrary = void 0; const ethers_1 = require("ethers"); const path_1 = __importDefault(require("path")); const fs_1 = __importDefault(require("fs")); const solc_1 = __importDefault(require("solc")); /** * Link the library bytecode to a compiled smart contract bytecode. * @param bytecode The compiled smart contract bytecode * @param libraries The name and the address of the library * @returns The combined bytecode * @example * ```ts * linkLibrary( * incArtifacts.bytecode, * { * ['poseidon-solidity/PoseidonT3.sol:PoseidonT3']: PoseidonT3.address, * } * ) * ``` */ function linkLibrary(bytecode, libraries = {}) { let linkedBytecode = bytecode; for (const [name, address] of Object.entries(libraries)) { const placeholder = `__\$${ethers_1.utils .solidityKeccak256(['string'], [name]) .slice(2, 36)}\$__`; const formattedAddress = ethers_1.utils .getAddress(address) .toLowerCase() .replace('0x', ''); if (linkedBytecode.indexOf(placeholder) === -1) { throw new Error(`Unable to find placeholder for library ${name}`); } while (linkedBytecode.indexOf(placeholder) !== -1) { linkedBytecode = linkedBytecode.replace(placeholder, formattedAddress); } } return linkedBytecode; } exports.linkLibrary = linkLibrary; /** * Create name of the verifier contracts. Capitalize the first character and add `Verifier` at the end. * @param circuitName Name of the circuit, which can be chosen from `Circuit` */ const createVerifierName = (circuitName) => { return `${circuitName.charAt(0).toUpperCase() + circuitName.slice(1)}Verifier`; }; exports.createVerifierName = createVerifierName; /** * Generate verifier smart contract with a given verification key. * @param contractName The name of the verifier contract * @param vk The verification key which is generated by snark protocol * @returns The string of the verifier content */ const genVerifier = (contractName, vk) => { const templatePath = path_1.default.resolve(__dirname, './template/groth16Verifier.txt'); let template = fs_1.default.readFileSync(templatePath, 'utf8'); template = template.replace('<%contract_name%>', contractName); const vkalpha1 = `uint256(${vk.vk_alpha_1[0].toString()}),` + `uint256(${vk.vk_alpha_1[1].toString()})`; template = template.replace('<%vk_alpha1%>', vkalpha1); const vkbeta2 = `[uint256(${vk.vk_beta_2[0][1].toString()}),` + `uint256(${vk.vk_beta_2[0][0].toString()})], ` + `[uint256(${vk.vk_beta_2[1][1].toString()}),` + `uint256(${vk.vk_beta_2[1][0].toString()})]`; template = template.replace('<%vk_beta2%>', vkbeta2); const vkgamma2 = `[uint256(${vk.vk_gamma_2[0][1].toString()}),` + `uint256(${vk.vk_gamma_2[0][0].toString()})], ` + `[uint256(${vk.vk_gamma_2[1][1].toString()}),` + `uint256(${vk.vk_gamma_2[1][0].toString()})]`; template = template.replace('<%vk_gamma2%>', vkgamma2); const vkdelta2 = `[uint256(${vk.vk_delta_2[0][1].toString()}),` + `uint256(${vk.vk_delta_2[0][0].toString()})], ` + `[uint256(${vk.vk_delta_2[1][1].toString()}),` + `uint256(${vk.vk_delta_2[1][0].toString()})]`; template = template.replace('<%vk_delta2%>', vkdelta2); template = template.replace('<%vk_input_length%>', (vk.IC.length - 1).toString()); template = template.replace('<%vk_ic_length%>', vk.IC.length.toString()); let vi = ''; for (let i = 0; i < vk.IC.length; i++) { if (vi.length !== 0) { vi = vi + ' '; } vi = vi + `vk.IC[${i}] = Pairing.G1Point(uint256(${vk.IC[i][0].toString()}),` + `uint256(${vk.IC[i][1].toString()}));\n`; } template = template.replace('<%vk_ic_pts%>', vi); return template; }; exports.genVerifier = genVerifier; /** * Compile the verifier smart contract with `solc` * @param contractName The name of output verifier contract * @param vkey The verification key of the verifier * @returns Output the compiled `abi` and `bytecode` */ const compileVerifier = async (contractName, vkey) => { const fileName = contractName + '.sol'; const sources = {}; sources[fileName] = {}; sources[fileName]['content'] = (0, exports.genVerifier)(contractName, vkey); const input = { language: 'Solidity', sources: sources, settings: { outputSelection: { '*': { '*': ['*'], }, }, }, }; const output = JSON.parse(solc_1.default.compile(JSON.stringify(input))); return { abi: output.contracts[fileName][contractName].abi, bytecode: output.contracts[fileName][contractName].evm.bytecode.object, }; }; exports.compileVerifier = compileVerifier; /** * Try to find an artifact file in the paths. * @param file The name of the file that will be searched. * @returns The found artifacts */ function tryPath(file) { let artifacts; try { artifacts = require(path_1.default.join(__dirname, '../build/artifacts', file)); } catch (_) { artifacts = require(path_1.default.join(__dirname, '../artifacts', file)); } return artifacts; } exports.tryPath = tryPath;