nil Foundation blueprint模块代码解析

1. 引言

zkllvm-blueprint库的核心思想还是借鉴了https://github.com/scipr-lab/libsnark

  • crypto3-zk库:为零知识密码学工具。当前仅支持SNARK系列的方案,未来将支持STARKs、IOP-based SNARKs、Bulletproofs等。
  • zkllvm-blueprint库:Blueprint库定义了Circuit components,供zkLLVM circuit compiler使用。
    支持与crypto3-zk一起使用:

circuit由:

  • Blueprint实例:对应电路本身、gates、constraints以及其它fixed expressions。
  • Blueprint assignment table实例:包含了zk-SNARK系统所需的public和private assignments。
    包含了:
    • Blueprint public assignment table
    • Blueprint private assignment table

组成。每个实例可包含一个或多个Component

主要示例见:

1.1 PLONK Component接口

Component X为state-less类型,包含了以下静态函数接口:

  • X::allocate_rows:分配一定行数给指定的Arithmetization table。所需的行数由特定component的constexpr决定。
  • X::generate_circuit:生成gate expressions、copy constraints、lookup constraints,并将其给特定的Blueprint
    • 会修改Blueprint public assignment table中的ConstantSelector列。
    • 但不会使用或设置Blueprint private assignment table中的数据。
  • X::generate_assignments:evaluate assignment values,并将其给特定的Blueprint assignment table
    • 仅有generate_assignment函数可管理修改Blueprint private assignment table中数据。
    • 也可修改Blueprint public assignment table中数据。

具体为:

FunctionRequired InputCan modify
X::allocate_rowsBlueprintBlueprint
X::generate_circuitBlueprint, Component params, Allocated data (auxiliary data for the component re-use), component start rowBlueprint, Allocated data
X::generate_assignmentsBlueprint assignment table, Component params, component start rowBlueprint assignment table

添加a component的流程为:

  • 1)调用allocate_rows来获取component的start row。若该component为其它component内的一部分,则没必要调用该行数,应所allocated rows由主component决定。
  • 2)调用Blueprint assignment table::allocate_public_input来给Blueprint assignment table分配public input。
  • 3)调用generate_circuit来设置Blueprint的所有gates和constraints。在generate_circuit函数运行过程中,会修改Allocated data
  • 4)调用generate_assignments来设置Blue assignment table中的所有assignments。

2. Vitalik R1CS示例

详细可参看 Vitalik 博客Quadratic Arithmetic Programs: from Zero to Hero

class test_component : public components::component<FieldType> {
    using field_type = FieldType;
    components::blueprint_variable<field_type> sym_1; //中间变量
    components::blueprint_variable<field_type> y; //中间变量
    components::blueprint_variable<field_type> sym_2; //中间变量
public:
    const components::blueprint_variable<field_type> out; //输出结果,为public input
    const components::blueprint_variable<field_type> x; //witness,为private input

    test_component(blueprint<field_type> &bp,
                const components::blueprint_variable<field_type> &out,
                const components::blueprint_variable<field_type> &x) : 
      components::component<field_type>(bp), out(out), x(x) {

      // Allocate variables to blueprint
      
      sym_1.allocate(this->bp); //分配中间变量
      y.allocate(this->bp); //分配中间变量
      sym_2.allocate(this->bp); //分配中间变量
    }

    void generate_gates() { //添加约束,生成电路。
      // x*x = sym_1
      this->bp.add_r1cs_constraint(snark::r1cs_constraint<field_type>(x, x, sym_1));

      // sym_1 * x = y
      this->bp.add_r1cs_constraint(snark::r1cs_constraint<field_type>(sym_1, x, y));

      // y + x = sym_2
      this->bp.add_r1cs_constraint(snark::r1cs_constraint<field_type>(y + x, 1, sym_2));

      // sym_2 + 5 = ~out
      this->bp.add_r1cs_constraint(snark::r1cs_constraint<field_type>(sym_2 + 5, 1, out));
    }

    void generate_assignments() { //为中间变量赋值
      this->bp.val(sym_1) = this->bp.val(x) * this->bp.val(x);
      this->bp.val(y) = this->bp.val(sym_1) * this->bp.val(x);
      this->bp.val(sym_2) = this->bp.val(y) + this->bp.val(x);
    }
};
int main(){

    using curve_type = curves::bls12<381>;
    using field_type = typename curve_type::scalar_field_type;
        
    // Create blueprint

    blueprint<field_type> bp;
    blueprint::value_type<field_type> out;
    blueprint::value_type<field_type> x;

    // Allocate variables

    out.allocate(bp); //分配变量
    x.allocate(bp);

    // This sets up the blueprint variables
    // so that the first one (out) represents the public
    // input and the rest is private input

    bp.set_input_sizes(1); //设置public input变量数为1,即表示所分配的第一个变量(out)为public input,之后的均为private input

    // Initialize component

    test_component<field_type> g(bp, out, x);
    g.generate_gates(); //添加约束,生成电路。
    
    // Add witness values

    bp.val(out) = 35; //为public和private input赋值
    bp.val(x) = 3;

    g.generate_assignments(); //为中间变量赋值
    
    assert(bp.is_satisfied()); //验证所赋变量值能否满足电路约束

    const snark::r1cs_constraint_system<field_type> constraint_system = bp.get_constraint_system(); //获取约束系统

    const typename snark::r1cs_gg_ppzksnark<curve_type>::keypair_type keypair = snark::generate<crypto3::zk::snark::r1cs_gg_ppzksnark<curve_type>>(constraint_system); //基于约束系统做可信设置,获得keypair

    const typename snark::r1cs_gg_ppzksnark<curve_type>::proof_type proof = snark::prove<crypto3::zk::snark::r1cs_gg_ppzksnark<curve_type>>(keypair.first, bp.primary_input(), bp.auxiliary_input()); //基于proving key、public(primary) input、auxiliary input(包括private input以及中间变量值)生成proof。

    bool verified = snark::verify<crypto3::zk::snark::r1cs_gg_ppzksnark<curve_type>>(keypair.second, bp.primary_input(), proof); //基于verifying key、public(primary)input和proof验证证明

    std::cout << "Number of R1CS constraints: " << constraint_system.num_constraints() << std::endl; //打印约叔叔
    std::cout << "Verification status: " << verified << std::endl;

    const typename snark::r1cs_gg_ppzksnark<curve_type>::verification_key_type vk = keypair.second;

    return 0;
}

3. Inner product示例

			class inner_product : public component<FieldType> {
                private:
                    /* S_i = \sum_{k=0}^{i} A[k] * B[k] */
                    blueprint_variable_vector<FieldType> S;

                public:
                    const blueprint_linear_combination_vector<FieldType> A;
                    const blueprint_linear_combination_vector<FieldType> B;
                    const blueprint_variable<FieldType> result;

                    inner_product(blueprint<FieldType> &bp,
                                  const blueprint_linear_combination_vector<FieldType> &A,
                                  const blueprint_linear_combination_vector<FieldType> &B,
                                  const blueprint_variable<FieldType> &result) :
                        component<FieldType>(bp),
                        A(A), B(B), result(result) {
                        assert(A.size() >= 1);
                        assert(A.size() == B.size());

                        S.allocate(bp, A.size() - 1);
                    }

                    void generate_gates() {
                        /*
                          S_i = \sum_{k=0}^{i} A[k] * B[k]
                          S[0] = A[0] * B[0]
                          S[i+1] - S[i] = A[i] * B[i]
                        */
                        for (std::size_t i = 0; i < A.size(); ++i) {
                            this->bp.add_r1cs_constraint(snark::r1cs_constraint<FieldType>(
                                A[i], B[i],
                                (i == A.size() - 1 ? result : S[i]) +
                                    (i == 0 ? 0 * blueprint_variable<FieldType>(0) : -S[i - 1])));
                        }
                    }

                    void generate_assignments() {
                        typename FieldType::value_type total = FieldType::value_type::zero();
                        for (std::size_t i = 0; i < A.size(); ++i) {
                            A[i].evaluate(this->bp);
                            B[i].evaluate(this->bp);

                            total += this->bp.lc_val(A[i]) * this->bp.lc_val(B[i]);
                            this->bp.val(i == A.size() - 1 ? result : S[i]) = total;
                        }
                    }
                };

            }    // namespace components
void test_inner_product_component(size_t n) {
    blueprint<FieldType> bp;
    nil::crypto3::zk::detail::blueprint_variable_vector<FieldType> A;
    A.allocate(bp, n);
    nil::crypto3::zk::detail::blueprint_variable_vector<FieldType> B;
    B.allocate(bp, n);

    nil::crypto3::zk::detail::blueprint_variable<FieldType> result;
    result.allocate(bp);

    components::inner_product<FieldType> g(bp, A, B, result);
    g.generate_gates();

    for (std::size_t i = 0; i < 1ul << n; ++i) {
        for (std::size_t j = 0; j < 1ul << n; ++j) {
            std::size_t correct = 0;
            for (std::size_t k = 0; k < n; ++k) {
                bp.val(A[k]) = (i & (1ul << k) ? FieldType::value_type::one() : FieldType::value_type::zero());
                bp.val(B[k]) = (j & (1ul << k) ? FieldType::value_type::one() : FieldType::value_type::zero());
                correct += ((i & (1ul << k)) && (j & (1ul << k)) ? 1 : 0);
            }

            g.generate_assignments();

            BOOST_CHECK(bp.val(result) == typename FieldType::value_type(correct));
            BOOST_CHECK(bp.is_satisfied());

            bp.val(result) = typename FieldType::value_type(100 * n + 19);
            BOOST_CHECK(!bp.is_satisfied());
        }
    }
}

4. SHA-256示例

附录 nil Foundation系列博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值