前序博客有:
其中 F ( x ) = x 3 + x + 5 F(x)=x^3+x+5 F(x)=x3+x+5,注意其中 x , y x,y x,y均为public input/output。以连续调用两次为例,代码见:
对IVC proof进行SNARK压缩,有两种压缩实现:
type S1<G1> = spartan::RelaxedR1CSSNARK<G1, EE1<G1>>;
type S2<G2> = spartan::RelaxedR1CSSNARK<G2, EE2<G2>>;
type S1Prime<G1> = spartan::pp::RelaxedR1CSSNARK<G1, EE1<G1>>;
type S2Prime<G2> = spartan::pp::RelaxedR1CSSNARK<G2, EE2<G2>>;
src/nifs.rs
中的测试用例:
#[test]
fn test_tiny_r1cs_bellperson() { // 基于[https://github.com/filecoin-project/bellperson](https://github.com/filecoin-project/bellperson)框架
test_tiny_r1cs_bellperson_with::<G>();
}
#[test]
fn test_tiny_r1cs() { //直观表示
test_tiny_r1cs_with::<pasta_curves::pallas::Point>();
}
src/lib.rs
中:
test_ivc_nontrivial
测试用例中:
#[test]
fn test_ivc_nontrivial() {
type G1 = pasta_curves::pallas::Point;
type G2 = pasta_curves::vesta::Point;
test_ivc_nontrivial_with::<G1, G2>();
}
fn test_ivc_nontrivial_with<G1, G2>()
where
G1: Group<Base = <G2 as Group>::Scalar>,
G2: Group<Base = <G1 as Group>::Scalar>,
{
let circuit_primary = TrivialTestCircuit::default();
let circuit_secondary = CubicCircuit::default();
// produce public parameters
let pp = PublicParams::<
G1,
G2,
TrivialTestCircuit<<G1 as Group>::Scalar>,
CubicCircuit<<G2 as Group>::Scalar>,
>::setup(circuit_primary.clone(), circuit_secondary.clone());
let num_steps = 3;
// produce a recursive SNARK
let mut recursive_snark = RecursiveSNARK::<
G1,
G2,
TrivialTestCircuit<<G1 as Group>::Scalar>,
CubicCircuit<<G2 as Group>::Scalar>,
>::new(
&pp,
&circuit_primary,
&circuit_secondary,
vec![<G1 as Group>::Scalar::ONE],
vec![<G2 as Group>::Scalar::ZERO],
);
for i in 0..num_steps {
let res = recursive_snark.prove_step(
&pp,
&circuit_primary,
&circuit_secondary,
vec![<G1 as Group>::Scalar::ONE],
vec![<G2 as Group>::Scalar::ZERO],
);
assert!(res.is_ok());
// verify the recursive snark at each step of recursion
let res = recursive_snark.verify(
&pp,
i + 1,
&[<G1 as Group>::Scalar::ONE],
&[<G2 as Group>::Scalar::ZERO],
);
assert!(res.is_ok());
}
// verify the recursive SNARK
let res = recursive_snark.verify(
&pp,
num_steps,
&[<G1 as Group>::Scalar::ONE],
&[<G2 as Group>::Scalar::ZERO],
);
assert!(res.is_ok());
let (zn_primary, zn_secondary) = res.unwrap();
// sanity: check the claimed output with a direct computation of the same
assert_eq!(zn_primary, vec![<G1 as Group>::Scalar::ONE]);
let mut zn_secondary_direct = vec![<G2 as Group>::Scalar::ZERO];
for _i in 0..num_steps {
zn_secondary_direct = circuit_secondary.clone().output(&zn_secondary_direct);
}
assert_eq!(zn_secondary, zn_secondary_direct);
assert_eq!(zn_secondary, vec![<G2 as Group>::Scalar::from(2460515u64)]);
}
test_ivc_nontrivial_with_compression
则在test_ivc_nontrivial
测试用例的基础之上,使用CompressedSNARK对结果进行了进一步压缩: // produce a compressed SNARK
let res = CompressedSNARK::<_, _, _, _, S1<G1>, S2<G2>>::prove(&pp, &pk, &recursive_snark);
assert!(res.is_ok());
let compressed_snark = res.unwrap();
// verify the compressed SNARK
let res = compressed_snark.verify(
&vk,
num_steps,
vec![<G1 as Group>::Scalar::ONE],
vec![<G2 as Group>::Scalar::ZERO],
);
assert!(res.is_ok());
test_ivc_nontrivial_with_spark_compression
则在test_ivc_nontrivial
测试用例的基础之上,使用Spark compiler对结果进行了进一步压缩: // run the compressed snark with Spark compiler
// produce the prover and verifier keys for compressed snark
let (pk, vk) = CompressedSNARK::<_, _, _, _, S1Prime<G1>, S2Prime<G2>>::setup(&pp).unwrap();
// produce a compressed SNARK
let res =
CompressedSNARK::<_, _, _, _, S1Prime<G1>, S2Prime<G2>>::prove(&pp, &pk, &recursive_snark);
assert!(res.is_ok());
let compressed_snark = res.unwrap();
// verify the compressed SNARK
let res = compressed_snark.verify(
&vk,
num_steps,
vec![<G1 as Group>::Scalar::ONE],
vec![<G2 as Group>::Scalar::ZERO],
);
assert!(res.is_ok());
test_ivc_nondet_with_compression
中: