libsnark教程

原文出自:libsnark庫
作者:libsnark貢獻(xiàn)者
譯者:Matter實(shí)驗(yàn)室

gadgetlib2庫的使用以及如何整合ppzkSNARK的教程和范例。這分文檔專為小零件(gadget)寫的,推薦從上至下作為教程來閱讀。

1. 面包板(protoboard)的使用和范例

這個(gè)測(cè)試給出構(gòu)造系統(tǒng)限制(constraint)的第一個(gè)范例。我們將時(shí)不時(shí)交替使用 ‘系統(tǒng)限制’(Constraint) 和 ‘電路’(Circuit) 兩個(gè)術(shù)語. 用輸入和輸出形象化一個(gè)電路非常容易。每個(gè)門強(qiáng)制規(guī)定輸入和輸出線之間的邏輯。例如,AND(inp1,inp2) 會(huì)強(qiáng)制 (inp1 & inp2 = out) 這個(gè)限制。因此,我們也能認(rèn)為這個(gè)電路是一個(gè)限制系統(tǒng)。每個(gè)門是一個(gè)數(shù)學(xué)限制,每個(gè)線是一個(gè)變量。在AND的例子中,通過boolean類型{0,1}我們將寫出一個(gè)像(inp1*inp2==out)這樣的限制。如果我們指派值到{inp1,inp2,out},并且這個(gè)限制對(duì)于這樣的賦值是滿足的,因此對(duì)這個(gè)限制的評(píng)估就是TRUE。所有接下來的例子是要么是領(lǐng)域不可知或素?cái)?shù)字段的特殊形式。

  1. 領(lǐng)域不可知情況:在這些例子中,我們用低級(jí)電路來創(chuàng)建一個(gè)高級(jí)電路。這種方法我們可以忽略一個(gè)字段的具體的情況,并假定低級(jí)電路會(huì)處理這個(gè)。如果我們必須在這些電路中顯示的寫出限制。這種情況常常是一下非?;A(chǔ)的限制,并可以定義在每個(gè)字段上,例如(e.g. x+y=0)。

  2. 所有字段都具體的例子,在這個(gè)庫中,是對(duì)素?cái)?shù)性質(zhì)的字段來說的,采用的是‘二次秩1多項(xiàng)式’或者叫R1P 。這是當(dāng)前SNARKs實(shí)現(xiàn)的唯一形式。這種形式專門處理像(Linear Combination) * (Linear Combination) == (Linear Combination)這樣的限制。這個(gè)庫已經(jīng)被設(shè)計(jì)成允許未來加入其他的特性或形式,目前只為這樣的形式實(shí)現(xiàn)了低級(jí)電路。

1. 代碼與過程

初始化素?cái)?shù)字段參數(shù),R1P總是需要這么做。

initPublicParamsFromDefaultPp();

面包版是一個(gè)“內(nèi)存管理器”,它維護(hù)所有的限制(當(dāng)創(chuàng)建驗(yàn)證電路的時(shí)候)和變量賦值(當(dāng)創(chuàng)建證明證人的時(shí)候)。我們特別說明這個(gè)R1P的類型,能在未來增加對(duì)BOOLEAN或GF2_EXTENSION字段的支持。

ProtoboardPtr pb = Protoboard::create(R1P);

現(xiàn)在我們創(chuàng)建三個(gè)輸入和一個(gè)輸出

VariableArray input(3, "input");
Variable output("output");

我們現(xiàn)在可以添加一些限制,其中字符串的目的是為了調(diào)試方便,并且能夠給這個(gè)限制一個(gè)文本說明。

pb->addRank1Constraint(
    input[0],
    5 + input[2],
    output,
    "Constraint 1: input[0] * (5 + input[2]) == output"
);

第二種形式是添加一個(gè)一元限制,這個(gè)意味著(LinearCombination == 0)

pb->addUnaryConstraint(
    input[1] - output,
    "Constraint 2: input[1] - output == 0"
);

注意到這樣寫也是可以的:

pb->addRank1Constraint(1, input[1] - input[2], 0, "");

對(duì)于更加一般化形式的字段,可以一次性實(shí)現(xiàn),我們可以使用addGeneralConstraint(Polynomial1, Polynomial2, string)會(huì)轉(zhuǎn)換成(Polynomial1 == Polynomial2)限制。例如:

pb->addGeneralConstraint(
  input[0] * (3 + input[1]) * input[2], 
  output + 5,
  "input[0] * (3 + input[1]) * input[2] == output + 5"
);

現(xiàn)在我們能將值賦給變量了,并且看一看限制是否滿足。之后,當(dāng)我們運(yùn)行SNARK(或者任何其他證明系統(tǒng))的時(shí)候,這些限制將會(huì)被驗(yàn)證者(verifier)使用,并且指派的值被證明者(prover)使用。

注意到面包版(protoboard)存儲(chǔ)了被指派的值。

pb->val(input[0]) =
pb->val(input[1]) =
pb->val(input[2]) =
pb->val(output) = 42;

EXPECT_FALSE(pb->isSatisfied());

這個(gè)限制系統(tǒng)是沒有被滿足的,現(xiàn)在讓我們嘗試一下可以滿足上面兩個(gè)等式的值。
The constraint system is not satisfied. Now let's try values which satisfy the two equations above:

pb->val(input[0]) = 1;
pb->val(input[1]) = 
pb->val(output) = 42;    // input[1]-output == 0
pb->val(input[2]) = 37;  // 1*(5+37)==42

EXPECT_TRUE(pb->isSatisfied());

2. Gadget與非的例子

在上面的例子中,我們清晰的寫了所有的限制和賦值。

在這個(gè)例子中,我們將構(gòu)造一個(gè)非常簡(jiǎn)單的gadget,一個(gè)實(shí)現(xiàn)了與非(NAND)的門。這個(gè)gadget是字段無關(guān)的,因?yàn)樗皇褂昧说图?jí)的gadget以及字段元素 '0' & '1'

Gadget是一個(gè)允許我們委托復(fù)雜電路元件到低層的框架。依靠限定與賦值以及利用子gadget,每一個(gè)gadget能夠構(gòu)造一個(gè)限定系統(tǒng)或證明者,或是兩者一起。。

1. 主過程

下面這個(gè)測(cè)試用來說明使用方法:

初始化字段

    initPublicParamsFromDefaultPp();

用R1P系統(tǒng)的類型創(chuàng)建一個(gè)面包板。

    ProtoboardPtr pb = Protoboard::create(R1P);

創(chuàng)建5個(gè)變量inputs[0]...inputs[4]。字符串“inputs”是調(diào)試信息。

    FlagVariableArray inputs(5, "inputs");
    FlagVariable output("output");
    GadgetPtr nandGadget = NAND_Gadget::create(pb, inputs, output);

現(xiàn)在我們能生成一個(gè)限定系統(tǒng)(或電路)

    nandGadget->generateConstraints();

如果我們現(xiàn)在嘗試去計(jì)算這個(gè)電路,一個(gè)異常會(huì)被拋出來,因?yàn)槲覀兤髨D計(jì)算沒有賦值的變量。

    EXPECT_ANY_THROW(pb->isSatisfied());

因此讓我們對(duì)這個(gè)輸入變量賦值,這么就可以進(jìn)行與非(NAND)計(jì)算,并且在創(chuàng)建證據(jù)之后,再次嘗試計(jì)算這個(gè)電路。

    for (const auto& input : inputs) {
        pb->val(input) = 1;
    }
    nandGadget->generateWitness();
    EXPECT_TRUE(pb->isSatisfied());
    EXPECT_TRUE(pb->val(output) == 0);

現(xiàn)在讓我們毀壞某些東西,并看看發(fā)生了什么?

    pb->val(inputs[2]) = 0;
    EXPECT_FALSE(pb->isSatisfied());

現(xiàn)在讓我們嘗試欺騙一下。如果我們沒有強(qiáng)制要求boolean化,這應(yīng)該是能運(yùn)行的。

    pb->val(inputs[1]) = 2;
    EXPECT_FALSE(pb->isSatisfied());

現(xiàn)在讓我們重新設(shè)置inputs[1]為一個(gè)正確的值。

    pb->val(inputs[1]) = 1;

之前我們?cè)O(shè)置了inputs和output。注意到output仍然是'0'。

    // before, we set both the inputs and the output. Notice the output is still set to '0'
    EXPECT_TRUE(pb->val(output) == 0);

現(xiàn)在我們將使gadget利用generateWitness() 創(chuàng)建證據(jù)計(jì)算出結(jié)果并且看發(fā)生了什么?

    nandGadget->generateWitness();
    EXPECT_TRUE(pb->val(output) == 1);
    EXPECT_TRUE(pb->isSatisfied());

3. hash難度執(zhí)行者例子

另外一個(gè)例子展示雙重變量的使用。一個(gè)雙重變量是一個(gè)具有下面兩種特性的變量,字的安位表現(xiàn)形式,以及可包裝的展現(xiàn)形式(例如,包裝值 {42} 和非包裝值 {1,0,1,0,1,0} )。如果這個(gè)字夠短(比如,小于它主要特征的任何整數(shù)),那么包裝起來的表達(dá)方式將被存儲(chǔ)在一個(gè)元素字段中。字在這個(gè)上下文中的意思是一組二進(jìn)制位,這是一個(gè)慣例,意味著我們期待一些語義能力去分解包裝的值到二進(jìn)制位去。

使用雙重變量是為了提高效率。更多的展示在例子的結(jié)尾。在這個(gè)例子中我們將構(gòu)造一個(gè)gadget,這個(gè)gadget接收一個(gè)包裝的整數(shù)作為輸入稱為'hash',和一個(gè)二進(jìn)制位的‘難度’級(jí)別,以及構(gòu)造一個(gè)用來證明‘hash’上第一個(gè)‘難度’位是0的電路。為了簡(jiǎn)單,我們將假定‘hash’總是64位長度。

1. 主過程

記得我們指出,雙重變量被用來提升效率?,F(xiàn)在就是詳細(xì)說明這個(gè)的時(shí)候。就像你看到的,我們需要一個(gè)位表達(dá)來檢查hashValue的第一個(gè)位。但是hashValue可能被用于很多其他的地方,因?yàn)槲覀兿胍獧z查實(shí)例是否與另一個(gè)值相等。在包裝的表達(dá)上檢查相等會(huì)‘消耗’我們一個(gè)限定,當(dāng)在沒有包裝的值上檢查相等的時(shí)候,將‘消耗’我們64個(gè)限制。在ppzkSNARK證明系統(tǒng)中,這個(gè)轉(zhuǎn)換會(huì)加重構(gòu)造證明的時(shí)間和內(nèi)存消耗。

    initPublicParamsFromDefaultPp();
    auto pb = Protoboard::create(R1P);
    const MultiPackedWord hashValue(64, R1P, "hashValue");
    const size_t difficulty = 10;
    auto difficultyEnforcer = HashDifficultyEnforcer_Gadget::create(pb, hashValue, difficulty);
    difficultyEnforcer->generateConstraints();

現(xiàn)在限制以及創(chuàng)建,但是還沒有賦值。在計(jì)算是會(huì)拋出異常。

    EXPECT_ANY_THROW(pb->isSatisfied());
    pb->val(hashValue[0]) = 42;
    difficultyEnforcer->generateWitness();

42的起始的10個(gè)位(當(dāng)以64位數(shù)形式展示的時(shí)候)都是'0',因此應(yīng)該可以工作。

    EXPECT_TRUE(pb->isSatisfied(PrintOptions::DBG_PRINT_IF_NOT_SATISFIED));
    pb->val(hashValue[0]) = 1000000000000000000;

這個(gè)值大于2^54,因此我們期待限制系統(tǒng)不會(huì)被滿足。
在斷言之前,generateWitness應(yīng)該就失敗了。

    difficultyEnforcer->generateWitness();
    EXPECT_FALSE(pb->isSatisfied());

4. R1P驗(yàn)證交易金額例子

在這個(gè)例子中,我們將構(gòu)造一個(gè)gadget,這個(gè)gadget構(gòu)建了一個(gè)證明(證據(jù))電路,并且認(rèn)可(限制)一個(gè)比特幣交易輸入的數(shù)量必須等于輸出+礦工費(fèi)。證明的限制將包括找到礦工的費(fèi)用。這個(gè)費(fèi)用能夠作為電路的輸出被考慮。

這是特定領(lǐng)域的gadget,就像我們將要用的 '+'操作一樣自由。在主特性領(lǐng)域而非在擴(kuò)展領(lǐng)域,加法操作像所期望的一樣工作在整數(shù)上。如果你不熟悉擴(kuò)展領(lǐng)域,不用擔(dān)心。應(yīng)該簡(jiǎn)單的意識(shí)到 +* 在不同的領(lǐng)域表現(xiàn)得不一樣,并且不一定給出你期望的整數(shù)值。

由于要用到不同的場(chǎng)景下,這個(gè)庫的設(shè)計(jì)支持多域構(gòu)造。當(dāng)其他的應(yīng)用使用主要域的時(shí)候一些加密圖應(yīng)用可能需要擴(kuò)展域,但是,用使用非rank-1的限制,并且有些可能還需要boolean電路。在新域或限制構(gòu)造上,這個(gè)庫的設(shè)計(jì)使高層次的gadget能夠重用底層的實(shí)現(xiàn)。

之后通過使用不可知接口,我們將提供一個(gè)創(chuàng)建這種特殊領(lǐng)域gadget的訣竅。我們?cè)谶@兒使用一些慣例,采用宏將這個(gè)過程變得容易。

1. Gadget定義

這是一個(gè)為所有的特定域創(chuàng)建一個(gè)繼承自gadget接口類的宏。
慣用法是:class {GadgetName}_GadgetBase

CREATE_GADGET_BASE_CLASS(VerifyTransactionAmounts_GadgetBase);

注意這里的多繼承。我們必須指定接口以及基礎(chǔ)gadget的特殊域。這允許類工廠在編譯期決定,特定的類需要為每個(gè)面包板實(shí)例化哪種域。可以在"gadget.hpp"中看到這個(gè)設(shè)計(jì)的信息。

慣用法:class {FieldType}_{GadgetName}_Gadget

#1: 我們給出工廠類的友元訪問為了實(shí)例化私有的構(gòu)造函數(shù)。

class R1P_VerifyTransactionAmounts_Gadget : public VerifyTransactionAmounts_GadgetBase,
                                            public R1P_Gadget {
public:
    void generateConstraints();
    void generateWitness();

    friend class VerifyTransactionAmounts_Gadget;  // #1
private:
    R1P_VerifyTransactionAmounts_Gadget(ProtoboardPtr pb,
                                        const VariableArray& txInputAmounts,
                                        const VariableArray& txOutputAmounts,
                                        const Variable& minersFee);
    void init();

    const VariableArray txInputAmounts_;
    const VariableArray txOutputAmounts_;
    const Variable minersFee_;

    DISALLOW_COPY_AND_ASSIGN(R1P_VerifyTransactionAmounts_Gadget);
};

使用宏CREATE_GADGET_FACTORY_CLASS_XX創(chuàng)建工廠類(用構(gòu)造函數(shù)的參數(shù)數(shù)量替換XX,protoboard不算)。有時(shí)候我們像要多構(gòu)造函數(shù),可以參照AND_Gadget。在這個(gè)場(chǎng)景下,我們將手工寫出工廠類。

CREATE_GADGET_FACTORY_CLASS_3(
          VerifyTransactionAmounts_Gadget,
          VariableArray, txInputAmounts,
          VariableArray, txOutputAmounts,
          Variable, minersFee
);
2. Gadget實(shí)現(xiàn)

為基類實(shí)現(xiàn)空析構(gòu)函數(shù)

VerifyTransactionAmounts_GadgetBase::~VerifyTransactionAmounts_GadgetBase() {}

看起來下面這點(diǎn)實(shí)現(xiàn)就足夠了,但是一個(gè)對(duì)抗者可能在域的模數(shù)上引起等式的一邊溢出。事實(shí)上,對(duì)于每個(gè)輸入/輸出的和我們總是會(huì)找到一個(gè)礦工的服務(wù)費(fèi)滿足這個(gè)限制。只剩下一個(gè)給讀者的練習(xí),實(shí)現(xiàn)一個(gè)加法限制(和證據(jù)),用來檢查每個(gè)數(shù)量(輸入,輸出,費(fèi)用)在0和21,000,000 * 1E8 中本村之間。用最大的輸入/輸出數(shù)量組合這個(gè)數(shù)防止域溢出。

提示:使用Comparison_Gadget創(chuàng)建gadget,這個(gè)gadget將一個(gè)變量的值與常數(shù)做比較。使用這些新gadget的數(shù)組去檢查各自的值。
不要忘記:

  1. 在init()中連接這些gadgets。
  2. 在generateConstraints()中調(diào)用這些gadgets的限定。
  3. 在generateWitness()中調(diào)用這些gadgets的證據(jù)。

#1 注意我們必須初始化3個(gè)基類(菱形繼承)

void R1P_VerifyTransactionAmounts_Gadget::generateConstraints() {
    addUnaryConstraint(
        sum(txInputAmounts_) - sum(txOutputAmounts_) - minersFee_,
        "sum(txInputAmounts) == sum(txOutputAmounts) + minersFee"
    );
}

void R1P_VerifyTransactionAmounts_Gadget::generateWitness() {
    FElem sumInputs = 0;
    FElem sumOutputs = 0;
    for (const auto& inputAmount : txInputAmounts_) {
        sumInputs += val(inputAmount);
    }
    for (const auto& outputAmount : txOutputAmounts_) {
        sumOutputs += val(outputAmount);
    }
    val(minersFee_) = sumInputs - sumOutputs;
}

R1P_VerifyTransactionAmounts_Gadget::R1P_VerifyTransactionAmounts_Gadget(
        ProtoboardPtr pb,
        const VariableArray& txInputAmounts,
        const VariableArray& txOutputAmounts,
        const Variable& minersFee
):
        Gadget(pb),
        VerifyTransactionAmounts_GadgetBase(pb),
        R1P_Gadget(pb),   // #1
        txInputAmounts_(txInputAmounts), 
        txOutputAmounts_(txOutputAmounts),
        minersFee_(minersFee) {}

void R1P_VerifyTransactionAmounts_Gadget::init() {}
2. 主流程

按照約定,用不可知接口創(chuàng)建一個(gè)特定域gadgets的訣竅是:

  1. 用宏創(chuàng)建一個(gè)基類:
    CREATE_GADGET_BASE_CLASS({GadgetName}_GadgetBase);

  2. 為基類創(chuàng)建一個(gè)構(gòu)造函數(shù):
    {GadgetName_Gadget}Base::~{GadgetName}_GadgetBase() {}

  3. 使用多繼承創(chuàng)建你需要的特定域gadgets。
    class {FieldType}_{GadgetName}_Gadget :
    public {GadgetName}_GadgetBase,
    public {FieldType_Gadget}

    注意到為了使用工廠類宏,構(gòu)造函數(shù)的所有參數(shù)必須是 const&。構(gòu)造參數(shù)必須與所有的特定域?qū)崿F(xiàn)一致。

  4. 給工廠類{GadgetName}_Gadget友元訪問特定域類的權(quán)限。

  5. 采用宏創(chuàng)建工廠類。
    CREATE_GADGET_FACTORY_CLASS_XX(
    {GadgetName}_Gadget,
    type1, input1, type2, input2, ... ,
    typeXX, inputXX
    );

void examples_r1p_verify_transaction_amounts() {
    initPublicParamsFromDefaultPp();
    auto pb = Protoboard::create(R1P);
    const VariableArray inputAmounts(2, "inputAmounts");
    const VariableArray outputAmounts(3, "outputAmounts");
    const Variable minersFee("minersFee");
    auto verifyTx = VerifyTransactionAmounts_Gadget::create(
        pb,
        inputAmounts,
        outputAmounts,
        minersFee
    );
    verifyTx->generateConstraints();
    pb->val(inputAmounts[0]) = pb->val(inputAmounts[1]) = 2;
    pb->val(outputAmounts[0]) = 
            pb->val(outputAmounts[1]) = 
                     pb->val(outputAmounts[2]) = 1;
    verifyTx->generateWitness();
    EXPECT_TRUE(pb->isSatisfied());
    EXPECT_EQ(pb->val(minersFee), 1);
    pb->val(minersFee) = 3;
    EXPECT_FALSE(pb->isSatisfied());
}

5. 整合gadgetlib2和ppzkSNARK

下面是一個(gè)整合gadgetlib2所構(gòu)造的限制系統(tǒng)和ppzkSNARK的例子。

1. 主流程
    initPublicParamsFromDefaultPp();

創(chuàng)建一個(gè)限制系統(tǒng)的例子,并翻譯成libsnark的格式化。

const libsnark::r1cs_example<
        libff::Fr<
            libff::default_ec_pp
        >
> example = libsnark::gen_r1cs_example_from_gadgetlib2_protoboard(100);
const bool test_serialization = false;

運(yùn)行ppzksnark,跳轉(zhuǎn)到分析函數(shù)。

const bool bit = libsnark::run_r1cs_ppzksnark<
    libff::default_ec_pp
>(example, test_serialization);

EXPECT_TRUE(bit);
2. r1cs創(chuàng)建

限制系統(tǒng)在gen_r1cs_example_from_gadgetlib2_protoboard中創(chuàng)建,我們來看看里面的過程是什么。

注意:這個(gè)例子確實(shí)創(chuàng)建了一個(gè)限制,這個(gè)限制至少說明說明了QAP限制的健全性。

r1cs_example<
    libff::Fr<
        libff::default_ec_pp
    >
>
gen_r1cs_example_from_gadgetlib2_protoboard(const size_t size)
{
    typedef libff::Fr<libff::default_ec_pp> FieldT;

    gadgetlib2::initPublicParamsFromDefaultPp();

必要的情況下,在之前就建立一個(gè)面包板,libsnark假定變量索引總是從0開始,因此我們必須在創(chuàng)建被libsnark使用的限制之前重設(shè)索引。

    gadgetlib2::GadgetLibAdapter::resetVariableIndex();

創(chuàng)建一個(gè)gadgetlib2的gadget。這個(gè)部分靠生成器和證明器實(shí)現(xiàn)。

    auto pb = gadgetlib2::Protoboard::create(gadgetlib2::R1P);
    gadgetlib2::VariableArray A(size, "A");
    gadgetlib2::VariableArray B(size, "B");
    gadgetlib2::Variable result("result");
    auto g = gadgetlib2::InnerProduct_Gadget::create(pb, A, B, result);

創(chuàng)建一個(gè)限制,這個(gè)部分靠生成器完成。

    g->generateConstraints();

創(chuàng)建賦值(證據(jù))。這個(gè)部分是證明者完成的。

    for (size_t k = 0; k < size; ++k)
    {
        pb->val(A[k]) = std::rand() % 2;
        pb->val(B[k]) = std::rand() % 2;
    }
    g->generateWitness();

將限制系統(tǒng)轉(zhuǎn)換成libsnark格式。

    r1cs_constraint_system<FieldT> cs = 
                            get_constraint_system_from_gadgetlib2(*pb);

轉(zhuǎn)換所有的變量的賦值到libsnark格式。

    const r1cs_variable_assignment<FieldT> full_assignment =
                             get_variable_assignment_from_gadgetlib2(*pb);

提取主要的和輔助的輸入

    const r1cs_primary_input<FieldT> primary_input(
               full_assignment.begin(), 
               full_assignment.begin() + cs.num_inputs()
    );
    const r1cs_auxiliary_input<FieldT> auxiliary_input(
               full_assignment.begin() + cs.num_inputs(), 
               full_assignment.end()
    );

    assert(cs.is_valid());
    assert(cs.is_satisfied(primary_input, auxiliary_input));

    return r1cs_example<FieldT>(cs, primary_input, auxiliary_input);
}
3. 運(yùn)行ppzksnark

下面的代碼提供了一個(gè)以R1CS的形式運(yùn)行ppzkSNARK的全場(chǎng)景的例子。
當(dāng)然,在實(shí)際的情景中,我們有三個(gè)明顯的實(shí)體,下面將亂入到一個(gè)演示實(shí)例中。這三種實(shí)體如下:

  1. 生成器:它運(yùn)行ppzkSNARK生成器,輸入一個(gè)給定的限制系統(tǒng)CS來創(chuàng)建一個(gè)證明過程和一個(gè)對(duì)于CS來說可驗(yàn)證的key。

  2. 證明者:運(yùn)行ppzkSNARK的證明者,輸入一個(gè)證明用的key。

  3. 驗(yàn)證者:運(yùn)行ppzkSNARK驗(yàn)證者,輸入一個(gè)可驗(yàn)證的key,一個(gè)CS的主輸入,和一個(gè)證據(jù)。

template<typename ppT>
bool run_r1cs_ppzksnark(const r1cs_example<libff::Fr<ppT> > &example,
                        const bool test_serialization)
{
    //libff::enter_block("Call to run_r1cs_ppzksnark");

    //libff::print_header("R1CS ppzkSNARK Generator");
    r1cs_ppzksnark_keypair<ppT> keypair = 
                   r1cs_ppzksnark_generator<ppT>(example.constraint_system);
    //printf("\n");
    //libff::print_indent();
    //libff::print_mem("after generator");

    //libff::print_header("Preprocess verification key");
    r1cs_ppzksnark_processed_verification_key<ppT> pvk = 
                   r1cs_ppzksnark_verifier_process_vk<ppT>(keypair.vk);

    if (test_serialization) {
        //libff::enter_block("Test serialization of keys");
        keypair.pk = 
                 libff::reserialize<
                      r1cs_ppzksnark_proving_key<ppT> 
                 >(keypair.pk);
        keypair.vk = 
                 libff::reserialize<
                      r1cs_ppzksnark_verification_key<ppT> 
                 >(keypair.vk);
        pvk = 
                libff::reserialize<
                      r1cs_ppzksnark_processed_verification_key<ppT> 
                >(pvk);
        //libff::leave_block("Test serialization of keys");
    }

    //libff::print_header("R1CS ppzkSNARK Prover");
    r1cs_ppzksnark_proof<ppT> proof = 
                r1cs_ppzksnark_prover<ppT>(
                       keypair.pk, 
                       example.primary_input, 
                       example.auxiliary_input
    );
    //printf("\n"); 
    //libff::print_indent(); 
    //libff::print_mem("after prover");

    if (test_serialization)
    {
        //libff::enter_block("Test serialization of proof");
        proof = libff::reserialize<
               r1cs_ppzksnark_proof<ppT> 
        >(proof);
        //libff::leave_block("Test serialization of proof");
    }

    //libff::print_header("R1CS ppzkSNARK Verifier");
    const bool ans = 
               r1cs_ppzksnark_verifier_strong_IC<ppT>(
                   keypair.vk, 
                   example.primary_input, 
                   proof
    );
    //printf("\n"); 
    //libff::print_indent(); 
    //libff::print_mem("after verifier");
    //printf("* The verification result is: %s\n", (ans ? "PASS" : "FAIL"));

    //libff::print_header("R1CS ppzkSNARK Online Verifier");
    const bool ans2 = 
                  r1cs_ppzksnark_online_verifier_strong_IC<ppT>(
                         pvk, 
                         example.primary_input, 
                         proof
    );
    assert(ans == ans2);

    test_affine_verifier<ppT>(
                  keypair.vk, 
                  example.primary_input, 
                  proof, 
                  ans
    );

    //libff::leave_block("Call to run_r1cs_ppzksnark");

    return ans;
}

譯者總結(jié):

結(jié)構(gòu)圖
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,715評(píng)論 19 139
  • 關(guān)于Mongodb的全面總結(jié) MongoDB的內(nèi)部構(gòu)造《MongoDB The Definitive Guide》...
    中v中閱讀 32,329評(píng)論 2 89
  • 開啟新生活 偷偷去看了你以前的日記,你寫著迫不及待要在開年有自己溫暖的小家,結(jié)束熬夜奔波的生活。 開年之前已實(shí)現(xiàn)了...
    Ermao閱讀 198評(píng)論 0 1
  • 流年七里香農(nóng)莊閱讀 126評(píng)論 0 0
  • 在印加帝國時(shí)間達(dá)到鼎盛,當(dāng)時(shí)印加帝國人口約有10萬到12萬,疆域包括今日的秘魯、厄瓜多爾和玻利維亞,以及部分的智利...
    左右文摘閱讀 510評(píng)論 0 0

友情鏈接更多精彩內(nèi)容