use crate::{Gate, Measurement, QuantumChannel, QuantumState, errors::StateError};
pub struct QiaQZKPResult {
pub total_qubits: usize,
pub matches: usize,
pub accuracy: f64,
pub authenticated: bool,
pub alice_id_a: Vec<bool>,
pub alice_commitment_b: Vec<bool>,
pub bob_challenge_c: Vec<bool>,
pub bob_recovered_c: Vec<bool>,
}
pub fn run(
num_qubits: usize,
channel: &QuantumChannel,
acceptance_threshold: f64,
) -> Result<QiaQZKPResult, StateError> {
let a: Vec<bool> = (0..num_qubits)
.map(|_| crate::rng::random_bool(0.5))
.collect();
let mut b_vec = Vec::with_capacity(num_qubits);
let mut c_vec = Vec::with_capacity(num_qubits);
let mut c_recovered_vec = Vec::with_capacity(num_qubits);
let mut matches = 0;
for &a_bit in &a {
let b_bit = crate::rng::random_bool(0.5);
b_vec.push(b_bit);
let mut state = QuantumState::new(1);
if a_bit {
state.apply(&Gate::x(), &[0])?;
}
if b_bit {
state.apply(&Gate::h(), &[0])?;
}
let c_bit = crate::rng::random_bool(0.5);
c_vec.push(c_bit);
if c_bit {
if !b_bit {
state.apply(&Gate::x(), &[0])?;
} else {
state.apply(&Gate::z(), &[0])?;
}
}
state.apply_channel(channel, &[0])?;
if b_bit {
state.apply(&Gate::z(), &[0])?;
}
if a_bit ^ b_bit {
state.apply(&Gate::h(), &[0])?;
}
if a_bit {
state.apply(&Gate::z(), &[0])?;
}
state.apply_channel(channel, &[0])?;
let measurement = if a_bit {
Measurement::x_basis()
} else {
Measurement::z_basis()
};
let res = state.measure(&measurement, &[0])?;
let measured_bit = res.index == 1;
let c_prime = measured_bit ^ b_bit; c_recovered_vec.push(c_prime);
if c_prime == c_bit {
matches += 1;
}
}
let accuracy = matches as f64 / num_qubits as f64;
let authenticated = accuracy >= acceptance_threshold;
Ok(QiaQZKPResult {
total_qubits: num_qubits,
matches,
accuracy,
authenticated,
alice_id_a: a,
alice_commitment_b: b_vec,
bob_challenge_c: c_vec,
bob_recovered_c: c_recovered_vec,
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_qia_qzkp_noiseless() {
let channel = QuantumChannel::bit_flip(0.0);
let result = run(100, &channel, 0.9).unwrap();
assert_eq!(result.total_qubits, 100);
assert_eq!(result.matches, 100);
assert_eq!(result.accuracy, 1.0);
assert!(result.authenticated);
}
#[test]
fn test_qia_qzkp_noise_rejection() {
let channel = QuantumChannel::bit_flip(1.0); let result = run(100, &channel, 0.9).unwrap();
assert!(!result.authenticated);
}
}