use group::Group;
use jubjub::{AffinePoint, ExtendedPoint};
use rand::SeedableRng;
use rand_chacha::ChaChaRng;
use proptest::{collection::vec, prelude::*};
use crate::primitives::Groth16Proof;
use super::{
keys::{self, ValidatingKey},
note, tree, FieldNotPresent, NoteCommitment, Output, OutputInTransactionV4, PerSpendAnchor,
SharedAnchor, Spend,
};
impl Arbitrary for Spend<PerSpendAnchor> {
type Parameters = ();
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
(
any::<tree::Root>(),
any::<note::Nullifier>(),
spendauth_verification_key_bytes(),
any::<Groth16Proof>(),
vec(any::<u8>(), 64),
)
.prop_map(|(per_spend_anchor, nullifier, rk, proof, sig_bytes)| Self {
per_spend_anchor,
cv: ExtendedPoint::generator().try_into().unwrap(),
nullifier,
rk,
zkproof: proof,
spend_auth_sig: redjubjub::Signature::from({
let mut b = [0u8; 64];
b.copy_from_slice(sig_bytes.as_slice());
b
}),
})
.boxed()
}
type Strategy = BoxedStrategy<Self>;
}
impl Arbitrary for Spend<SharedAnchor> {
type Parameters = ();
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
(
any::<note::Nullifier>(),
spendauth_verification_key_bytes(),
any::<Groth16Proof>(),
vec(any::<u8>(), 64),
)
.prop_map(|(nullifier, rk, proof, sig_bytes)| Self {
per_spend_anchor: FieldNotPresent,
cv: ExtendedPoint::generator().try_into().unwrap(),
nullifier,
rk,
zkproof: proof,
spend_auth_sig: redjubjub::Signature::from({
let mut b = [0u8; 64];
b.copy_from_slice(sig_bytes.as_slice());
b
}),
})
.boxed()
}
type Strategy = BoxedStrategy<Self>;
}
impl Arbitrary for Output {
type Parameters = ();
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
(
any::<note::EncryptedNote>(),
any::<note::WrappedNoteKey>(),
any::<Groth16Proof>(),
)
.prop_map(|(enc_ciphertext, out_ciphertext, zkproof)| Self {
cv: ExtendedPoint::generator().try_into().unwrap(),
cm_u: NoteCommitment(AffinePoint::identity()).extract_u(),
ephemeral_key: keys::EphemeralPublicKey(ExtendedPoint::generator().into()),
enc_ciphertext,
out_ciphertext,
zkproof,
})
.boxed()
}
type Strategy = BoxedStrategy<Self>;
}
impl Arbitrary for OutputInTransactionV4 {
type Parameters = ();
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
any::<Output>().prop_map(OutputInTransactionV4).boxed()
}
type Strategy = BoxedStrategy<Self>;
}
fn spendauth_verification_key_bytes() -> impl Strategy<Value = ValidatingKey> {
prop::array::uniform32(any::<u8>()).prop_map(|bytes| {
let rng = ChaChaRng::from_seed(bytes);
let sk = redjubjub::SigningKey::<redjubjub::SpendAuth>::new(rng);
redjubjub::VerificationKey::<redjubjub::SpendAuth>::from(&sk)
.try_into()
.unwrap()
})
}
fn jubjub_base_strat() -> BoxedStrategy<jubjub::Base> {
(vec(any::<u8>(), 64))
.prop_map(|bytes| {
let bytes = bytes.try_into().expect("vec is the correct length");
jubjub::Base::from_bytes_wide(&bytes)
})
.boxed()
}
impl Arbitrary for tree::Root {
type Parameters = ();
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
jubjub_base_strat().prop_map(tree::Root).boxed()
}
type Strategy = BoxedStrategy<Self>;
}
impl Arbitrary for tree::Node {
type Parameters = ();
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
jubjub_base_strat().prop_map(tree::Node::from).boxed()
}
type Strategy = BoxedStrategy<Self>;
}