zebra_chain/sapling/
arbitrary.rs
1use group::Group;
4use jubjub::{AffinePoint, ExtendedPoint};
5use rand::SeedableRng;
6use rand_chacha::ChaChaRng;
7
8use proptest::{collection::vec, prelude::*};
9
10use crate::primitives::Groth16Proof;
11
12use super::{
13 keys::{self, ValidatingKey},
14 note, tree, FieldNotPresent, NoteCommitment, Output, OutputInTransactionV4, PerSpendAnchor,
15 SharedAnchor, Spend,
16};
17
18impl Arbitrary for Spend<PerSpendAnchor> {
19 type Parameters = ();
20
21 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
22 (
23 any::<tree::Root>(),
24 any::<note::Nullifier>(),
25 spendauth_verification_key_bytes(),
26 any::<Groth16Proof>(),
27 vec(any::<u8>(), 64),
28 )
29 .prop_map(|(per_spend_anchor, nullifier, rk, proof, sig_bytes)| Self {
30 per_spend_anchor,
31 cv: ExtendedPoint::generator().try_into().unwrap(),
32 nullifier,
33 rk,
34 zkproof: proof,
35 spend_auth_sig: redjubjub::Signature::from({
36 let mut b = [0u8; 64];
37 b.copy_from_slice(sig_bytes.as_slice());
38 b
39 }),
40 })
41 .boxed()
42 }
43
44 type Strategy = BoxedStrategy<Self>;
45}
46
47impl Arbitrary for Spend<SharedAnchor> {
48 type Parameters = ();
49
50 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
51 (
52 any::<note::Nullifier>(),
53 spendauth_verification_key_bytes(),
54 any::<Groth16Proof>(),
55 vec(any::<u8>(), 64),
56 )
57 .prop_map(|(nullifier, rk, proof, sig_bytes)| Self {
58 per_spend_anchor: FieldNotPresent,
59 cv: ExtendedPoint::generator().try_into().unwrap(),
60 nullifier,
61 rk,
62 zkproof: proof,
63 spend_auth_sig: redjubjub::Signature::from({
64 let mut b = [0u8; 64];
65 b.copy_from_slice(sig_bytes.as_slice());
66 b
67 }),
68 })
69 .boxed()
70 }
71
72 type Strategy = BoxedStrategy<Self>;
73}
74
75impl Arbitrary for Output {
76 type Parameters = ();
77
78 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
79 (
80 any::<note::EncryptedNote>(),
81 any::<note::WrappedNoteKey>(),
82 any::<Groth16Proof>(),
83 )
84 .prop_map(|(enc_ciphertext, out_ciphertext, zkproof)| Self {
85 cv: ExtendedPoint::generator().try_into().unwrap(),
86 cm_u: NoteCommitment(AffinePoint::identity()).extract_u(),
87 ephemeral_key: keys::EphemeralPublicKey(ExtendedPoint::generator().into()),
88 enc_ciphertext,
89 out_ciphertext,
90 zkproof,
91 })
92 .boxed()
93 }
94
95 type Strategy = BoxedStrategy<Self>;
96}
97
98impl Arbitrary for OutputInTransactionV4 {
99 type Parameters = ();
100
101 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
102 any::<Output>().prop_map(OutputInTransactionV4).boxed()
103 }
104
105 type Strategy = BoxedStrategy<Self>;
106}
107
108fn spendauth_verification_key_bytes() -> impl Strategy<Value = ValidatingKey> {
111 prop::array::uniform32(any::<u8>()).prop_map(|bytes| {
112 let rng = ChaChaRng::from_seed(bytes);
113 let sk = redjubjub::SigningKey::<redjubjub::SpendAuth>::new(rng);
114 redjubjub::VerificationKey::<redjubjub::SpendAuth>::from(&sk)
115 .try_into()
116 .unwrap()
117 })
118}
119
120fn jubjub_base_strat() -> BoxedStrategy<jubjub::Base> {
121 (vec(any::<u8>(), 64))
122 .prop_map(|bytes| {
123 let bytes = bytes.try_into().expect("vec is the correct length");
124 jubjub::Base::from_bytes_wide(&bytes)
125 })
126 .boxed()
127}
128
129impl Arbitrary for tree::Root {
130 type Parameters = ();
131
132 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
133 jubjub_base_strat().prop_map(tree::Root).boxed()
134 }
135
136 type Strategy = BoxedStrategy<Self>;
137}
138
139impl Arbitrary for tree::Node {
140 type Parameters = ();
141
142 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
143 jubjub_base_strat().prop_map(tree::Node::from).boxed()
144 }
145
146 type Strategy = BoxedStrategy<Self>;
147}