零知识编程语言

文章介绍了零知识证明编程语言的工作原理,并列举了几种流行的零知识证明编程语言,如Circom、Zokrates、Noir和Cairo,同时讨论了它们在区块链和隐私保护中的应用。

零知识编程语言

零知识证明月亮数学

零知识证明月亮数学

零知识证明证明你正确地执行了一项计算,而无需透露计算的输入。零知识编程语言是一种方便的方式来表示该计算。

一个常见但具有误导性的类比是“我可以证明我超过21岁,而无需给你看我的身份证”。以这种方式表述时,你无法创建一个零知识证明。

零知识证明并不证明 知识,而是证明 正确的计算,对于 公共算法的公共输出,而不透露计算的输入。

因此,零知识身份证并不是这样的。让我们用一个真实的例子。可以选择一个已知的数字,比如1,093,073,并创建一个证明,表明你是通过乘以两个数字得到了它,而无需透露这两个数字(在这个例子中是1103和991)。

这个零知识证明将包含三个组件:

  • 两个数字(我们称之为 字段),在这个例子中,经过加密的版本1103和991
  • 一个大的字节字符串(证明)
  • 一个乘法算法的程序描述

称输入为“加密”有点误导,因为没有一种自然的方法来解密它们,但这是一种合理的思考方式。你可以对输入进行数学上的合理操作,但无法确定它们的原始值。

你可以将零知识证明视为数字签名的高度概括版本。

通过数字签名,你证明了对私钥的知识,而无需分享私钥。你首先通过提供一个消息和一个公钥来证明这一点。然后你展示一个与消息和公钥一致的签名。

零知识证明的类比如下:

(公共输出,加密输入,零知识证明) —> 数字签名

(算法) —> 公钥。

你生成的证明(字节字符串)与输出和算法是一致的。验证者实际上无法执行计算,但他们可以验证

  • 算法
  • 输出
  • 加密输入,以及
  • 证明字符串

都是彼此一致的。

在数字签名中,公共地址是事先已知的。在零知识应用中,你正在执行的算法是事先已知的。数字签名会根据你签署的消息而变化。同样,在零知识证明中,你的证明字符串将随着你所证明的输入和输出而变化。

一般形式下,零知识计算看起来像这样:

prove(inputs, algorithm_description) -> (encrypted_inputs, proof, public_output)
verify(encrypted_inputs, proof, algorithm_description) == public_output

一个更有趣的例子是在像zcash这样的加密货币中转移资金。每一笔钱的转移交易都是一个状态转换,这本身就是一个计算。公共输出是总供应量(在矿工奖励的情况下并未改变)。加密输入是地址之间的余额转移。

由于零知识证明只是计算,因此它们非常自然地可以用编程语言来描述。还记得之前提到的乘法算法的程序描述吗?它可以方便地用一种传统的编程语言来表示,后台将其编译为“月亮数学”。

不再多说,以下是零知识编程语言的列表。

Circom,由 iden3 提供

如果你来自电气工程背景,那就庆祝吧。零知识中表示计算的主流方式是使用布尔电路。布尔电路实际上是巨大的数学方程,因此它们可以轻松转换为后台发生的“月亮数学”方程。

你可能想知道,如果零知识用电路表示,那么如何进行哈希算法或for循环呢?这需要多个步骤,而电路可以一次计算所有东西。

这通过将每个步骤视为一个单独的电路并为每个步骤提供一组证明来完成。这对我们来说是件幸运的事,因为使用电路来描述大多数计算是非常具有挑战性的。

值得庆幸的是,Circom 提供了一个抽象层,而不必自己实现ALU(算术逻辑单元)。以下是将两个数字相加的代码:

pragma circom 2.0.0;

template Add(){
    //信号声明
    signal input in1;
    signal input in2;
    signal output out;
    out <== in1 + in2;
}

component main {public [in1,in2]} = Add();

这些模板允许你将构件组合在一起以进行更复杂的操作,例如连接字节字符串、椭圆曲线算术或哈希函数。

Zokrates

如果六行代码将两个数字相加对你来说令人失望,幸运的是,还有更高级的抽象。这是Zokrates的做法。

def main(field x, field y) -> field {
    field z = x + y;
    return z;
}

为什么零知识编程语言称数字为字段?在零知识证明中,数学总是以大素数为模进行的(与大多数加密算法一样)。这里“字段”这个术语是“有限域”的缩写,因为数字可以取的值是有限的。具体而言,它是进行模算术计算的素数的大小。

显然,在不透露这两个数字的情况下证明你知道两个数字的和并不很有趣。以下是一个更好的应用,使用开头的例子。

Zokrates中的零知识身份证

零知识证明身份证算法

零知识证明身份证算法

经过一些修改,我们可以使我们的零知识身份证工作。

首先,无法在没有某个权威机构验证你在某个日期出生的情况下展示你的年龄。但这是将对一个事实的知识转换为计算证明的一种方法。

政府将你的生日、公民身份证号码和一个随机盐连接在一起,进行哈希处理,然后对哈希摘要进行数字签名。当你去某个需要证明你超过21岁的地方时,你会提供加密的生日、加密的公民身份证、加密的随机盐、政府签署的哈希和字节字符串证明。

目标是证明你可以正确执行算法以生成已签名的哈希。

通常,你无法将加密值连接起来并恢复签名的哈希,但这就是零知识编程的用武之地。你实际上并不是对加密输入进行哈希,而是证明你正确执行了计算,而不透露输入。

在Zokrates中,这看起来令人惊讶地简洁。

import "hashes/sha256/512bitPacked" as sha256packed;

def main(private field birthday,
         private field citizenId,
         private field salt,
         public requiredBirthday,
         public field hashFirst128bits,
         public field hashSecond128bits) {

    field[2] hash = sha256packed([birthday, citizenId, salt]);
    assert(hash[0] == hashFirst128bits);
    assert(hash[1] == hashSecond128bits);
    assert(birthday < requiredBirthday);
    return;
}

// 哈希的签名将在传统方式下进行验证

这看起来并不吓人,对吗!?我们确保秘密值哈希到期望的哈希,并确保与生日对应的输入达到阈值。

有一点不禁让人想起:如何在生日被加密的情况下执行以下代码行

assert(birthday < requiredBirthday)

代码被编译成数学,这在实际意义上是有意义的——它并不是以我们通常所理解的方式“执行”。同样,哈希电路实际上并不是在对输入进行哈希。它只是在验证加密输入与公共哈希输出在底层电路及其伴随证明的函数的一致性。

Zokrates的原始白皮书发表于2018年IEEE(http://www.ise.tu-berlin.de/fileadmin/fg308/publications/2018/2018_eberhardt_ZoKrates.pdf

Leo

Aleo区块链是一个注重隐私的智能合约链,Leo是其主要编程语言。你可以在他们的在线游乐场上看看语言是什么样的。

在撰写本文时,仅测试网已启动。

这是用该语言将两个数字相加的代码。

program helloworld.aleo {
  transition main(public a: u32, b: u32) -> u32 {
      let c: u32 = a + b;
      return c;
  }
}

Leo白皮书/学术论文:https://eprint.iacr.org/2021/651.pdf

二层应用

虽然零知识证明因其隐私而著称,但它们在区块链可扩展性方面有一个强大的用例。请记住,验证者实际上无法对加密输入进行哈希或加法运算并获得合理结果。他们只验证输入、输出、电路和证明是一致的。

有趣的是,证明一致性在计算上比实际进行计算要简单。这意味着组装交易的块生产者负有相当大的计算负担,因为他们必须执行计算并产生证明,但其他验证者验证提议块的工作量要少得多,因为他们只需验证证明,这在渐进上更简单。

共识不是在块生成时达成的,而是在网络中超过三分之二的节点同意块有效时达成的。他们必须执行的计算越多,共识所需的时间就越长,这会导致吞吐量瓶颈。

因为这个用例优化了快速验证,所以你不应该假设操作默认是私密的。以下语言的实现并不一定优化隐私保护,除非它们明确表示。

NoirAztec 提供

Noir是Aztec的语言,这是一个以隐私为中心的以太坊L2。语法受到Rust的强烈启发;即使构建工具也称为“nargo”,显然是对Rust的cargo的致敬。

以下是Noir将两个数字相加的代码

fn foo(x : Field, y : Field) -> Field {
    x + y
}

在Rust和Noir中,没有分号的语句会被解释为函数返回,以防你想知道为什么返回语句消失了。

CairoStarkware 提供

Starknet是另一个L2。

这个名字是中央处理单元代数中间表示的合成词。中间表示语言用于“略低于汇编”,但在零知识证明中,“汇编”是用于证明零知识的代数公式。

C或C++开发者(或在汇编语言下感到自信的Solidity开发者)会对这种语言感到熟悉,因为它相当低级。以下是Cairo的游乐场

与传统相一致,Cairo称数字为“字段”,但称其为“字段元素”,在语法中简化为“felt”( f ield + el ement t)。

以下是Cairo将两个数字相加的代码

%builtins output

// 导入serialize_word()函数。
from starkware.cairo.common.serialize import serialize_word

func main{output_ptr: felt*}() {
    tempvar x = 12;
    tempvar y = 14;
    tempvar z = x + y;
    serialize_word(z);
    return ();
}

Cairo白皮书:https://eprint.iacr.org/2021/1063.pdf

Solidity

没想到会在这里看到这个吧?!

你可能听说过一些关于“zk evms”的炒作,Polygon和Matter Labs正在制作。炒作的内容是你可以将普通的Solidity编译成常规的EVM字节码,同时生成一个零知识证明,表明你已正确执行字节码。这当然需要一个特殊的虚拟机,这些公司通常将其品牌化为某种变体的“zk evm”。

你可以将EVM的状态视为由两个数组表示:堆栈和内存。每个操作都会改变堆栈和/或内存。每一步都是证明你改变状态的方式与之前的状态及刚刚执行的操作代码一致的证明。

由于这种创新,Solidity很可能会长期保持相关性,因此请查看我们的Solidity bootcamp !。这是我们零知识bootcamp的先决条件。

我该使用哪个,以及进一步资源

如果你计划在Aleo、Starknet或Aztec上开发,你必须使用他们各自的语言。但如果你试图在以太坊上开发一个以隐私为重点的智能合约,你需要使用Circom或Zokrates。Noir目前也有限制支持编译为Solidity。

尽管直接使用比Circom更友好的语言可能很诱人,但值得培养对电路编程功能的直觉。毕竟,这里列出的语言最终都会编译成类似的东西。你会注意到此列表中Circom后面的语言有奇怪的约束,除非你对背后的机制有一定了解,否则是无法理解的。例如,在Zokrates中,所有“if”语句的分支都会执行,而在Cairo中内存不能被覆盖。

没有人能更温和地介绍零知识证明背后的数学,但这篇论文应该能让任何修习过预备微积分或基本加密课程的人理解。

练习零知识谜题

如果你想更温和地了解Circom,请阅读他们的文档并尝试解决我们的开源零知识谜题

  • 原文链接: rareskills.io/post/zero-...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
RareSkills
RareSkills
https://www.rareskills.io/