创建和验证零知识证明需要多长时间?

本文介绍了使用Rust编程语言和Bellman库实现Groth16零知识证明,并测量了生成和验证证明所需的时间。实验结果表明,生成电路需要较长时间(140秒),生成证明需要15秒,但验证证明非常快(0.03秒)。

创建和验证零知识证明需要多长时间?

一根绳子有多长?嗯,谁知道呢!但是,创建一个和验证一个零知识证明需要多长时间?嗯,这是我们可以实际测量的事情。我们将发现,我们可能需要大约两分钟来生成证明,但我们可以快速检查证明是否正确。总的来说,生成 ZKP 可能需要一段时间,但之后验证起来很快。

由于我们想要良好的性能,我们将使用 Rust 编程语言来实现这一点,它将被编译成一个可执行程序。一个常见的 ZKP 是 Groth16,它由 Jen Groth 在 2016 年创建 [1]。它使用基于配对的密码学,并创建一个简短的证明。最好的 Rust 库之一是 Bellman 库。

以下代码基于这里

use bellman::{
    gadgets::{
        boolean::{AllocatedBit, Boolean},
        multipack,
        sha256::sha256,
    },
    groth16, Circuit, ConstraintSystem, SynthesisError,
};
use bls12_381::Bls12;
use ff::PrimeField;
use rand::rngs::OsRng;
use sha2::{Digest, Sha256};

use std::env;

/// 我们自己的 SHA-256d gadget。输入和输出都采用小端位顺序。
fn sha256d<Scalar: PrimeField, CS: ConstraintSystem<Scalar>>(
    mut cs: CS,
    data: &[Boolean],
) -> Result<Vec<Boolean>, SynthesisError> {
    // 翻转每个输入字节的字节序
    let input: Vec<_> = data
        .chunks(8)
        .map(|c| c.iter().rev())
        .flatten()
        .cloned()
        .collect();

    let mid = sha256(cs.namespace(|| "SHA-256(input)"), &input)?;
    let res = sha256(cs.namespace(|| "SHA-256(mid)"), &mid)?;

    // 翻转每个输出字节的字节序
    Ok(res
        .chunks(8)
        .map(|c| c.iter().rev())
        .flatten()
        .cloned()
        .collect())
}

struct MyCircuit {
    /// 我们正在证明我们知道的 SHA-256d 的输入。当我们验证证明(并且没有 witness 数据)时,设置为 `None`。
    preimage: Option<[u8; 80]>,
}

impl<Scalar: PrimeField> Circuit<Scalar> for MyCircuit {
    fn synthesize<CS: ConstraintSystem<Scalar>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
        // 计算 preimage 各位的值。如果我们正在验证证明,我们仍然需要创建相同的约束,因此我们返回一个等效大小的 Vec<None>(表示每个位的值未知)。
        let bit_values = if let Some(preimage) = self.preimage {
            preimage
                .into_iter()
                .map(|byte| (0..8).map(move |i| (byte >> i) & 1u8 == 1u8))
                .flatten()
                .map(|b| Some(b))
                .collect()
        } else {
            vec![None; 80 * 8]
        };
        assert_eq!(bit_values.len(), 80 * 8);

        // Witness preimage 的各位。
        let preimage_bits = bit_values
            .into_iter()
            .enumerate()
            // 分配每个位。
            .map(|(i, b)| {
                AllocatedBit::alloc(cs.namespace(|| format!("preimage bit {}", i)), b)
            })
            // 将 AllocatedBits 转换为 Booleans(sha256 gadget 需要)。
            .map(|b| b.map(Boolean::from))
            .collect::<Result<Vec<_>, _>>()?;

        // 计算 hash = SHA-256d(preimage)。
        let hash = sha256d(cs.namespace(|| "SHA-256d(preimage)"), &preimage_bits)?;

        // 将 32 个布尔变量的向量公开为紧凑的公共输入。
        multipack::pack_into_inputs(cs.namespace(|| "pack hash"), &hash)
    }
}

fn main() {
// 为我们的电路创建参数。在生产部署中,这些将使用多方计算安全地生成。

let mut msg="Hello";
let args: Vec < String >  = env::args().collect();

if args.len() >1 { msg = args[1].as_str();}

let mut rng = rand::thread_rng();

use std::time::Instant;
let now = Instant::now();
println!("\nSetting up");

let params = {
    let c = MyCircuit { preimage: None };
    groth16::generate_random_parameters::<Bls12, _, _>(c, &mut rng).unwrap()
};
println!("\n== Setting up verification key");

// 准备验证密钥(用于证明验证)。
let pvk = groth16::prepare_verifying_key(&params.vk);

println!("\n== Verifying key created");
let elapsed = now.elapsed();
println!("Elapsed: {:.2?}", elapsed);

// 选择一个 preimage 并计算其哈希值。

let mut preimage = [0; 80];

// let plain=msg.as_bytes();
let mut n=0;
for  ch in msg.chars() {

    preimage[n]= ch as u8;
    n=n+1;
}

let hash = Sha256::digest(&Sha256::digest(&preimage));

println!("Message to prove is {0}\n",msg);
println!("Hash is {0}\n",&hex::encode(hash));
// 创建电路的一个实例(以 preimage 作为 witness)。
let c = MyCircuit {
    preimage: Some(preimage),
};

println!("== Creating proof");
// 使用我们的参数创建一个 Groth16 证明。
let proof = groth16::create_random_proof(c, &params, &mut OsRng).unwrap();

let elapsed = now.elapsed();
println!("Elapsed: {:.2?}", elapsed);

// 将哈希值打包为证明验证的输入。
let hash_bits = multipack::bytes_to_bits_le(&hash);
let inputs = multipack::compute_multipacking(&hash_bits);

// 检查证明!
let ver=groth16::verify_proof(&pvk, &proof, &inputs);

if ver.is_ok() { println!("\nProof verified"); }
else  { println!("\nProof NOT verified"); }

let elapsed = now.elapsed();
println!("Elapsed: {:.2?}", elapsed);

}

为此,我们设置一个 pre-image,它将使用 SHA-256 进行哈希以用于证明。 pre-image 包含 80 字节的信息, 这些信息使用 NULL 字符 (0) 初始化为这 80 个字节。然后,我们将字符串中的字符添加到 pre-image:

let mut preimage = [0; 80];

let mut n=0;
for  ch in msg.chars() {

    preimage[n]= ch as u8;
    n=n+1;
}

然后我们可以获取此 pre-image 的 SHA-256:

let hash = Sha256::digest(&Sha256::digest(&preimage));

然后使用它来创建证明:

println!("== Creating proof");
// 使用我们的参数创建一个 Groth16 证明。
let proof = groth16::create_random_proof(c, &params, &mut OsRng).unwrap();

该电路是使用变量 c 创建的,并且是从 pre-image 的 SHA-256 哈希创建的。因此,此证明将证明 pre-image 的知识。最后,我们可以使用以下方法进行验证:

// 将哈希值打包为证明验证的输入。
let hash_bits = multipack::bytes_to_bits_le(&hash);
let inputs = multipack::compute_multipacking(&hash_bits);

// 检查证明!
let ver=groth16::verify_proof(&pvk, &proof, &inputs);

if ver.is_ok() { println!("\nProof verified"); }
else  { println!("\nProof NOT verified"); }

当我们使用字符串“Test123”运行时,我们得到:

Setting up circuit
Elapsed: 140.46s

== Setting up verification key

== Verifying key created

Elapsed: 140.49s

Message to prove is Test123

Hash is 15d6efed64a87bbd0679700dd2fe22f0c23c3a6b9a4c80ee42ae965e1dff66e7

== Creating proof
Elapsed: 155.32s

Proof verified
Elapsed: 155.35s

因此,我们看到生成电路花费了将近 140 秒, 然后生成证明花费了大约 15 秒, 但证明它只花费了 0.03 秒。

结论

就这样,生成初始电路可能需要相当长的时间,但创建证明的速度更快。但是,可以快速完成证明的验证。如果你想了解有关 Jen Groth 及其方法的更多信息,请尝试以下方法:

Groth16 和证明你知道 x²-2x-15=0 的答案

参考文献

[1] Groth, J. (2016, April). On the size of pairing-based non-interactive arguments. In Annual international conference on the theory and applications of cryptographic techniques (pp. 305–326). Berlin, Heidelberg: Springer Berlin Heidelberg.

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

0 条评论

请先 登录 后评论
billatnapier
billatnapier
江湖只有他的大名,没有他的介绍。