use curve25519_dalek::ristretto::RistrettoPoint;
use curve25519_dalek::scalar::Scalar;
use rand::rngs::OsRng;
use rand::TryRngCore;
use crate::error::{Error, Result};
use crate::sigma::{MultiPointCommitment, ScalarChallenge, ScalarResponse, SigmaProtocol};
#[derive(Clone, Debug)]
pub struct DLEQStatement {
pub g: RistrettoPoint,
pub h: RistrettoPoint,
pub x: RistrettoPoint,
pub y: RistrettoPoint,
}
#[derive(Clone, Debug)]
pub struct DLEQWitness {
pub alpha: Scalar,
}
pub struct DLEQProof;
impl SigmaProtocol for DLEQProof {
type Statement = DLEQStatement;
type Witness = DLEQWitness;
type Commitment = MultiPointCommitment;
type Challenge = ScalarChallenge;
type Response = ScalarResponse;
fn prover_commit(
statement: &Self::Statement,
_witness: &Self::Witness,
) -> (Self::Commitment, Vec<u8>) {
let mut r_bytes = [0u8; 32];
OsRng
.try_fill_bytes(&mut r_bytes)
.expect("Failed to generate random bytes");
let r = Scalar::from_bytes_mod_order(r_bytes);
let a = r * statement.g;
let b = r * statement.h;
let state = r.to_bytes().to_vec();
(MultiPointCommitment(vec![a, b]), state)
}
fn prover_response(
_statement: &Self::Statement,
witness: &Self::Witness,
state: &[u8],
challenge: &Self::Challenge,
) -> Result<Self::Response> {
if state.len() != 32 {
return Err(Error::InvalidProof);
}
let mut r_bytes = [0u8; 32];
r_bytes.copy_from_slice(state);
let r_option = Scalar::from_canonical_bytes(r_bytes);
let r = if r_option.is_some().unwrap_u8() == 1 {
r_option.unwrap()
} else {
return Err(Error::InvalidScalar);
};
let response = r + challenge.0 * witness.alpha;
Ok(ScalarResponse(response))
}
fn verifier(
statement: &Self::Statement,
commitment: &Self::Commitment,
challenge: &Self::Challenge,
response: &Self::Response,
) -> Result<()> {
if commitment.0.len() != 2 {
return Err(Error::InvalidCommitment);
}
let a = commitment.0[0];
let b = commitment.0[1];
let lhs_g = response.0 * statement.g;
let rhs_g = a + challenge.0 * statement.x;
let lhs_h = response.0 * statement.h;
let rhs_h = b + challenge.0 * statement.y;
if lhs_g == rhs_g && lhs_h == rhs_h {
Ok(())
} else {
Err(Error::InvalidProof)
}
}
}