#[doc(hidden)]
#[macro_export]
macro_rules! __compute_formula_constraint {
(($public_vars:ident, $secret_vars:ident) ($($x:tt)*)) => {
__compute_formula_constraint!(($public_vars,$secret_vars) $($x)* +)
};
(($public_vars:ident, $secret_vars:ident)
$( $scalar:ident * $point:ident +)+ ) => {
vec![ $( ($secret_vars.$scalar , $public_vars.$point), )* ]
};
}
#[macro_export]
macro_rules! define_proof {
(
$proof_module_name:ident
,
$proof_label_string:expr
,
( $($secret_var:ident),+ )
,
( $($instance_var:ident),* )
,
( $($common_var:ident),* )
:
$($lhs:ident = $statement:tt),+
) => {
#[allow(non_snake_case)]
pub mod $proof_module_name {
use $crate::curve25519_dalek::scalar::Scalar;
use $crate::curve25519_dalek::ristretto::RistrettoPoint;
use $crate::curve25519_dalek::ristretto::CompressedRistretto;
use $crate::toolbox::prover::Prover;
use $crate::toolbox::verifier::Verifier;
pub use $crate::merlin::Transcript;
pub use $crate::{CompactProof, BatchableProof, ProofError};
pub mod internal {
use $crate::toolbox::SchnorrCS;
pub const PROOF_LABEL: &'static str = $proof_label_string;
pub struct TranscriptLabels {
$( pub $secret_var: &'static str, )+
$( pub $instance_var: &'static str, )+
$( pub $common_var: &'static str, )+
}
pub const TRANSCRIPT_LABELS: TranscriptLabels = TranscriptLabels {
$( $secret_var: stringify!($secret_var), )+
$( $instance_var: stringify!($instance_var), )+
$( $common_var: stringify!($common_var), )+
};
#[derive(Copy, Clone)]
pub struct SecretVars<CS: SchnorrCS> {
$( pub $secret_var: CS::ScalarVar, )+
}
#[derive(Copy, Clone)]
pub struct PublicVars<CS: SchnorrCS> {
$( pub $instance_var: CS::PointVar, )+
$( pub $common_var: CS::PointVar, )+
}
pub fn proof_statement<CS: SchnorrCS>(
cs: &mut CS,
secrets: SecretVars<CS>,
publics: PublicVars<CS>,
) {
$(
cs.constrain(
publics.$lhs,
__compute_formula_constraint!( (publics, secrets) $statement ),
);
)+
}
}
#[derive(Copy, Clone)]
pub struct ProveAssignments<'a> {
$(pub $secret_var: &'a Scalar,)+
$(pub $instance_var: &'a RistrettoPoint,)+
$(pub $common_var: &'a RistrettoPoint,)+
}
#[derive(Copy, Clone)]
pub struct VerifyAssignments<'a> {
$(pub $instance_var: &'a CompressedRistretto,)+
$(pub $common_var: &'a CompressedRistretto,)+
}
#[derive(Copy, Clone)]
pub struct CompressedPoints {
$(pub $instance_var: CompressedRistretto,)+
$(pub $common_var: CompressedRistretto,)+
}
#[derive(Clone)]
pub struct BatchVerifyAssignments {
$(pub $instance_var: Vec<CompressedRistretto>,)+
$(pub $common_var: CompressedRistretto,)+
}
fn build_prover<'a>(
transcript: &'a mut Transcript,
assignments: ProveAssignments,
) -> (Prover<'a>, CompressedPoints) {
use self::internal::*;
use $crate::toolbox::prover::*;
let mut prover = Prover::new(PROOF_LABEL.as_bytes(), transcript);
let secret_vars = SecretVars {
$(
$secret_var: prover.allocate_scalar(
TRANSCRIPT_LABELS.$secret_var.as_bytes(),
*assignments.$secret_var,
),
)+
};
struct VarPointPairs {
$( pub $instance_var: (PointVar, CompressedRistretto), )+
$( pub $common_var: (PointVar, CompressedRistretto), )+
}
let pairs = VarPointPairs {
$(
$instance_var: prover.allocate_point(
TRANSCRIPT_LABELS.$instance_var.as_bytes(),
*assignments.$instance_var,
),
)+
$(
$common_var: prover.allocate_point(
TRANSCRIPT_LABELS.$common_var.as_bytes(),
*assignments.$common_var,
),
)+
};
let public_vars = PublicVars {
$($instance_var: pairs.$instance_var.0,)+
$($common_var: pairs.$common_var.0,)+
};
let compressed = CompressedPoints {
$($instance_var: pairs.$instance_var.1,)+
$($common_var: pairs.$common_var.1,)+
};
proof_statement(&mut prover, secret_vars, public_vars);
(prover, compressed)
}
pub fn prove_compact(
transcript: &mut Transcript,
assignments: ProveAssignments,
) -> (CompactProof, CompressedPoints) {
let (prover, compressed) = build_prover(transcript, assignments);
(prover.prove_compact(), compressed)
}
pub fn prove_batchable(
transcript: &mut Transcript,
assignments: ProveAssignments,
) -> (BatchableProof, CompressedPoints) {
let (prover, compressed) = build_prover(transcript, assignments);
(prover.prove_batchable(), compressed)
}
fn build_verifier<'a>(
transcript: &'a mut Transcript,
assignments: VerifyAssignments,
) -> Result<Verifier<'a>, ProofError> {
use self::internal::*;
use $crate::toolbox::verifier::*;
let mut verifier = Verifier::new(PROOF_LABEL.as_bytes(), transcript);
let secret_vars = SecretVars {
$($secret_var: verifier.allocate_scalar(TRANSCRIPT_LABELS.$secret_var.as_bytes()),)+
};
let public_vars = PublicVars {
$(
$instance_var: verifier.allocate_point(
TRANSCRIPT_LABELS.$instance_var.as_bytes(),
*assignments.$instance_var,
)?,
)+
$(
$common_var: verifier.allocate_point(
TRANSCRIPT_LABELS.$common_var.as_bytes(),
*assignments.$common_var,
)?,
)+
};
proof_statement(&mut verifier, secret_vars, public_vars);
Ok(verifier)
}
pub fn verify_compact(
proof: &CompactProof,
transcript: &mut Transcript,
assignments: VerifyAssignments,
) -> Result<(), ProofError> {
let verifier = build_verifier(transcript, assignments)?;
verifier.verify_compact(proof)
}
pub fn verify_batchable(
proof: &BatchableProof,
transcript: &mut Transcript,
assignments: VerifyAssignments,
) -> Result<(), ProofError> {
let verifier = build_verifier(transcript, assignments)?;
verifier.verify_batchable(proof)
}
pub fn batch_verify(
proofs: &[BatchableProof],
transcripts: Vec<&mut Transcript>,
assignments: BatchVerifyAssignments,
) -> Result<(), ProofError> {
use self::internal::*;
use $crate::toolbox::batch_verifier::*;
let batch_size = proofs.len();
let mut verifier = BatchVerifier::new(PROOF_LABEL.as_bytes(), batch_size, transcripts)?;
let secret_vars = SecretVars {
$($secret_var: verifier.allocate_scalar(TRANSCRIPT_LABELS.$secret_var.as_bytes()),)+
};
let public_vars = PublicVars {
$(
$instance_var: verifier.allocate_instance_point(
TRANSCRIPT_LABELS.$instance_var.as_bytes(),
assignments.$instance_var,
)?,
)+
$(
$common_var: verifier.allocate_static_point(
TRANSCRIPT_LABELS.$common_var.as_bytes(),
assignments.$common_var,
)?,
)+
};
proof_statement(&mut verifier, secret_vars, public_vars);
verifier.verify_batchable(proofs)
}
#[cfg(all(feature = "bench", test))]
mod bench {
use super::*;
use $crate::rand::thread_rng;
extern crate test;
use self::test::Bencher;
#[bench]
fn prove(b: &mut Bencher) {
let mut rng = thread_rng();
struct RandomAssignments {
$(pub $secret_var: Scalar,)+
$(pub $instance_var: RistrettoPoint,)+
$(pub $common_var: RistrettoPoint,)+
}
let assignments = RandomAssignments {
$($secret_var: Scalar::random(&mut rng),)+
$($instance_var: RistrettoPoint::random(&mut rng),)+
$($common_var: RistrettoPoint::random(&mut rng),)+
};
b.iter(|| {
let mut trans = Transcript::new(b"Benchmark");
prove_compact(&mut trans, ProveAssignments {
$($secret_var: &assignments.$secret_var,)+
$($instance_var: &assignments.$instance_var,)+
$($common_var: &assignments.$common_var,)+
})
});
}
#[bench]
fn verify_compact_proof(b: &mut Bencher) {
let mut rng = thread_rng();
struct RandomAssignments {
$(pub $secret_var: Scalar,)+
$(pub $instance_var: RistrettoPoint,)+
$(pub $common_var: RistrettoPoint,)+
}
let assignments = RandomAssignments {
$($secret_var: Scalar::random(&mut rng),)+
$($instance_var: RistrettoPoint::random(&mut rng),)+
$($common_var: RistrettoPoint::random(&mut rng),)+
};
let mut trans = Transcript::new(b"Benchmark");
let (proof, points) = prove_compact(&mut trans, ProveAssignments {
$($secret_var: &assignments.$secret_var,)+
$($instance_var: &assignments.$instance_var,)+
$($common_var: &assignments.$common_var,)+
});
b.iter(|| {
let mut trans = Transcript::new(b"Benchmark");
verify_compact(&proof, &mut trans, VerifyAssignments {
$($instance_var: &points.$instance_var,)+
$($common_var: &points.$common_var,)+
})
});
}
#[bench]
fn verify_batchable_proof(b: &mut Bencher) {
let mut rng = thread_rng();
struct RandomAssignments {
$(pub $secret_var: Scalar,)+
$(pub $instance_var: RistrettoPoint,)+
$(pub $common_var: RistrettoPoint,)+
}
let assignments = RandomAssignments {
$($secret_var: Scalar::random(&mut rng),)+
$($instance_var: RistrettoPoint::random(&mut rng),)+
$($common_var: RistrettoPoint::random(&mut rng),)+
};
let mut trans = Transcript::new(b"Benchmark");
let (proof, points) = prove_batchable(&mut trans, ProveAssignments {
$($secret_var: &assignments.$secret_var,)+
$($instance_var: &assignments.$instance_var,)+
$($common_var: &assignments.$common_var,)+
});
b.iter(|| {
let mut trans = Transcript::new(b"Benchmark");
verify_batchable(&proof, &mut trans, VerifyAssignments {
$($instance_var: &points.$instance_var,)+
$($common_var: &points.$common_var,)+
})
});
}
}
}
}
}