龙空技术网

零知识扑克牌游戏开发教程「Circom/Snarkjs」

新缸中之脑 83

前言:

此时兄弟们对“c语言输出扑克牌”大概比较注重,姐妹们都需要了解一些“c语言输出扑克牌”的相关文章。那么小编同时在网上收集了一些关于“c语言输出扑克牌””的相关内容,希望小伙伴们能喜欢,同学们一起来了解一下吧!

零知识证明是实现去中心化的一个重要工具。当平台透明存储数据时 我们应当如何保证隐私?当为了扩容而引入链下交易时,我们如何在 链上进行验证?零知识证明在解决这些问题时可以发挥重要的作用。 这个教程的目的是帮助你探索circom/snarkjs的更多可能性,我们 将学习如何开发一个基于零知识证明的扑克牌游戏。

当谈及零知识电路开发时,我们有很多可选的库。实现我发现iden3开发的circom和snarkjs 对于零知识证明的新手很友好:电路很容易编写,整个零知识证明框架 的运行也很简单,不需要复杂的环境。

建议你在学习本教程之前先阅读circom/snarkjs的官方教程。 本教程的完整代码可以从这里下载。

用自己熟悉的语言学习以太坊DApp开发: Java | Php | Python | .Net / C# | Golang | Node.JS | Flutter / Dart

1、零知识扑克牌游戏规则简介

为了突出重点,我们简化了扑克牌游戏的规则:

每个选手发5张牌不可以换牌当比较牌大小时,只考虑对子(pairs),不考虑顺子(straights)、同花(flushes)、满堂红(full houses)等等情况选手可选的动作只有:不跟(fold)、下注(see)、加注(raise)如果一手牌里没有对子,选手就不能叫牌(bid)

还有最后一个规则 —— 不允许虚张声势(bluffing) —— 这就是我们要用零知识证据来保证的。 叫牌的选手可以避免泄露自己的牌,但同时依然可以向其他选手证明自己的确有对子,不是 虚张声势。在下面的教程中,我们将忽略游戏机制而聚焦于零知识证明电路的设计与实现。

2、零知识扑克牌游戏的电路概述

我们这个基于零知识证明的扑克牌游戏的电路,大致应该是这样的:

采集输入:牌型、选手的叫牌选择确认牌面中至少有一个对子评估叫牌类型,例如跟进或弃牌设置一个约束来检查是否已经进行选择设置一个约束来检查所选择的选项符合当前的牌型

下面就让我们分步骤学习这个电路的实现代码。

3、引入circom提供的基础电路

首先我们需要引入一些circom提供的基础电路:

include “../node_modules/circomlib/circuits/gates.circom”;include “../node_modules/circomlib/circuits/comparators.circom”;

需要指出的是,我们的文件夹结构看起来是这样:

project-root\poker

因此我们使用上面的路径来引入基础电路。这些基础电路时circomlib 提供的,因此需要进行额外的安装:

npm install --save circomlib
4、定义扑克牌游戏的零知识电路模板
template Poker() {     ... circuit body ...}component main = Poker();

这个结构基本和官方教程里一样,只有一个模板并且定义了入口点。

5、定义扑克牌游戏的输入、输出和中间结果

signal private input cards[5]; // Each 2..14signal input isSee; // 1 or 0signal input isFold; // 1 or 0signal input raise; // intsignal output out; // 1 or 0// Intermediate resultssignal isBid;signal isRaise;signal hasChosen;

牌型信息定义为一个数组:cards[5],每一张牌都用其牌面值 表示,我们忽略花色。例如 Ace=14、King=13、Queen=12、Jack=11… 依次类推直至2。选手的牌型是电路的私有输入,这表示我们要求 这个输入保持隐秘。

叫牌选项当然是公开的,因为该信息需要向所有其他选手公布。 弃牌或者跟随下注选项都用布尔值表示,加注选项则是整数 类型,表示实际增加的注数。

唯一的输出是out,值为1或0。

我们还定义了其他一些中间值,稍后在进行介绍。

6、检查牌型中的对子数量

这一部分的代码用于决定牌型中是否包含对子。注意这部分代码看起来 和普通javascript非常像,不包含任何约束定义或者信号操作。

这里是关于电路工作的一个直觉。现实生活中的电路可能需要一些预处理 或者中间评估,但是注意,这样的代码不会包含于正式的证据中,只有那些 约束会嵌入零知识证明公共参数中,并在证据生成和验证节点 。一个不诚实 的证明人可能会修改中间结果来伪造见证。

预处理环节的结果是一个单独的变量numPairs,在后面部分会用到。

这里的实现逻辑就是两重循环进行配对并计算对子的总数:

// Count pairsvar numPairs = 0;for (var i=0; i<4; i++) {   for (var j=i+1; j<5; j++) {      if (cards[i] == cards[j]) {         numPairs++;         // break doesn’t work. Just force j and i to exit         j = 5;         i = 5;      }   }}
7、零知识扑克牌游戏中的电路约束

在之前的入门教程中我们介绍了电路信号的操作符号: <–, –>, <==, ==> , 和 === 。 这个教程中我们引入新的符号:组件。组件就是类的实例,注意我们调用组件的方法, 组件的输入信号(a、b、c、in等等)被赋值并使用信号操作符。组件的数据信号也可以 类似方法使用。

在这里我们使用组件进行布尔运算,circomlib提供了不少电路组件可供我们利用。

同样,我们定义了约束,其中一个约束是检查选手是否做出了选择(fold、see或raise)。 另一个要检查的约束就是看是否存在对子。最终输出信号的值为1。

// isRaise = (raise != 0)isRaise <-- (raise > 0);isBid <-- (isRaise || isSee); // Constraint: Must be either bid or fold: isBid XOR isFold = 1hasChosen <-- isBid + isFold — 2*isBid*isFold;hasChosen === 1; // Constraint: numPairs must be > 0 if isBid = 1var hasPairs = (numPairs > 0);component not3 = NOT();not3.in <-- isBid; component or2 = OR();or2.a <-- hasPairs;or2.b <-- not3.out;or2.out === 1; out <-- or2.out;
8、零知识电路的公共参数设置、证据生成和验证

首先利用电路进行设置,生成公共参数:

circom poker.circom -o poker.jsonsnarkjs setup -o poker.json

接下来需要提供输入,例如下面这个简单的输入文件input.json:

{“cards”: [8, 7, 4, 7, 13], “isFold”: 0, “isSee”: 0, “raise”: 10 }

这手牌里包含一个对子,因此所有的叫牌选项都可用。选手选择了加注10。 我们预期这个输入是有效的。输入信息中只有cards是私有的,而其他西悉尼都是 公开的。

现在来生成证据:

snarkjs calculatewitness -c poker.jsonsnarkjs proof

证据生成的性能复杂度为O(n),其中n表示电路中约束的个数。因为 我们的电路很简单,因此约束很少,证据生成也快。如果你的电路中有 非常多的约束就需要更多的时间生成证据,你可以查看这个测试 来了解电路性能与约束数量的关系。

现在用验证器来验证证据:

PS C:\dev\snarks\poker> snarkjs verifyOK

的确和预期一样!

原文链接:

标签: #c语言输出扑克牌