1. Proof of exponentiation
Proof of exponentiation时基于adaptive root assumption(充分必要条件)的。
特别适合当
很大时,计算
将大量节约verifier直接计算
的时间。
借助Fiat-Shamir heuristic,可将上面的交互式PoE转化为NI-PoE:
对应在https://github.com/dignifiedquire/rust-accumulators/blob/master/src/proofs.rs
中的实现为:
/// NI-PoE Prove
/// Assumes `u^x = w`
/// All operations are `mod n`.
pub fn ni_poe_prove(x: &BigUint, u: &BigUint, w: &BigUint, n: &BigUint) -> ExponentProof {
debug_assert!(&u.modpow(x, n) == w, "invalid input");
// l <- H_prime(x, u, w)
let mut to_hash = x.to_bytes_be();
to_hash.extend(&u.to_bytes_be());
to_hash.extend(&w.to_bytes_be());
let l = hash_prime::<_, Blake2b>(&to_hash);
// q <- floor(x/l)
let q = x.div_floor(&l);
//Prover sends Q <- u^q ∈ G to the Verifier.
u.modpow(&q, n)
}
/// NI-PoE Verify
/// Assumes `u^x = w`
/// All operations are `mod n`.
pub fn ni_poe_verify(
x: &BigUint,
u: &BigUint,
w: &BigUint,
q: &ExponentProof,
n: &BigUint,
) -> bool {
// l <- H_prime(x, u, w)
let mut to_hash = x.to_bytes_be();
to_hash.extend(&u.to_bytes_be());
to_hash.extend(&w.to_bytes_be());
let l = hash_prime::<_, Blake2b>(&to_hash);
// r <- x mod l
let r = x.mod_floor(&l);
// Q^l u^r == w
&((q.modpow(&l, &n) * &u.modpow(&r, &n)) % n) == w
}
// 基于hash值来获取prime数值。
// When the proofs are made non-interactive, using the
// Fiat-Shamir heuristic the challenge is generated by hashing the previous transcript
/// Hash the given numbers to a prime number.
/// Currently uses only 128bits.
pub fn hash_prime<O: ArrayLength<u8>, D: Digest<OutputSize = O>>(input: &[u8]) -> BigUint {
let mut y = BigUint::from_bytes_be(&D::digest(input)[..16]);
while !probably_prime(&y, 20) {
y = BigUint::from_bytes_be(&D::digest(&y.to_bytes_be())[..16]);
}
y
}
2. Proof of knowledge of exponentiation
2.1 有安全攻击隐患的PoKE
此时,verifier不需要自己计算余数
,改由prover提供。同时注意,此时要求discrete logarithm base
必须被包含在CRS中
存在安全攻击问题,不是secure protocol:
2.2 基于base 和 的两次PoKE
对witness
的证明,做了两次PoKE证明,一次是base
,一次是base
。
以上,proof中包含了两个group元素
。如下,通过增加一个challenge
,可以将proof中的group元素仍然减为1个
:
借助Fiat-Shamir heuristic,可将上面的交互式PoKE2转化为NI-PoKE2:
对应在https://github.com/dignifiedquire/rust-accumulators/blob/master/src/proofs.rs
中的实现为:
//proof of knowledge of exponent, i.e. a proof that a computationally bounded prover knows the discrete logarithm between two elements in a group of unknown order. The proof is succinct in that the proof size and verification time is independent of the size of the discrete-log.
/// NI-PoKE2 Prove
/// assumes `u^x = w`
/// All operations are `mod n`.
pub fn ni_poke2_prove(
x: impl Into<BigInt>,
u: &BigUint,
w: &BigUint,
n: &BigUint,
) -> (BigUint, BigUint, BigInt) {
let x: BigInt = x.into();
debug_assert!(&modpow_uint_int(u, &x, n).unwrap() == w, "invalid input");
// g <- H_G(u, w)
let mut to_hash = u.to_bytes_be();
to_hash.extend(&w.to_bytes_be());
let g = hash_group::<_, Blake2b>(&to_hash, n);
// z = g^x
let z = modpow_uint_int(&g, &x, n).expect("invalid state");
// l <- H_prime(u, w, z)
to_hash.extend(&z.to_bytes_be());
let l: BigInt = hash_prime::<_, Blake2b>(&to_hash).into();
// alpha = H(u, w, z, l)
to_hash.extend(&l.to_bytes_be().1);
let alpha = BigUint::from_bytes_be(&Blake2b::digest(&to_hash)[..]);
// q <- floor(x/l)
// r <- x % l
let (q, r) = x.div_rem(&l);
// Q <- (ug^alpha)^q
let q_big = modpow_uint_int(&(u * &g.modpow(&alpha, n)), &q, n).expect("invalid state");
(z, q_big, r)
}
/// NI-PoKE2 Verify
/// assumes `u^x = w`
/// All operations are `mod n`
pub fn ni_poke2_verify(
u: &BigUint,
w: &BigUint,
pi: &(BigUint, BigUint, BigInt),
n: &BigUint,
) -> bool {
// {z, Q, r} <- pi
let (z, q_big, r) = pi;
// g <- H_G(u, w)
let mut to_hash = u.to_bytes_be();
to_hash.extend(&w.to_bytes_be());
let g = hash_group::<_, Blake2b>(&to_hash, n);
// l <- H_prime(u, w, z)
to_hash.extend(&z.to_bytes_be());
let l = hash_prime::<_, Blake2b>(&to_hash);
// alpha = H(u, w, z, l)
to_hash.extend(&l.to_bytes_be());
let alpha = BigUint::from_bytes_be(&Blake2b::digest(&to_hash)[..]);
// Q^l(ug^alpha)^r
let lhs: BigInt = ((q_big.modpow(&l, n)
* modpow_uint_int(&(u * &g.modpow(&alpha, n)), &r, n).expect("invalid state"))
% n)
.into();
// wz^alpha
let z_alpha = z.modpow(&alpha, n);
let rhs: BigInt = ((w * z_alpha) % n).into();
lhs == rhs
}
3. Aggreating Knowledge of Co-prime Roots
在第2节中,已可证明
,若有一系列的co-prime roots
满足
且
https://github.com/cambrian/accumulator/
中也有相应的代码实现,且实现的性能要优于https://github.com/dignifiedquire/rust-accumulators/
。
``
#[allow(non_snake_case)]
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
/// Struct for NI-PoKCR.
pub struct Pokcr<G: Group> {
w: G::Elem,
}
impl<G: Group> Pokcr<G> {
/// Generates an NI-PoKCR proof.
pub fn prove(witnesses: &[G::Elem]) -> Self {
Self {
w: witnesses.iter().fold(G::id(), |a, b| G::op(&a, b)),
}
}
/// Verifies an NI-PoKCR proof.
pub fn verify(alphas: &[G::Elem], x: &[Integer], proof: &Self) -> bool {
let y = multi_exp::<G>(alphas, x);
let lhs = G::exp(&proof.w, &x.iter().product());
lhs == y
}
}
参考资料:
[1] 2018年论文《Batching Techniques for Accumulators with Applications to IOPs and Stateless Blockchains》
[2] 博客密码学中的各种假设——DL/SDH…