use ark_ec::{CurveGroup, PrimeGroup};
use ark_std::UniformRand;
use rand::rngs::OsRng;
use spongefish::{
protocol_id, Codec, DomainSeparator, Encoding, NargDeserialize, NargSerialize, ProverState,
VerificationError, VerificationResult, VerifierState,
};
struct Schnorr;
impl Schnorr {
pub fn protocol_id() -> [u8; 64] {
protocol_id(core::format_args!("schnorr proof"))
}
#[allow(non_snake_case)]
fn prove<'a, G>(
prover_state: &'a mut ProverState,
instance: &[G; 2],
x: G::ScalarField,
) -> &'a [u8]
where
G: CurveGroup + NargSerialize + Encoding + Clone,
G::ScalarField: Codec,
{
let k = G::ScalarField::rand(prover_state.rng());
let K = instance[0] * k;
prover_state.prover_message(&K);
let c = prover_state.verifier_message::<G::ScalarField>();
let r = k + c * x;
prover_state.prover_message(&r);
prover_state.narg_string()
}
#[allow(non_snake_case)]
fn verify<G>(mut verifier_state: VerifierState, P: G, X: G) -> VerificationResult<()>
where
G: CurveGroup + NargDeserialize + Encoding,
G::ScalarField: Codec,
{
let K = verifier_state.prover_message::<G>()?;
let c = verifier_state.verifier_message::<G::ScalarField>();
let r = verifier_state.prover_message::<G::ScalarField>()?;
let relation_holds = P * r == K + X * c;
if !relation_holds {
return Err(VerificationError);
}
verifier_state.check_eof()?;
Ok(())
}
}
fn main() {
type G = ark_curve25519::EdwardsProjective;
type F = ark_curve25519::Fr;
let generator = G::generator();
let sk = F::rand(&mut OsRng);
let pk = generator * sk;
let instance = [generator, pk];
let domain_sep = DomainSeparator::new(Schnorr::protocol_id())
.session(spongefish::session!("spongefish examples"))
.instance(&instance);
let mut prover_state = domain_sep.std_prover();
let narg_string = Schnorr::prove(&mut prover_state, &instance, sk);
println!("Here's a Schnorr signature:\n{}", hex::encode(narg_string));
let verifier_state = domain_sep.std_verifier(narg_string);
Schnorr::verify(verifier_state, instance[0], instance[1]).expect("Verification failed");
}