use super::wscalar::Wscalar;
use super::ProverMessage;
use ergo_chain_types::EcPoint;
use ergotree_ir::serialization::SigmaSerializable;
#[derive(PartialEq, Eq, Debug, Clone)]
#[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(proptest_derive::Arbitrary))]
pub struct FirstDlogProverMessage {
#[cfg_attr(feature = "json", serde(rename = "a"))]
pub(crate) a: Box<EcPoint>,
}
impl From<EcPoint> for FirstDlogProverMessage {
fn from(ecp: EcPoint) -> Self {
FirstDlogProverMessage { a: ecp.into() }
}
}
impl ProverMessage for FirstDlogProverMessage {
fn bytes(&self) -> Vec<u8> {
#[allow(clippy::unwrap_used)]
self.a.sigma_serialize_bytes().unwrap()
}
}
#[derive(PartialEq, Eq, Debug, Clone, derive_more::From, derive_more::Into)]
#[cfg_attr(feature = "arbitrary", derive(proptest_derive::Arbitrary))]
pub struct SecondDlogProverMessage {
pub z: Wscalar,
}
pub mod interactive_prover {
use std::ops::Mul;
use super::{FirstDlogProverMessage, SecondDlogProverMessage};
use crate::sigma_protocol::crypto_utils;
use crate::sigma_protocol::wscalar::Wscalar;
use crate::sigma_protocol::{private_input::DlogProverInput, Challenge};
use ergo_chain_types::{
ec_point::{exponentiate, generator, inverse},
EcPoint,
};
use ergotree_ir::sigma_protocol::dlog_group;
use ergotree_ir::sigma_protocol::sigma_boolean::ProveDlog;
use k256::Scalar;
pub(crate) fn simulate(
public_input: &ProveDlog,
challenge: &Challenge,
) -> (FirstDlogProverMessage, SecondDlogProverMessage) {
let z = dlog_group::random_scalar_in_group_range(crypto_utils::secure_rng());
let e: Scalar = challenge.clone().into();
let minus_e = e.negate();
let h_to_e = exponentiate(&public_input.h, &minus_e);
let g_to_z = exponentiate(&generator(), &z);
let a = g_to_z * &h_to_e;
(
FirstDlogProverMessage { a: a.into() },
SecondDlogProverMessage { z: z.into() },
)
}
pub fn first_message() -> (Wscalar, FirstDlogProverMessage) {
let r = dlog_group::random_scalar_in_group_range(crypto_utils::secure_rng());
let g = generator();
let a = exponentiate(&g, &r);
(r.into(), FirstDlogProverMessage { a: a.into() })
}
pub(crate) fn second_message(
private_input: &DlogProverInput,
rnd: Wscalar,
challenge: &Challenge,
) -> SecondDlogProverMessage {
let e: Scalar = challenge.clone().into();
let ew = e.mul(private_input.w.as_scalar_ref());
let z = rnd.as_scalar_ref().add(&ew);
SecondDlogProverMessage { z: z.into() }
}
pub fn compute_commitment(
proposition: &ProveDlog,
challenge: &Challenge,
second_message: &SecondDlogProverMessage,
) -> EcPoint {
let g = generator();
let h = *proposition.h.clone();
let e: Scalar = challenge.clone().into();
let g_z = exponentiate(&g, second_message.z.as_scalar_ref());
let h_e = exponentiate(&h, &e);
g_z * &inverse(&h_e)
}
}
#[allow(clippy::panic)]
#[cfg(test)]
#[cfg(feature = "arbitrary")]
mod tests {
use super::super::*;
use super::*;
use crate::sigma_protocol::private_input::DlogProverInput;
use proptest::prelude::*;
proptest! {
#![proptest_config(ProptestConfig::with_cases(16))]
#[test]
#[cfg(feature = "arbitrary")]
fn test_compute_commitment(secret in any::<DlogProverInput>(), challenge in any::<Challenge>()) {
let pk = secret.public_image();
let (r, commitment) = interactive_prover::first_message();
let second_message = interactive_prover::second_message(&secret, r, &challenge);
let a = interactive_prover::compute_commitment(&pk, &challenge, &second_message);
prop_assert_eq!(a, *commitment.a);
}
}
}