#plonk #zero-knowledge #smart-contracts #zk #near-protocol #cryptography

near_plonk_verifier

为 Near 协议智能合约实现的 Plonk 证明验证器

1 个稳定版本

1.0.0 2023年6月7日

#6#near-protocol

MIT 许可证

52KB
991

near-plonk-verifier

Rust 库,用于在 NEAR 协议智能合约中验证 plonk 零知识证明。

用例

在区块链智能合约中应用零知识密码学是这一新技术最广受赞誉的使用之一。在以太坊生态系统中,有许多应用使用零知识证明来确保在无需许可的区块链环境中数据隐私和计算效率。

借助诸如 snark.jscircom 这样的库,开发这种类型的应用变得对普通(也就是说,不是密码学专家)的开发者来说触手可及。这些工具通过抽象掉所有密码学实现,使开发者只需关注业务逻辑,从而简化了算法的构建。然而,这些工具仅与基于 EVM 的区块链兼容。对于希望基于 NEAR 协议构建 zk 应用程序的开发者来说,这些工具还不够。

鉴于此,我们开发了此库,作为一个通用的证明验证器,利用 plonk 算法。这可以与 snark.js 和 circom 一起使用,以生成一个运行 zk 证明的完整应用程序。

您可以使用此库作为 circom 教程 中的“从智能合约进行验证”部分的替代品。

如何使用它

要将此验证器实现到您的智能合约中,您必须首先设置您的逻辑电路并使用 snark.js 生成一个可信设置。此库将允许您在智能合约内部验证证明是否有效。为此,您必须

  1. 通过传递 snark.js 生成的设置值来在智能合约状态中初始化验证器
  2. 将生成者二进制文件(由 snark.js 创建)生成的证明提交到智能合约

验证器可以通过简单的导入实现

use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize};
use near_sdk::json_types::U128;
use near_sdk::{env, near_bindgen, PanicOnDefault, AccountId, BorshStorageKey};
use near_sdk::collections::{LookupSet};
use near_plonk_verifier::{self, Verifier, U256, G1Point, G2Point};

#[near_bindgen]
#[derive(PanicOnDefault, BorshDeserialize, BorshSerialize)]
pub struct Contract {
  pub verifier: Verifier,
}

impl Contract {
  #[init]
  pub fn new(
      power: U256,
      n_public: U256,
      q_m: G1Point,
      q_l: G1Point,
      q_r: G1Point,
      q_o: G1Point,
      q_c: G1Point,
      s_1: G1Point,
      s_2: G1Point,
      s_3: G1Point,
      k_1: U256,
      k_2: U256,
      x_2: G2Point,
      q: U256,
      qf: U256,
      w1: U256,
  ) -> Self {
    assert!(!env::state_exists(), "Already initialized");
    
    Self {
      verifier: Verifier::new(
        power
        n_public,
        q_m,
        q_l,
        q_r,
        q_o,
        q_c,
        s_1,
        s_2,
        s_3,
        k_1,
        k_2,
        x_2,
        q,
        qf,
        w1,
      )
    }
  }
}

Verifier 结构可以表示为一系列椭圆曲线点和标量值

#[derive(Serialize, Deserialize, BorshSerialize, BorshDeserialize, Clone, Debug)]
#[serde(crate = "near_sdk::serde")]
pub struct G1Point {
    pub x: U256,
    pub y: U256,
}

#[derive(Serialize, Deserialize, BorshSerialize, BorshDeserialize, Clone)]
#[serde(crate = "near_sdk::serde")]
pub struct G2Point {
    pub x: [U256; 2],
    pub y: [U256; 2],
}

#[derive(BorshSerialize, BorshDeserialize, Serialize, Deserialize)]
#[serde(crate = "near_sdk::serde")]
pub struct Verifier {
    pub struct Verifier {
    // n values
    power: U256,
    n: U256,
    n_public: U256,
    n_lagrange: U256,
    // Q values
    q_m: G1Point,
    q_l: G1Point,
    q_r: G1Point,
    q_o: G1Point,
    q_c: G1Point,
    // S values
    s_1: G1Point,
    s_2: G1Point,
    s_3: G1Point,
    // k values
    k_1: U256,
    k_2: U256,
    // X2 values
    x_2: G2Point,
    // Field size constants
    q: U256,
    qf: U256,
    // omega value
    w1: U256,
  }
}

要填充这些值,请参阅由 snarkjs.js 生成的 verification_key.json 文件,它将提供初始化 Verifier 所需的所有参数。

初始化验证器后,可以使用它通过 verify 方法评估电路中的任何证明,并检查其是否有效。

pub fn verify(&self, input: Vec<U256>, proof: Proof) -> bool

#[derive(Serialize, Deserialize)]
#[serde(crate = "near_sdk::serde")]
pub struct Proof {
    // public values
    public_values: Vec<U256>,
    // proof values
    a: G1Point,
    b: G1Point,
    c: G1Point,
    z: G1Point,
    t_1: G1Point,
    t_2: G1Point,
    t_3: G1Point,
    eval_a: U256,
    eval_b: U256,
    eval_c: U256,
    eval_s1: U256,
    eval_s2: U256,
    eval_zw: U256,
    eval_r: U256,
    wxi: G1Point,
    wxi_w: G1Point,
}

证明始终遵循相同的结构,并在运行验证器算法时由 snark.js 生成。它们添加了 public_values 作为向量,在 snark.js 中,公共值作为一个包含单个数组的单独 JSON 文件生成。

snark.js 在创建证明时总是生成 2 个文件。

  1. public -> 包含一个数组,这些值应传递给 public_values
  2. proof -> 包含要添加到 Proof 的其余参数

支持的 near-sdk 版本

near-plonk-verifier 基于 near-sdk 4.0.0 构建,并将定期更新以反映 near-sdk 的更新。之前的 near-sdk 版本与此库不兼容。

依赖项

~6MB
~124K SLoC