https://github.com/dalek-cryptography/merlin
中的Merlin transcript是基于STROBE(参见博客strobe——面向IoT物联网应用的密码学协议框架)的封装,使用的是keccak-f/1600 128-bit安全级别。
Merlin是基于Fiat-Shamir transform(可参见博客Fiat-Shamir heuristic(含实现)和Random oracle)的实现,通过非交互式的方式实现交互式执行的效果。(直白说就是可将交互式零知识证明转化为非交互式零知识证明。)
STROBE是一种协议框架,意在构建在线传输协议。而Merlin主要用于零知识证明,仅需要用到STROBE的部分功能。Merlin在实际实现时,可直接调用STROBE库,也可单独实现STROBE中需用到的功能。
Merlin中有两大对象:
Merlin代码库中的Merlin transcript是对STROBE对象的封装,库中使用的是0.3.0版本的strobe-rs库(当前最新版本为0.5.2),实例化为仅支持128-bit安全级别和使用Keccak-f/1600。
app_label
:代表特定应用层面的分隔符,为a byte string。Merlin transcripts通常用它来初始化。
构建Merlin transcript的过程为:
b"Merlin v1.0"
b"dom-sep"
附加在app_label
后面。Merlin的消息为byte strings,最大可支持4GB(u32::max_value()
bytes)。通常不建议使用太长的消息,若消息过长,考虑将其hash化,并将相应的hash值作为消息附加上。
通过STROBE操作,将一条消息message
附加在label label
上:
AD[label || LE32(message.len())](message);
其中的LE32(x)
为4字节的,以little-endian编码的32-bit数字x
。采用的是STROBE论文第9页所定义的OP[meta](data)
格式。由于Merlin没有传输的概念,其中的metadata采用meta-AD
编码。
在交互式沟通时,会使用到多个challenges,若要将其转换为非交互式沟通,需要具有能将一序列的challenge bytes依序extract提取出来的能力。
为了将以label
标记的一序列challenge bytes提取到buffer dest
中,Merlin采用如下的STROBE操作:
dest <- PRF[label || LE32(dest.len())]();
在Schnorr签名中(可参见博客Schnorr signature (Schnorr 签名)数学原理)nonce为 a bliding factor used for a single sigma-protocoal (a proof of knowledge of the secret key, with the message in the context)。
blinding factor若随机性不好,会从一下多方面毁坏Schnorr签名:
Merlin在证明过程中使用了一个基于STROBE的RNG,目的是防止熵攻击。Merlin的transcript RNG是对一下三种协议的通用概括实现:
Merlin的transcript具有确定性和可生成合成nonce的特性。Merlin提供了一个transcript-based RNG,结合了(2)和(3)的理念,对于Prover,生成随机数的过程为:
*1. creates a secret clone of the public transcript state up to that point, so that the RNG output is bound to the entire public transcript;(Binding the output to the transcript state ensures that two different proof contexts always generate different outputs. This prevents repeating blinding factors between proofs. )
*2. rekeys their clone with their secret witness data, so that the RNG output is bound to their secrets;(Binding the output to the prover’s witness data ensures that the PRF output has at least as much entropy as the witness does. )
*3.rekeys their clone with 32 bytes of entropy from an external RNG, avoiding fully deterministic proofs.(Finally, binding the output to the output of an external RNG provides a backstop and avoids the downsides of fully deterministic generation.)
In Merlin’s setting, the only secrets available to the prover are the witness variables for the proof statement, so in the presence of a weak or failing RNG, the RNG’s entropy is limited to the entropy of the witness variables.
A verifier can also use the transcript RNG to perform randomized verification checks, although defense-in-depth is less essential there. They can skip step 2, and perform only steps 1 and 3.
通过label
标签标记witness
secret bytes来更新密钥,Prover执行如下STROBE操作:
KEY[label || LE32(witness.len())](witness);
To finalize the transcript RNG constructor into an RNG, the prover obtains rng, 32 bytes of output from an external rng, then performs
KEY[b"rng"](rng);
Ideally, the transcript, transcript RNG constructor, and transcript RNG should all have different types, so that it is impossible to accidentally rekey the public transcript, or use an RNG before it has been finalized.
参考资料:
[1] 博客strobe——面向IoT物联网应用的密码学协议框架
[2] https://merlin.cool/transcript/ops.html
[3] https://github.com/dalek-cryptography/merlin
[4] 博客Arthur-Merlin protocol交互式知识证明系统