zebra_chain/sapling/
arbitrary.rs1use group::Group;
4use jubjub::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, Output, OutputInTransactionV4, PerSpendAnchor, SharedAnchor,
15 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().into(),
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().into(),
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().into(),
86 cm_u: sapling_crypto::note::ExtractedNoteCommitment::from_bytes(&[0u8; 32])
87 .unwrap(),
88 ephemeral_key: keys::EphemeralPublicKey(ExtendedPoint::generator().into()),
89 enc_ciphertext,
90 out_ciphertext,
91 zkproof,
92 })
93 .boxed()
94 }
95
96 type Strategy = BoxedStrategy<Self>;
97}
98
99impl Arbitrary for OutputInTransactionV4 {
100 type Parameters = ();
101
102 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
103 any::<Output>().prop_map(OutputInTransactionV4).boxed()
104 }
105
106 type Strategy = BoxedStrategy<Self>;
107}
108
109fn spendauth_verification_key_bytes() -> impl Strategy<Value = ValidatingKey> {
112 prop::array::uniform32(any::<u8>()).prop_map(|bytes| {
113 let rng = ChaChaRng::from_seed(bytes);
114 let sk = redjubjub::SigningKey::<redjubjub::SpendAuth>::new(rng);
115 redjubjub::VerificationKey::<redjubjub::SpendAuth>::from(&sk)
116 .try_into()
117 .unwrap()
118 })
119}
120
121fn jubjub_base_strat() -> BoxedStrategy<jubjub::Base> {
122 (vec(any::<u8>(), 64))
123 .prop_map(|bytes| {
124 let bytes = bytes.try_into().expect("vec is the correct length");
125 jubjub::Base::from_bytes_wide(&bytes)
126 })
127 .boxed()
128}
129
130impl Arbitrary for tree::Root {
131 type Parameters = ();
132
133 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
134 jubjub_base_strat().prop_map(tree::Root).boxed()
135 }
136
137 type Strategy = BoxedStrategy<Self>;
138}
139
140impl Arbitrary for tree::legacy::Node {
141 type Parameters = ();
142
143 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
144 jubjub_base_strat()
145 .prop_map(tree::legacy::Node::from)
146 .boxed()
147 }
148
149 type Strategy = BoxedStrategy<Self>;
150}
151
152impl From<jubjub::Fq> for tree::legacy::Node {
153 fn from(x: jubjub::Fq) -> Self {
154 let node = sapling_crypto::Node::from_bytes(x.to_bytes());
155 if node.is_some().into() {
156 tree::legacy::Node(node.unwrap())
157 } else {
158 sapling_crypto::Node::from_bytes([0; 32]).unwrap().into()
159 }
160 }
161}