#![allow(dead_code)]
use super::ed;
use crate::frost::hashing::sha512_256i_tagged;
use purecrypto::ec::edwards25519::hazmat::{EdwardsPoint, Scalar};
use purecrypto::rng::RngCore;
pub(crate) struct ZkProof {
pub alpha: EdwardsPoint,
pub t: Scalar,
}
fn random_scalar<R: RngCore>(rng: &mut R) -> Scalar {
loop {
let mut b = [0u8; 64];
rng.fill_bytes(&mut b);
let s = Scalar::from_bytes_mod_order(&b);
if !bool::from(s.ct_eq(&Scalar::from_bytes_mod_order(&[0u8; 64]))) {
return s;
}
}
}
fn challenge(session: &[u8], x_pub: &EdwardsPoint, alpha: &EdwardsPoint) -> Scalar {
let (xx, xy) = ed::coords_be(x_pub);
let (gx, gy) = ed::generator_coords_be();
let (ax, ay) = ed::coords_be(alpha);
let ops: [&[u8]; 6] = [&xx, &xy, &gx, &gy, &ax, &ay];
let h = sha512_256i_tagged(session, &ops);
ed::scalar_from_be(&h)
}
impl ZkProof {
pub(crate) fn prove<R: RngCore>(
session: &[u8],
x: &Scalar,
x_pub: &EdwardsPoint,
rng: &mut R,
) -> ZkProof {
let a = random_scalar(rng);
let alpha = ed::mul_base(&a);
let c = challenge(session, x_pub, &alpha);
let t = c.mul(x).add(&a);
ZkProof { alpha, t }
}
pub(crate) fn verify(&self, session: &[u8], x_pub: &EdwardsPoint) -> bool {
let c = challenge(session, x_pub, &self.alpha);
let lhs = ed::add(&self.alpha, &ed::mul(x_pub, &c));
ed::eq(&lhs, &ed::mul_base(&self.t))
}
}
#[cfg(test)]
mod tests {
use super::*;
use purecrypto::rng::OsRng;
#[test]
fn zkproof_roundtrip() {
let mut rng = OsRng;
let x = random_scalar(&mut rng);
let xp = ed::mul_base(&x);
let pf = ZkProof::prove(b"sess", &x, &xp, &mut rng);
assert!(pf.verify(b"sess", &xp));
assert!(!pf.verify(b"other", &xp));
let bad = ed::mul_base(&random_scalar(&mut rng));
assert!(!pf.verify(b"sess", &bad));
}
}