Mina 开发者中文文档
Snapps (“snark apps”) are Mina’s zk-SNARK -powered smart contracts.
SNARKs是一个强大的加密工具,它可以让应用程序给予用户前所未有的监督和隐私。它们也是构建像Mina这样的可扩展的去中心化系统的关键成分。
snarky是一种用于使用SNARKs的领域特定语言。本节旨在指导您如何在使用snarky的程序中开始使用snarky。
在这里,您可以找到关于如何使用snarky(一种用于zk-SNARKS的DSL)的文档,以及snarkyjs-crypto(一个附带的JavaScript库,提供了一套适合与snarky一起使用的密码学原语)的文档。
SNAPP(或snarkified app)有两个部分:
我们将使用两个Node.js库:
● snarkyjs-crypto,它让我们能够访问密码学哈希、默克尔树和签名,这些都对应了了snarky-universe中的数据
● snarkyjs,它给了我们创建和验证SNARK证明的方法。
让我们构建一个简单的应用程序来证明我们知道一个哈希函数的原像。你可以在这里找到完整的应用程序。
构建SNAPP的第一步是定义SNARK。在这种情况下,我们的SNARK将证明,给定一个哈希值h
我知道一个元素字符串x,满足哈希(x) = h。
其中hash是snarky-universe中提供的Poseidon hash函数。
snarky组件——在这个文件中定义——如下:
module Universe = (val Snarky_universe.default());open! Universe.Impl;open! Universe;
let input = InputSpec.[(module Hash)];
module Witness = Field;
let main = (preimage: Witness.t, h, ()) =>
Field.assertEqual(Hash.hash([|preimage|]), h);
runMain(input, (module Witness), main);
让我们一点一点地分析这个文件。
module Universe = (val Snarky_universe.default());open! Universe.Impl;open! Universe;
前3行只是一个前言,介绍我们所需要的所有功能。它使用“默认的”SNARK构建后端,即使用bn128曲线实例化的Groth16 SNARK。
下一行声明SNARK的公共输入将是散列。“公共输入”(或“语句”)是检查SNARK的值。
let input = InputSpec.[(module Hash)];
下一行声明我们的顶级“witness”(即我们正在证明我们知道的东西)将是一个字符串,如上所述。
module Witness = Field;
接下来,我们有main
函数,它真正定义了我们的SNARK
let main = (preimage: Witness.t, h, ()) =>
Field.assertEqual(Hash.hash([|preimage|]), h);
这里我们就像上面描述的那样写:main
计算”witness”的哈希值,并断言它等于公共输入h
。
main
的参数必须是以下之一
1.顶级witness。
2.任何公共投入。这里只有一个h
。
3.dummy()
参数。
最后一行设置我们的程序以使用Node.js API。
runMain(input, (module Witness), main);
现在我们准备好用我们的SNARK了。我们将使用Node.js API。
API相当简单。我们可以创建一个“snarky”对象,它有两个方法:
1.prove
,即获取一个statement和一个witness,并返回一个证明的承诺。
2.verify
,它接受一个statement和一个证明,并返回bool类型的承诺。
以下是它们是如何组合在一起的内容:
const { bn128 } = require('snarkyjs-crypto');const Snarky = require('snarkyjs');const snarky = new Snarky("./ex_preimage.exe");
const preImage = bn128.Field.ofInt(5);const statement = bn128.Hash.hash([ preImage ]);
snarky.prove({
statement: [ statement ],
witness: preImage
}).then((proof) => {
console.log("Created proof:\n" + proof + "\n");
return snarky.verify({
"statement": [ statement ],
"proof": proof
});
}, console.log).then((verified) => {
console.log("Was the proof verified? " + verified);
if (verified) {
process.exit(0);
} else {
process.exit(1);
}
}, () => { process.exit(1); });
有许多不同的SNARK结构,它们在性能和安全性方面有权衡。本页概述了在选择方案时需要考虑的一些重要标准。
对于许多应用程序,SNARKs的不可延展性是很重要的。直觉上,如果已知的证明不能帮助你对新statements生成证明,那么一个SNARK就是不可延展的。
更详细地说,如果不可能将针对输入x的证明p修改为针对输入x'的证明p',那么SNARK结构是不可扩展的,除非您可以在不知道(p, x)的情况下这样做。
这种非延展性的技术术语是可仿真提取。
在witness或部分witness见证应保密的应用中,你可能需要不可延展性。有一些技术可以在使用可延展性的同时实现同样的安全性,但最好还是让专家来做。
在实践中,使用非延展性的SNARK只会带来很小的性能损失,所以除非你确信自己不需要它,否则使用这种SNARK是没有坏处的。
这是在选择SNARK构造时要记住的最大的实际考虑因素之一。一些SNARK需要一个“设置”,它涉及到一个可信方或一组可信方(其中之一是您可以信任的)运行一个计算来为SNARK生成密钥。这是较为常见的方式,就像对ZCash所做的那样。
1.Universal.通用设置只需要执行一次,产生的密钥可以在所有未来的SNARK程序中重用。
2.Per-program. 每个程序设置必须在每个SNARK程序中运行一次。
通用设置要方便得多,但是为每个程序设置的SNARK结构有更好的性能。
也有完全没有设置的SNARKs。一般来说,这些SNARKs的证明大小要大得多:50-200kB,相比之下,带有setup的SNARKs大小为100字节。
在选择SNARK结构时,要记住以下效率特征:
● Prover time. 生成一个证明需要多长时间?
● Proof size. 每个证明有多大?
● Verifier time. 验证证明要多长时间?
如果要使用递归SNARKS,还需要考虑其他性能标准,但这超出了本文的范围。
让我们根据我们的标准来评估一些现有的SNARK结构。一些参数的性能描述仍然是主观的,直到有人开始运行一个适当的、公平的基准测试。下面的表格有些空缺,如果你很启发,请做个PR:)
在本文中,“无需设置”,指的是透明设置,这实际上相当于选择一个哈希函数,如SHA256, blake2s等。
这个包提供了域算术、哈希函数、Merkle树模块和适合在SNARKs内部使用的Schnorr签名。你可以用
npm install snarkyjs-crypto
关于API的使用,请参阅这里的示例。
(代码省略)
这个包提供了域算术、哈希函数、Merkle树模块和适合在SNARKs内部使用的Schnorr签名。你可以用
npm install snarkyjs-crypto
关于API的使用,请参阅这里的示例。
snarky-universe是一个snarky标准库,它提供了处理各种有用对象(域元素、散列、默克尔树、签名、整数)的函数。
(一大串代码,省略)
snarky-universe中的大多数模块都有一个子模块叫做“Constant”。例如,有一个模块Field带有子模块Field.Constant。
Field提供对“in SNARK”变量域元素的操作,而Field.Constant提供对常规旧域元素的操作。
区别如下:对于“in snark”字段元素,您基本上只能对它们进行相加和相乘。使用“Constant”字段元素,您可以查看它们的二进制数据,将它们转换为字符串,将它们打印到控制台,等等。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!