use anyhow::Result;
use midnight_circuits::hash::poseidon::PoseidonState;
use midnight_curves::Bls12;
use midnight_proofs::poly::kzg::params::ParamsKZG;
use midnight_zk_stdlib as zk;
use midnight_zk_stdlib::{MidnightCircuit, Relation};
use rand_chacha::ChaCha20Rng;
use rand_core::SeedableRng;
use crate::LotteryTargetValue;
use crate::circuits::halo2::types::CircuitBase;
use crate::circuits::halo2::witness::LotteryTargetValue as CircuitLotteryTargetValue;
use crate::circuits::halo2::witness::{
CircuitMerkleTreeLeaf, CircuitWitnessEntry, MerklePath, MerkleRoot, SignedMessageWithoutPrefix,
};
use crate::hash::poseidon::MidnightPoseidonDigest;
use crate::membership_commitment::{
MerkleTree as StmMerkleTree, MerkleTreeSnarkLeaf as StmMerkleTreeSnarkLeaf,
};
use crate::signature_scheme::{BaseFieldElement, SchnorrSigningKey, SchnorrVerificationKey};
pub(crate) const TEST_MERKLE_TREE_DEPTH: usize = 3;
pub(crate) fn prove_and_verify_relation<R>(
relation: &R,
instance: &R::Instance,
witness: R::Witness,
) -> Result<()>
where
R: Relation,
{
let circuit = MidnightCircuit::from_relation(relation);
let srs = ParamsKZG::<Bls12>::unsafe_setup(circuit.min_k(), ChaCha20Rng::seed_from_u64(42));
let vk = zk::setup_vk(&srs, relation);
let pk = zk::setup_pk(relation, &vk);
let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
let proof = zk::prove::<R, PoseidonState<CircuitBase>>(
&srs, &pk, relation, instance, witness, &mut rng,
)
.map_err(anyhow::Error::new)?;
zk::verify::<R, PoseidonState<CircuitBase>>(&srs.verifier_params(), &vk, instance, None, &proof)
.map_err(anyhow::Error::new)
}
pub(crate) fn assert_relation_rejected(result: Result<()>) {
assert!(result.is_err(), "expected relation to reject witness");
}
pub(crate) fn comparison_used_chips() -> midnight_zk_stdlib::ZkStdLibArch {
midnight_zk_stdlib::ZkStdLibArch {
nr_pow2range_cols: 2,
..midnight_zk_stdlib::ZkStdLibArch::default()
}
}
pub(crate) fn jubjub_poseidon_used_chips() -> midnight_zk_stdlib::ZkStdLibArch {
midnight_zk_stdlib::ZkStdLibArch {
jubjub: true,
poseidon: true,
nr_pow2range_cols: 2,
..midnight_zk_stdlib::ZkStdLibArch::default()
}
}
pub(crate) fn sample_valid_circuit_witness_entry()
-> Result<(CircuitWitnessEntry, MerkleRoot, SignedMessageWithoutPrefix)> {
let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
let signing_key = SchnorrSigningKey::generate(&mut rng);
let verification_key = SchnorrVerificationKey::new_from_signing_key(signing_key.clone());
let circuit_lottery_target_value = -CircuitLotteryTargetValue::ONE;
let stm_lottery_target_value: LotteryTargetValue = circuit_lottery_target_value.into();
let leaf = StmMerkleTreeSnarkLeaf(verification_key, stm_lottery_target_value);
let stm_tree = StmMerkleTree::<MidnightPoseidonDigest, StmMerkleTreeSnarkLeaf>::new(
&vec![leaf; 1 << TEST_MERKLE_TREE_DEPTH],
);
let merkle_tree_commitment: MerkleRoot =
BaseFieldElement::from_bytes(stm_tree.to_merkle_tree_commitment().root.as_slice())?.into();
let message = SignedMessageWithoutPrefix::from(42u64);
let transcript = [merkle_tree_commitment.into(), message.into()];
let unique_schnorr_signature = signing_key.sign(&transcript, &mut rng)?;
let merkle_path: MerklePath = (&stm_tree.compute_merkle_tree_path(0)).try_into()?;
let entry = CircuitWitnessEntry {
leaf: CircuitMerkleTreeLeaf(verification_key, circuit_lottery_target_value),
merkle_path,
unique_schnorr_signature,
lottery_index: 0,
};
Ok((entry, merkle_tree_commitment, message))
}
macro_rules! impl_focused_test_relation {
($name:ident, $witness:ty, $chips:expr, |$std_lib:ident, $layouter:ident, $witness_value:ident| $body:block) => {
#[derive(Clone, Default, Debug)]
struct $name;
impl midnight_zk_stdlib::Relation for $name {
type Instance = ();
type Witness = $witness;
fn format_instance(
_instance: &Self::Instance,
) -> Result<Vec<crate::circuits::halo2::types::CircuitBase>, midnight_proofs::plonk::Error> {
Ok(vec![])
}
fn circuit(
&self,
$std_lib: &midnight_zk_stdlib::ZkStdLib,
$layouter: &mut impl midnight_proofs::circuit::Layouter<crate::circuits::halo2::types::CircuitBase>,
_instance: midnight_proofs::circuit::Value<()>,
$witness_value: midnight_proofs::circuit::Value<$witness>,
) -> Result<(), midnight_proofs::plonk::Error> $body
fn used_chips(&self) -> midnight_zk_stdlib::ZkStdLibArch {
$chips
}
fn write_relation<W: std::io::Write>(&self, _writer: &mut W) -> std::io::Result<()> {
Ok(())
}
fn read_relation<R: std::io::Read>(_reader: &mut R) -> std::io::Result<Self> {
Ok(Self)
}
}
};
}
pub(crate) use impl_focused_test_relation;