Skip to main content

zkMega v0.2 报告(Megaclite v0.2 报告)

1.回顾0.2的设计目标#

M1: ZoPatract集成arkworks-g16以及四条曲线#

  1. 准备ark的g16算法和,算法包由xxxx封装而来
  2. 准备ark的bls12_381 Curve算法包,算法包由xxxx封装而来
  3. 准备ark的bn254 Curve算法包,算法包由xxxx封装而来
  4. 将以上三个算法包集成到ZoPatract_core中.
  5. 完成CLI flag参数对新增算法包的调整支持.

M2: 实现zkSNARKs协议全阶段的CLI命令(ZoPatract_cli)#

  1. 实现verifier功能的ink!智能合约模板ink_verifier.rs,并对接到ZoPatract_cli
  2. 实现ZoPatract_cli模块的Compile、Setup、Compute-witness、Generate-proof、Export-verifier命令在Ink!智能合约环境的移植改造

M3: 实现ZoPatract的Javascript工具包(ZoPatract_js)#

  1. 实现wrapper模块对接ZoPatract_cli
  2. 实现Javascript工具包,支持API接口compile、computeWitness、setup、generateProof、exportInkVerifier

M4: 集成测试#

  1. 测试CLI对Arkworks的G16和曲线bls12_381、bn254算法包的使用
  2. 测试CLI对Compile、Setup、Compute-witness、Generate-proof、Export-verifier命令在Ink!智能合约环境的使用
  3. 测试Javascript工具包在Ink!智能合约环境与CLI的集成
  4. 使用ZoKrates高级语言编写是示例应用,使用CLI完成证明构建,并使用Javascript工具包和链上交易完成测试验证
  5. 搭建ZoPatract文档和在线安装环境

2.实现的交付物#

2.1 ZoPatract项目#

ZoPatract 是一个基于zokrates改造的适配于jupiter ink环境的zksnark toolbox.

2.2 ZoPatract的在线安装和手动安装#

One-line installation#

We provide one-line installation for Linux, MacOS and FreeBSD:

curl -LSfs get.zoprat.es | sh

From source#

You can build ZoPatract from source with the following commands:

git clone https://github.com/ZoPatract/ZoPatractcd ZoPatractcargo +nightly build --releasecd target/release

2.3 Javascript工具包#

JavaScript bindings for ZoPatract.

npm install zopatract-js

Importing#

Bundlers#

Note: As this library uses a model where the wasm module itself is natively an ES module, you will need a bundler of some form. Currently the only known bundler known to be fully compatible with zopatract-js is Webpack. The choice of this default was done to reflect the trends of the JS ecosystem.

import { initialize } from 'zopatract-js';
Node#
const { initialize } = require('zopatract-js/node');

Example#

initialize().then((zopatractProvider) => {    const source = "def main(private field a) -> field: return a * a";
    // compilation    const artifacts = zopatractProvider.compile(source);
    // computation    const { witness, output } = zopatractProvider.computeWitness(artifacts, ["2"]);
    // run setup    const keypair = zopatractProvider.setup(artifacts.program);
    // generate proof    const proof = zopatractProvider.generateProof(artifacts.program, witness, keypair.pk);
    // export solidity verifier    const verifier = zopatractProvider.exportSolidityVerifier(keypair.vk, "v1");});

2.4 ZoPatract的详细使用文档#

可以获取相关命令、高级语言、工具包和示例代码的使用信息 (项目代码/工具包/文档/示例程序)

2.5 ZoPatract开发的简单zk示例应用#

ZoPatract use bls12_381-based arkworks-groth16 algorithm case:#

First, create the text-file square_root.zop and implement your program. In this example, we will prove knowledge of the square root a of a number b:

def main(private field a, field b) -> bool:  return a * a == b

Some observations:

  • The keyword field is the basic type we use, which is an element of a given prime field.
  • The keyword private signals that we do not want to reveal this input, but still prove that we know its value.

Then run the different phases of the protocol: compile: 将zok源码压平成逻辑条件语句形式, 生成两个文件(默认 out, out.ztf), 其中 .ztf 文件是可读版.

# compile , 选择bls12_381曲线./zopatract compile -i square_root.zop -c bls12_381

setup: 执行trusted setup操作, 生成arkworks-groth16算法的CRS(Common Reference String).

输入为 compile 生成的 out, 在生成 CRS 前会会先生成 R1CS 等操作, 最终输出两个文件: proving.key 和 verification.key.

# perform the setup phase./zopatract setup -b ark -s g16

compute-witness: 命令的输入为compile生成的out, 以及计算问题的输入参数; 输出一个文件, 默认文件名为 witness.

# execute the program./zopatract compute-witness -a 12 144

generate-proof: 基于constrained system(computation problem)以及 witness 生成对应的零知识证明 proof.json.

# use arkworks groth16 algorithm to generate a proof of computation./zopatract generate-proof -b ark -s g16

verify: 验证proof.json(默认选择当前路径下的proof.json文件)

# 通过-b, -s, -c分别选择arkworks scheme, groth16 algorithm, bls12_381 curve./zopatract verify -b ark -s g16 -c bls12_381

3. 详细实现(展示核心代码)#

ZoPatract helps you use verifiable computation in your DApp, from the specification of your program in a high level language to generating proofs of computation to verifying those proofs in ink!.

3.1 ZoPatract的详细实现#

3.1.1 集成arkworks-groth16(https://github.com/arkworks-rs/groth16) 到ZoPatract#

整个设计最上层主要通过各个不同的零知识证明库去实现Backend trait来触发不同库的使用:

pub trait Backend<T: Field, S: Scheme<T>> {    fn setup(program: ir::Prog<T>) -> SetupKeypair<S::VerificationKey>;
    fn generate_proof(        program: ir::Prog<T>,        witness: ir::Witness<T>,        proving_key: Vec<u8>,    ) -> Proof<S::ProofPoints>;
    fn verify(vk: S::VerificationKey, proof: Proof<S::ProofPoints>) -> bool;}

我们给Ark struct(对标arkworks库)实现Backend trait的三个方法: 初始化生成CRS(provingkey, verifykey)

fn setup(program: Prog<T>) -> SetupKeypair<<G16 as Scheme<T>>::VerificationKey> {    let parameters = Computation::without_witness(program).groth16_setup();
    let mut pk: Vec<u8> = Vec::new();    parameters.serialize_uncompressed(&mut pk).unwrap();
    let vk = VerificationKey {        alpha: parse_g1::<T>(&parameters.vk.alpha_g1),        beta: parse_g2::<T>(&parameters.vk.beta_g2),        gamma: parse_g2::<T>(&parameters.vk.gamma_g2),        delta: parse_g2::<T>(&parameters.vk.delta_g2),        gamma_abc: parameters            .vk            .gamma_abc_g1            .iter()            .map(|g1| parse_g1::<T>(g1))            .collect(),    };    SetupKeypair::new(vk, pk)}

主要用于将dsl产生的Prog转换成computation,然后通过groth16_prove产生proof

fn generate_proof(        program: Prog<T>,        witness: Witness<T>,        proving_key: Vec<u8>,    ) -> Proof<<G16 as Scheme<T>>::ProofPoints> {    let computation = Computation::with_witness(program, witness);    let params = ProvingKey::<<T as ArkFieldExtensions>::ArkEngine>::deserialize_uncompressed(        &mut proving_key.as_slice(),    ).unwrap();
    let proof = computation.clone().groth16_prove(&params);    let proof_points = ProofPoints {        a: parse_g1::<T>(&proof.a),        b: parse_g2::<T>(&proof.b),        c: parse_g1::<T>(&proof.c),    };
    let inputs = computation        .public_inputs_values()        .iter()        .map(parse_fr::<T>)        .collect::<Vec<_>>();
    Proof::new(proof_points, inputs)}

主要做了verifykey和proof的格式转化, 封装了arkworks-groth16的verify_proof function.

fn verify(        vk: <G16 as Scheme<T>>::VerificationKey,        proof: Proof<<G16 as Scheme<T>>::ProofPoints>,    ) -> bool {    let vk = VerifyingKey {        alpha_g1: serialization::to_g1::<T>(vk.alpha),        beta_g2: serialization::to_g2::<T>(vk.beta),        gamma_g2: serialization::to_g2::<T>(vk.gamma),        delta_g2: serialization::to_g2::<T>(vk.delta),        gamma_abc_g1: vk            .gamma_abc            .into_iter()            .map(|g1| serialization::to_g1::<T>(g1))            .collect(),    };
    let ark_proof = ArkProof {        a: serialization::to_g1::<T>(proof.proof.a),        b: serialization::to_g2::<T>(proof.proof.b),        c: serialization::to_g1::<T>(proof.proof.c),    };
    let pvk: PreparedVerifyingKey<<T as ArkFieldExtensions>::ArkEngine> =        prepare_verifying_key(&vk);
    let public_inputs: Vec<_> = proof        .inputs        .iter()        .map(|s| {            T::try_from_str(s.trim_start_matches("0x"), 16)                .unwrap()                .into_ark()        })        .collect::<Vec<_>>();    verify_proof(&pvk, &ark_proof, &public_inputs).unwrap()}

通过computation_basic macro给Computation实现了封装arkworks groth16和gm17 algorithm的setup prove.

macro_rules! computation_basic {    ($algorithm:tt, $name:ident) => {        paste::item! {            impl<T: Field + ArkFieldExtensions> Computation<T> {                pub fn [<$name _prove>](self, params: &$algorithm::ProvingKey<T::ArkEngine>) -> $algorithm::Proof<T::ArkEngine> {                    let rng = &mut rand_0_7::rngs::StdRng::from_entropy();
                    let proof = $algorithm::create_random_proof(self.clone(), params, rng).unwrap();
                    let pvk = $algorithm::prepare_verifying_key(&params.vk);
                    // extract public inputs                    let public_inputs = self.public_inputs_values();
                    assert!($algorithm::verify_proof(&pvk, &proof, &public_inputs).unwrap());
                    proof                }
                pub fn [<$name _setup>](self) -> $algorithm::ProvingKey<T::ArkEngine> {                    let rng = &mut rand_0_7::rngs::StdRng::from_entropy();
                    // run setup phase                    $algorithm::generate_random_parameters(self, rng).unwrap()                }            }        }    }}
computation_basic!(ark_gm17, gm17);computation_basic!(ark_groth16, groth16);

3.1.2 集成arkworks四条曲线Bls12_377, Bls12_381, Bn254, BW6_761到ZoPatract的arkworks groth16算法:#

通过ArkFieldExtensions trait添加arkworks curve:

pub trait ArkFieldExtensions {    /// An associated type to be able to operate with ark ff traits    type ArkEngine: PairingEngine;
    fn from_ark(e:<Self::ArkEngine as ark_ec::PairingEngine>::Fr) -> Self;    fn into_ark(self) -> <Self::ArkEngine as ark_ec::PairingEngine>::Fr;}

通过ark_extensions macro给各个曲线实现ArkFieldExtensions trait:

ark_extensions!(Bls12_377);ark_extensions!(Bls12_381);ark_extensions!(Bn254);ark_extensions!(BW6_761);

通过T: trait bound可以选择不同的arkworks curves:

impl<T: Field + ArkFieldExtensions + NotBw6_761Field> Backend<T, G16> for Ark { /*Omited*/ }

3.2 集成ink合约 verfify模板的实现(模板代码在哪里,改动核心点用代码展示出来,包括export_ink_verifier,包括命令行处参数部分的改动)#

可以通过./zopatract export-verifier -t ink命令导出 ink_verifier.rs 合约模板. 实现通过InkCompatibleScheme trait的export_ink_verifier方法处理INK_CONTRACT_TEMPLATE常量字符串和CARGO_TOML常用字符串.

impl<T: InkCompatibleField> InkCompatibleScheme<T> for G16 {    fn export_ink_verifier(vk: <G16 as Scheme<T>>::VerificationKey,abi: InkAbi) -> (String,String) {        let (mut template_text,toml_text) =  match abi {            InkAbi::V1 => (String::from(INK_CONTRACT_TEMPLATE),String::from(CARGO_TOML)),            InkAbi::V2 => (String::from(INK_CONTRACT_TEMPLATE),String::from(CARGO_TOML))        };        let vk_regex = Regex::new(r#"(<%vk_[^i%]*%>)"#).unwrap();        let vk_gamma_abc_len_regex = Regex::new(r#"(<%vk_gamma_abc_len%>)"#).unwrap();        let vk_gamma_abc_regex = Regex::new(r#"(<%vk_gamma_abc%>)"#).unwrap();
        let format_g2affine = |g2:G2Affine|{            format!(                "\"{}\", \"{}\", \"{}\", \"{}\"",                (g2.0).0, (g2.0).1,                (g2.1).0, (g2.1).1        )};
        template_text = vk_regex            .replace(template_text.as_str(),format!("\"{}\",\"{}\"",vk.alpha.0,vk.alpha.1).as_str())            .into_owned();        template_text = vk_regex            .replace(template_text.as_str(), format_g2affine(vk.beta).as_str())            .into_owned();        template_text = vk_regex            .replace(template_text.as_str(),format_g2affine(vk.gamma).as_str())            .into_owned();        template_text = vk_regex            .replace(template_text.as_str(),format_g2affine(vk.delta).as_str())            .into_owned();        template_text = vk_gamma_abc_len_regex            .replace(template_text.as_str(),format!("{}", vk.gamma_abc.len()*2).as_str())            .into_owned();
        let mut vk_gamma_abc = String::new();        vk.gamma_abc.iter().for_each(|g1| {                vk_gamma_abc.extend(format!("\"{}\",\"{}\",",g1.0,g1.1).chars());        });        template_text = vk_gamma_abc_regex            .replace(template_text.as_str(),vk_gamma_abc.strip_suffix(",").unwrap())            .into_owned();        (template_text, toml_text)    }}

ink contract template(ink_verifier.rs):#

#![cfg_attr(not(feature = "std"), no_std)]use ink_lang as ink;use megaclite_arkworks::{groth16, curve::<%curve%>, result::Error};
// VK = [alpha beta gamma delta]static VK:[&str;14] = [<%vk_alpha%>,                        <%vk_beta%>,                        <%vk_gamma%>,                        <%vk_delta%>];static VK_GAMMA_ABC:[&str;<%vk_gamma_abc_len%>] =[<%vk_gamma_abc%>];
#[ink::contract]mod zop {    #[ink(storage)]    pub struct Zop {        // Stores the ZK result        result: bool,    }
    impl Zop {        /// Use false as initial value        #[ink(constructor)]        pub fn default() -> Self {            Self { result: false }        }
        #[ink(message)]        pub fn verify(&self, proof_and_input: &[u8]) -> Result<bool, Error> {            groth16::preprocessed_verify_proof::<<%curve%>>(VK, VK_GAMMA_ABC, proof_and_input)        }    }}

Cargo.toml templa:

[package]name = "zop"version = "0.1.0"authors = ["[your_name] <[your_email]>"]edition = "2018"
[dependencies]ink_primitives = { version = "3.0.0-rc2", default-features = false }ink_metadata = { version = "3.0.0-rc2", default-features = false, features = ["derive"], optional = true }ink_env = { version = "3.0.0-rc2", default-features = false }ink_storage = { version = "3.0.0-rc2", default-features = false }ink_lang = { version = "3.0.0-rc2", default-features = false }
scale = { package = "parity-scale-codec", version = "1.3", default-features = false, features = ["derive"] }scale-info = { version = "0.4.1", default-features = false, features = ["derive"], optional = true }
# megalicte zk librarymegaclite-arkworks = { git = "https://github.com/patractlabs/megaclite.git", default-features = false }
[lib]name = "zop"path = "lib.rs"crate-type = [    # Used for normal contract Wasm blobs.    "cdylib",]
[features]default = ["std"]std = [    "ink_metadata/std",    "ink_env/std",    "ink_storage/std",    "ink_primitives/std",    "scale/std",    "scale-info/std",]ink-as-dependency = []

4. 用ZoPatract在Jupiter上开发zk应用#

off-chain:#

First, create the text-file square_root.zop and implement your program. In this example, we will prove knowledge of the square root a of a number b:

def main(private field a, field b) -> bool:  return a * a == b

Then run the different phases of the protocol:#

compile: 将zok源码压平成逻辑条件语句形式, 生成两个文件(默认 out, out.ztf), 其中 .ztf 文件是可读版.

# compile , 选择bls12_381曲线./zopatract compile -i square_root.zop -c bls12_381

setup: 执行trusted setup操作, 生成arkworks-groth16算法的CRS(Common Reference String). 输入为 compile 生成的 out, 在生成的CRS 前会会先生成 R1CS 等操作, 最终输出两个文件: proving.key 和 verification.key.

# perform the setup phase./zopatract setup -b ark -s g16

导出ink_verifier.rs合约,并部署到链上:#

export-verifier: select the curve at compile phase to export ink contract-type ink_verifier.rs

./zopatract export-verifier -t ink -c bls12_381

部署: //配图

generate proof:#

compute-witness: 命令的输入为compile生成的out, 以及计算问题的输入参数; 输出一个文件, 默认文件名为 witness.

# execute the program./zopatract compute-witness -a 12 144

基于constrained system(computation problem)以及 witness 生成对应的零知识证明 proof.json和proof.txt(hex encode all data).

# use arkworks groth16 algorithm to generate a proof of computation./zopatract generate-proof -b ark -s g16

cli printed:

Generating proof...Proof hex:822a26fa4c0a7fbcc725dd45f89d9a33fd69f0545702c55dfe6e5c36f987b9de3a48b53df6e9c2ce04e51dc479307f0281fbdbec9b1510435f8d3b1b6649d408e71f7e61a78d00156e42d7eef6a68f1e6b14b3a0c209e133e5d0fecbf17c2d1500647ec3b72e31d59ed2dc3d4ac84111db3d505c7d0d376e2f5b406c302d927c939e01f76a6298f3e751d7624a72c5d3196abea9d14509701344da6eb3b10d235068dd1f113d78a63b108f64da5c4a13117776a2a6cb8a765f020f569e56172c15cc94eb9d5aba92ec0ad775b14beeca44b9f6db7e6d74d9594a731c40e7cc31b13b140d12e04e0b087315f72624dd97188c9dd182e1607cf18ae48981be0a86a9fa62a696a88e57eee3dad0c5a24f6a5df938a48c77265f595a9765c0cad25c110052c05fa24dc8058811bbeeeced871472451c23370f924854e328198088e533f070f9b7e5636bcd9b4dfd1af96d6b7a0564d4660f7f0e1e75cc25f6c55cd1f1e8db29f105286fd48a5c90394b50b8b2641949f8d62b22778b0bc3b56ee12cbb050090000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000

发送proof到链上:#

通过postman将hex proof或proof.txt内容以交易形式发送到链上: // Todo 配图

On chain#

链上验证结果: // 配图

回顾验证信息#

  • ZoPatract_core integrates arkworks-g16、arkworks-bls12_381、arkworks-bn254
  • Implement CLI command for the whole phase of Zksnarks agreement (Zopatract_cli)
  • The Ink smart contract template ink_verifier.rs that implements the verifier function is connected to Zopatract_cli's export-verifier.
  • Modify the Zopatract JavaScript toolkit
  • Test CLI's use of Arkworks groth16 algorithm and curve Bls12_381 and Bn254 curve package
  • Test CLI on compile, setup, compute-witness, generate-proof, export-verifier commands in ink! smart contract environments.