use serde::{Serialize, Deserialize};
use crate::elgamal::CryptoContext;
use crate::curve::CurveElem;
use crate::{CryptoError, Hasher, Scalar};
#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
pub struct PrfKnowDlog {
pub(crate) g: CurveElem,
y: CurveElem,
a: CurveElem,
r: Scalar,
}
impl PrfKnowDlog {
fn challenge(g: &CurveElem, y: &CurveElem, a: &CurveElem) -> Scalar {
Hasher::sha_256()
.update(&g.as_bytes())
.update(&y.as_bytes())
.update(&a.as_bytes())
.finish_scalar()
}
pub fn new(ctx: &mut CryptoContext, g: &CurveElem, x: &Scalar, y: &CurveElem) -> Result<Self, CryptoError> {
let z = ctx.random_power()?;
let a = g.scaled(&z);
let c = Self::challenge(g, y, &a);
let r = Scalar(z.0 + c.0 * x.0);
Ok(Self {
g: g.clone(),
y: y.clone(),
a,
r,
})
}
pub fn verify(&self) -> Result<bool, CryptoError> {
let c = Self::challenge(&self.g, &self.y, &self.a);
Ok(self.g.scaled(&self.r) == &self.a + &self.y.scaled(&c))
}
}
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
pub struct PrfEqDlogs {
pub v: CurveElem,
pub f: CurveElem,
pub w: CurveElem,
pub h: CurveElem,
a: CurveElem,
b: CurveElem,
r: Scalar,
}
impl PrfEqDlogs {
fn challenge(f: &CurveElem,
h: &CurveElem,
v: &CurveElem,
w: &CurveElem,
a: &CurveElem,
b: &CurveElem) -> Scalar {
Hasher::sha_256()
.update(&f.as_bytes())
.update(&h.as_bytes())
.update(&v.as_bytes())
.update(&w.as_bytes())
.update(&a.as_bytes())
.update(&b.as_bytes())
.finish_scalar()
}
pub fn new(ctx: &mut CryptoContext,
f: &CurveElem,
h: &CurveElem,
v: &CurveElem,
w: &CurveElem,
x: &Scalar) -> Result<Self, CryptoError> {
let z = ctx.random_power()?;
let a = f.scaled(&z);
let b = h.scaled(&z);
let c = Self::challenge(&f, &h, &v, &w, &a, &b);
let r = Scalar(z.0 + c.0 * x.0);
Ok(Self {
v: v.clone(),
f: f.clone(),
w: w.clone(),
h: h.clone(),
a,
b,
r
})
}
pub fn verify(&self) -> Result<bool, CryptoError> {
let c = Self::challenge(&self.f, &self.h, &self.v, &self.w, &self.a, &self.b);
Ok(self.f.scaled(&self.r) == &self.a + &self.v.scaled(&c)
&& self.h.scaled(&self.r) == &self.b + &self.w.scaled(&c))
}
}
#[cfg(test)]
mod tests {
use crate::elgamal::CryptoContext;
use crate::zkp::{PrfKnowDlog, PrfEqDlogs};
use crate::{DalekScalar, Scalar};
#[test]
fn test_exp_sum() {
let mut ctx = CryptoContext::new();
let a = ctx.random_power().unwrap();
let b = ctx.random_power().unwrap();
let r = Scalar(a.0 + b.0);
let x = ctx.g_to(&r);
let y = ctx.g_to(&a) + ctx.g_to(&b);
assert_eq!(x, y);
}
#[test]
fn test_prf_know_dlog_complete() {
let mut ctx = CryptoContext::new();
let x = ctx.random_power().unwrap();
let y = ctx.g_to(&x);
let g = ctx.generator();
let proof = PrfKnowDlog::new(&mut ctx, &g, &x, &y).unwrap();
assert!(proof.verify().unwrap());
}
#[test]
fn test_prof_know_dlog_sound() {
let mut ctx = CryptoContext::new();
let x = ctx.random_power().unwrap();
let y = ctx.g_to(&x);
let g = ctx.generator();
let mut proof = PrfKnowDlog::new(&mut ctx, &g, &x, &y).unwrap();
proof.r.0 += &DalekScalar::one();
assert!(!proof.verify().unwrap());
}
#[test]
fn test_prf_eq_dlogs_complete() {
let mut ctx = CryptoContext::new();
let x1 = ctx.random_power().unwrap();
let f = ctx.g_to(&x1);
let x2 = ctx.random_power().unwrap();
let h = ctx.g_to(&x2);
let x = ctx.random_power().unwrap();
let v = f.scaled(&x);
let w = h.scaled(&x);
let proof = PrfEqDlogs::new(&mut ctx, &f, &h, &v, &w, &x).unwrap();
assert!(proof.verify().unwrap());
}
#[test]
fn test_prf_eq_dlogs_sound() {
let mut ctx = CryptoContext::new();
let x1 = ctx.random_power().unwrap();
let f = ctx.g_to(&x1);
let x2 = ctx.random_power().unwrap();
let h = ctx.g_to(&x2);
let x = ctx.random_power().unwrap();
let v = f.scaled(&x);
let w = h.scaled(&x);
let mut proof = PrfEqDlogs::new(&mut ctx, &f, &h, &v, &w, &x).unwrap();
proof.r.0 += &DalekScalar::one();
assert!(!proof.verify().unwrap());
}
}