最近看知乎,發(fā)現(xiàn)知乎上有些文章真的醍醐灌頂。印象比較深的是,文因互聯(lián)CEO 鮑捷的一篇文章:最快的成長(zhǎng)方式就是慢慢來。創(chuàng)業(yè)最關(guān)鍵的能力
最近看知乎,發(fā)現(xiàn)知乎上有些文章真的醍醐灌頂。印象比較深的是,文因互聯(lián)CEO 鮑捷的一篇文章:最快的成長(zhǎng)方式就是慢慢來。創(chuàng)業(yè)最關(guān)鍵的能力,就是“不被卡住”的能力。這才是“探索力”的根本,是創(chuàng)業(yè)“執(zhí)行力”的核心。
很多人都熟悉讓別人告知一個(gè)明確的目標(biāo),然后清晰的執(zhí)行。但是,創(chuàng)業(yè)是一種探索,沒有人會(huì)告訴你這樣的明確的目標(biāo)。探索,是一種反人性的活動(dòng)。大多數(shù)人會(huì)對(duì)探索畏懼,恐懼,抵觸,茫然。
“不被卡住”,需要掌握好“任務(wù)分解,快速迭代”的方法論,需要建立“交付”的態(tài)度(每個(gè)時(shí)期結(jié)束都有可交付的狀態(tài)),需要“勤于溝通”, 需要”不固執(zhí)己見“,更需要”不斷復(fù)盤“。”不被卡住“,還有個(gè)要注意的是,有多少本錢打多少仗,不要總想著打大仗,要學(xué)會(huì)從小仗慢慢打。
ethsnarks在libsnark的基礎(chǔ)上,實(shí)現(xiàn)了以太坊上與zkSNARK相關(guān)的智能合約和電路。ethsnarks本身也是libsnark應(yīng)用很好的學(xué)習(xí)示例。
ethsnarks的源代碼地址:
https://github.com/HarryR/ethsnarks.git
本文中使用的ethsnarks源代碼的最后一個(gè)commit如下:
commit 9adc64355adb9154ba5042c0fadf84c438b8a08a
Author: Wanseob Lim
Date: Fri Aug 16 01:49:19 2019 +0900
Add Fr field class to the field.py
1. 源代碼結(jié)構(gòu)
contracts - 實(shí)現(xiàn)了groth16的驗(yàn)證智能合約(Verifier.sol),橢圓曲線的計(jì)算,MerkleTree以及MiMC Hash計(jì)算的智能合約。這些智能合約可以通過truffle進(jìn)行部署測(cè)試。部署相關(guān)的腳本在migrations目錄下。
ethsnarks - python實(shí)現(xiàn)的相關(guān)功能,包括pedersen/mimc/poseidon等hash函數(shù),groth16驗(yàn)證,以及橢圓曲線的計(jì)算。
test - 以上兩個(gè)功能的測(cè)試代碼,采用python語言實(shí)現(xiàn)。
depends - 依賴庫(kù),包括libsnark,libfqfft等等。
src - 基于libsnark的gadget1庫(kù)實(shí)現(xiàn)的更多的gadget。本文著重介紹這些gadget的實(shí)現(xiàn)。
2. gadget實(shí)現(xiàn)
src目錄下的源代碼結(jié)構(gòu)如下:
2.1 ethsnarks.hpp
libsnark的gadget1庫(kù)主要圍繞sha256(基于bit的hash函數(shù))實(shí)現(xiàn)各種gadgets。ethsnarks在alt_bn128這條橢圓曲線上實(shí)現(xiàn)了基于Field的hash函數(shù)(mimc,pedersen,poseidon等)。
libsnark的電路中各種定義都非常長(zhǎng)。libsnark定義一個(gè)變量數(shù)組類型:pb_variable_array
ethsnarks.hpp精簡(jiǎn)了在alt_bn128這條橢圓曲線相關(guān)的類型聲明:
namespace ethsnarks {
typedef libff::bigint
typedef libff::alt_bn128_G1 G1T;
typedef libff::alt_bn128_G2 G2T;
typedef libff::alt_bn128_pp ppT;
typedef libff::Fq
typedef libff::Fr
typedef libsnark::r1cs_constraint
typedef libsnark::protoboard
typedef libsnark::pb_variable
typedef libsnark::pb_variable_array
typedef libsnark::pb_linear_combination
typedef libsnark::pb_linear_combination_array
typedef libsnark::linear_term
typedef libsnark::gadget
typedef libsnark::r1cs_gg_ppzksnark_zok_proof
typedef libsnark::r1cs_gg_ppzksnark_zok_proving_key
typedef libsnark::r1cs_gg_ppzksnark_zok_verification_key
typedef libsnark::r1cs_gg_ppzksnark_zok_primary_input
typedef libsnark::r1cs_gg_ppzksnark_zok_auxiliary_input
}
其中,F(xiàn)ieldT特指在alt_bn128線上的點(diǎn)的個(gè)數(shù)。
2.2 utils.hpp/utils.cpp
utils實(shí)現(xiàn)了電路實(shí)現(xiàn)中常用的功能性函數(shù)。
inline const VariableT make_variable( ProtoboardT &in_pb, const std::string &annotation )
{
VariableT x;
x.allocate(in_pb, annotation);
return x;
}
make_variable創(chuàng)建一個(gè)VariableT。
const VariableArrayT flatten( const std::vector
{
size_t total_sz = 0;
for( const auto& scalar : in_scalars )
total_sz += scalar.size();
VariableArrayT result;
result.resize(total_sz);
size_t offset = 0;
for( const auto& scalar : in_scalars )
{
for( size_t i = 0; i < scalar.size(); i++ )
{
result[offset++].index = scalar[i].index;
}
}
return result;
}
flatten函數(shù)將多個(gè)VariableArrayT合并成一個(gè)VariableArray。其實(shí)也很簡(jiǎn)單,就是把VariableArray中的index都合并到一個(gè)VariableArray中。
2.3 r1cs_gg_ppzksnark_zok
在libsnark的r1cs_gg_ppzksnark的基礎(chǔ)上,稍做改動(dòng),讓以太坊的預(yù)編譯智能合約能驗(yàn)證groth16的算法。r1cs_gg_ppzksnark_zok目錄中的README.md很清晰的解釋了改動(dòng)的原因。
從以太坊的拜占庭硬分叉之后,以太坊引入了基于ALT_BN128的配對(duì)函數(shù)計(jì)算的預(yù)編譯合約,合約實(shí)現(xiàn)的功能如下:
給定ALT_BN128上兩個(gè)基點(diǎn)(G1/G2)一系列的點(diǎn)(a1, b1, a2, b2, ..., ak, bk),預(yù)編譯合約能檢查:
e(a1, b1) * ... * e(ak, bk) 是否等于1?
Groth16原有的驗(yàn)證系數(shù)為:vk.alpha_beta,vk.gamma以及vk.delta。Groth16的驗(yàn)證等式為:
vk.alpha_beta = e(A, B) * e(-x, vk.gamma) * e(-C, vk.delta)
其中vk.alpha_beta為e(alpha, beta)。
如果直接用之前的驗(yàn)證等式,以太坊上的預(yù)編譯合約沒法實(shí)現(xiàn)。在不影響Groth16的安全性的情況下,將Groth16的驗(yàn)證系數(shù)變?yōu)椋簐k.alpha,vk.beta,vk.gamma以及vk.delta。Groth16的驗(yàn)證等式也變?yōu)椋?/p>
e(A, B) * e(-x, vk.gamma) * e(-C, vk.delta) * e(-alpha, beta) = 1
r1cs_gg_ppzksnark_zok目錄就是實(shí)現(xiàn)如上的改動(dòng)。同時(shí)提供了stubs.hpp/stubs.cpp,從json文件中讀取相應(yīng)的驗(yàn)證參數(shù)進(jìn)行驗(yàn)證。
2.4 poseidon
poseidon算法的實(shí)現(xiàn)在gadgets/poseidon.hpp文件中。
template
using Poseidon128 = Poseidon_gadget_T<6, 1, 8, 57, nInputs, nOutputs, constrainOutputs>;
Poseidon128是Poseidon_gadget_T的一個(gè)實(shí)例。前面四個(gè)參數(shù)是poseidon算法的參數(shù),后續(xù)會(huì)寫文章詳細(xì)介紹poseidon算法以及這些參數(shù)的含義(6,1,8,57是默認(rèn)的配置)。nInputs指定算法的輸入的個(gè)數(shù),nOutputs指定輸出的個(gè)數(shù),contrainOutputs指定是否對(duì)輸出進(jìn)行約束。
Poseidon_gadget_T的構(gòu)造函數(shù)如下:
Poseidon_gadget_T(
ProtoboardT &pb,
const VariableArrayT& in_inputs,
const std::string& annotation_prefix
) :
GadgetT(pb, annotation_prefix),
inputs(in_inputs),
constants(poseidon_params
first_round(pb, constants.C[0], constants.M, in_inputs, FMT(annotation_prefix, ".round[0]")),
prefix_full_rounds(
make_rounds
1, partial_begin, pb,
first_round.outputs, constants, annotation_prefix)),
partial_rounds(
make_rounds
partial_begin, partial_end, pb,
prefix_full_rounds.back().outputs, constants, annotation_prefix)),
suffix_full_rounds(
make_rounds
partial_end, total_rounds-1, pb,
partial_rounds.back().outputs, constants, annotation_prefix)),
last_round(pb, constants.C.back(), constants.M, suffix_full_rounds.back().outputs, FMT(annotation_prefix, ".round[%u]", total_rounds-1)),
_output_vars(constrainOutputs ? make_var_array(pb, nOutputs, ".output") : VariableArrayT())
{
}
poseidon算法的計(jì)算由好幾輪組成:first_round(第一輪),prefix_full_rounds(預(yù)處理,完整輪),partial_rounds(中間,不完整輪),suffix_full_rounds(后處理,完整輪)以及l(fā)ast_round(最后一輪)。
_output_vars是輸出的變量。這些輪都是通過make_rounds函數(shù)實(shí)現(xiàn)。
template
static const std::vector
unsigned n_begin, unsigned n_end,
ProtoboardT& pb,
const std::vector
const PoseidonConstants& constants,
const std::string& annotation_prefix)
{
std::vector
result.reserve(n_end - n_begin);
for( unsigned i = n_begin; i < n_end; i++ )
{
const auto& state = (i == n_begin) ? inputs : result.back().outputs;
result.emplace_back(pb, constants.C[i], constants.M, state, FMT(annotation_prefix, ".round[%u]", i));
}
return result;
}
make_rounds就是為每一輪準(zhǔn)備合適的參數(shù)。每一輪的具體實(shí)現(xiàn)通過Poseidon_Round實(shí)現(xiàn)。
在Poseidon_Round的封裝下,Poseidon_gadget_T的generate_r1cs_constraints以及generate_r1cs_witness相對(duì)簡(jiǎn)單,小伙伴們可以自行查看源代碼。
3. 示例代碼
在ethsnarks的基礎(chǔ)上,實(shí)現(xiàn)Poseidon函數(shù)的電路就非常簡(jiǎn)單了。構(gòu)造一個(gè)簡(jiǎn)單的電路,給大家參考一下。
電路的需求:實(shí)現(xiàn)Poseidon計(jì)算,輸入為兩個(gè)FieldT,輸出為一個(gè)FieldT。輸出作為電路的public input。
#include "ethsnarks.hpp"
#include "gadgets/poseidon.hpp"
using namespace ethsnarks;
namespace testproject {
using TestHash = Poseidon128<2, 1>;
class test_gadget : public GadgetT {
public:
VariableT output;
VariableT input0;
VariableT input1;
TestHash tHash;
test_gadget(
ProtoboardT& pb,
const std::string& prefix
) : GadgetT(pb, prefix),
output(make_variable(pb, FMT(prefix, ".output"))),
input0(make_variable(pb, FMT(prefix, ".input0"))),
input1(make_variable(pb, FMT(prefix, ".input1"))),
tHash(pb, create_var_array({input0, input1}), FMT(prefix, ".testhash"))
{
}
void generate_r1cs_witness(
ethsnarks::FieldT w_input0,
ethsnarks::FieldT w_input1,
ethsnarks::FieldT w_output)
{
pb.val(input0) = w_input0;
pb.val(input1) = w_input1;
pb.val(output) = w_output;
tHash.generate_r1cs_witness();
}
void generate_r1cs_constraints()
{
pb.set_input_sizes(1);
tHash.generate_r1cs_constraints();
pb.add_r1cs_constraint(ConstraintT(output, 1, tHash.result()),
FMT(annotation_prefix, " output == Poseidon(input0 || input1)"));
}
};
};
總結(jié):
ethsnarks在libsnark的基礎(chǔ)上,實(shí)現(xiàn)了以太坊上與zkSNARK相關(guān)的智能合約和電路。ethsnarks本身也是libsnark應(yīng)用很好的學(xué)習(xí)示例。libsnark的gadget1庫(kù)主要圍繞sha256(基于bit的hash函數(shù))實(shí)現(xiàn)各種gadgets。ethsnarks在alt_bn128這條橢圓曲線上實(shí)現(xiàn)了基于Field的hash函數(shù)(mimc,pedersen,poseidon等)。(Star Li)