zebra_chain/orchard/
arbitrary.rs1use group::{
4 ff::{FromUniformBytes, PrimeField},
5 prime::PrimeCurveAffine,
6};
7use halo2::pasta::pallas;
8use reddsa::{orchard::SpendAuth, Signature, SigningKey, VerificationKey, VerificationKeyBytes};
9
10use proptest::{array, collection::vec, prelude::*};
11
12use super::{
13 keys::*, note, tree, Action, AuthorizedAction, Flags, NoteCommitment, ValueCommitment,
14};
15
16impl Arbitrary for Action {
17 type Parameters = ();
18
19 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
20 (
21 any::<note::Nullifier>(),
22 any::<SpendAuthVerificationKeyBytes>(),
23 any::<note::EncryptedNote>(),
24 any::<note::WrappedNoteKey>(),
25 )
26 .prop_map(|(nullifier, rk, enc_ciphertext, out_ciphertext)| Self {
27 cv: ValueCommitment(pallas::Affine::identity()),
28 nullifier,
29 rk: rk.0,
30 cm_x: NoteCommitment(pallas::Affine::identity()).extract_x(),
31 ephemeral_key: EphemeralPublicKey(pallas::Affine::generator()),
32 enc_ciphertext,
33 out_ciphertext,
34 })
35 .boxed()
36 }
37
38 type Strategy = BoxedStrategy<Self>;
39}
40
41impl Arbitrary for note::Nullifier {
42 type Parameters = ();
43
44 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
45 (vec(any::<u8>(), 64))
46 .prop_map(|bytes| {
47 let bytes = bytes.try_into().expect("vec is the correct length");
48 Self::try_from(pallas::Scalar::from_uniform_bytes(&bytes).to_repr())
49 .expect("a valid generated nullifier")
50 })
51 .boxed()
52 }
53
54 type Strategy = BoxedStrategy<Self>;
55}
56
57impl Arbitrary for AuthorizedAction {
58 type Parameters = ();
59
60 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
61 (any::<Action>(), any::<SpendAuthSignature>())
62 .prop_map(|(action, spend_auth_sig)| Self {
63 action,
64 spend_auth_sig: spend_auth_sig.0,
65 })
66 .boxed()
67 }
68
69 type Strategy = BoxedStrategy<Self>;
70}
71
72#[derive(Copy, Clone, Debug, Eq, PartialEq)]
73struct SpendAuthSignature(pub(crate) Signature<SpendAuth>);
74
75impl Arbitrary for SpendAuthSignature {
76 type Parameters = ();
77
78 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
79 (array::uniform32(any::<u8>()), array::uniform32(any::<u8>()))
80 .prop_map(|(r_bytes, s_bytes)| {
81 let mut bytes = [0; 64];
82 bytes[0..32].copy_from_slice(&r_bytes[..]);
83 bytes[32..64].copy_from_slice(&s_bytes[..]);
84 SpendAuthSignature(Signature::<SpendAuth>::from(bytes))
85 })
86 .boxed()
87 }
88
89 type Strategy = BoxedStrategy<Self>;
90}
91
92#[derive(Copy, Clone, PartialEq, Eq, Debug)]
93struct SpendAuthVerificationKeyBytes(pub(crate) VerificationKeyBytes<SpendAuth>);
94
95impl Arbitrary for SpendAuthVerificationKeyBytes {
96 type Parameters = ();
97
98 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
99 (vec(any::<u8>(), 64))
101 .prop_map(|bytes| {
102 let bytes = bytes.try_into().expect("vec is the correct length");
103 let sk_scalar = pallas::Scalar::from_uniform_bytes(&bytes);
105 let sk_bytes = sk_scalar.to_repr();
107 let sk = SigningKey::try_from(sk_bytes).unwrap();
109 let pk = VerificationKey::<SpendAuth>::from(&sk);
110 SpendAuthVerificationKeyBytes(pk.into())
111 })
112 .boxed()
113 }
114
115 type Strategy = BoxedStrategy<Self>;
116}
117
118impl Arbitrary for Flags {
119 type Parameters = ();
120
121 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
122 let pre_nu6_3 = Self::ENABLE_SPENDS.bits() | Self::ENABLE_OUTPUTS.bits();
127 (any::<u8>())
128 .prop_map(move |bits| Self::from_bits_truncate(bits & pre_nu6_3))
129 .boxed()
130 }
131
132 type Strategy = BoxedStrategy<Self>;
133}
134
135fn pallas_base_strat() -> BoxedStrategy<pallas::Base> {
136 (vec(any::<u8>(), 64))
137 .prop_map(|bytes| {
138 let bytes = bytes.try_into().expect("vec is the correct length");
139 pallas::Base::from_uniform_bytes(&bytes)
140 })
141 .boxed()
142}
143
144impl Arbitrary for tree::Root {
145 type Parameters = ();
146
147 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
148 pallas_base_strat()
149 .prop_map(|base| {
150 Self::try_from(base.to_repr())
151 .expect("a valid generated Orchard note commitment tree root")
152 })
153 .boxed()
154 }
155
156 type Strategy = BoxedStrategy<Self>;
157}
158
159impl Arbitrary for tree::Node {
160 type Parameters = ();
161
162 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
163 pallas_base_strat()
164 .prop_map(|base| {
165 Self::try_from(base.to_repr())
166 .expect("a valid generated Orchard note commitment tree root")
167 })
168 .boxed()
169 }
170
171 type Strategy = BoxedStrategy<Self>;
172}