1use memuse::DynamicUsage;
2
3use crate::{
4 note::{ExtractedNoteCommitment, Nullifier, Rho, TransmittedNoteCiphertext},
5 primitives::redpallas::{self, SpendAuth},
6 value::ValueCommitment,
7};
8
9#[derive(Debug, Clone)]
14pub struct Action<A> {
15 nf: Nullifier,
17 rk: redpallas::VerificationKey<SpendAuth>,
19 cmx: ExtractedNoteCommitment,
21 encrypted_note: TransmittedNoteCiphertext,
23 cv_net: ValueCommitment,
25 authorization: A,
27}
28
29impl<T> Action<T> {
30 pub fn from_parts(
32 nf: Nullifier,
33 rk: redpallas::VerificationKey<SpendAuth>,
34 cmx: ExtractedNoteCommitment,
35 encrypted_note: TransmittedNoteCiphertext,
36 cv_net: ValueCommitment,
37 authorization: T,
38 ) -> Self {
39 Action {
40 nf,
41 rk,
42 cmx,
43 encrypted_note,
44 cv_net,
45 authorization,
46 }
47 }
48
49 pub fn nullifier(&self) -> &Nullifier {
51 &self.nf
52 }
53
54 pub fn rk(&self) -> &redpallas::VerificationKey<SpendAuth> {
56 &self.rk
57 }
58
59 pub fn cmx(&self) -> &ExtractedNoteCommitment {
61 &self.cmx
62 }
63
64 pub fn encrypted_note(&self) -> &TransmittedNoteCiphertext {
66 &self.encrypted_note
67 }
68
69 pub fn rho(&self) -> Rho {
71 Rho::from_nf_old(self.nf)
72 }
73
74 pub fn cv_net(&self) -> &ValueCommitment {
76 &self.cv_net
77 }
78
79 pub fn authorization(&self) -> &T {
81 &self.authorization
82 }
83
84 pub fn map<U>(self, step: impl FnOnce(T) -> U) -> Action<U> {
86 Action {
87 nf: self.nf,
88 rk: self.rk,
89 cmx: self.cmx,
90 encrypted_note: self.encrypted_note,
91 cv_net: self.cv_net,
92 authorization: step(self.authorization),
93 }
94 }
95
96 pub fn try_map<U, E>(self, step: impl FnOnce(T) -> Result<U, E>) -> Result<Action<U>, E> {
98 Ok(Action {
99 nf: self.nf,
100 rk: self.rk,
101 cmx: self.cmx,
102 encrypted_note: self.encrypted_note,
103 cv_net: self.cv_net,
104 authorization: step(self.authorization)?,
105 })
106 }
107}
108
109impl DynamicUsage for Action<redpallas::Signature<SpendAuth>> {
110 #[inline(always)]
111 fn dynamic_usage(&self) -> usize {
112 0
113 }
114
115 #[inline(always)]
116 fn dynamic_usage_bounds(&self) -> (usize, Option<usize>) {
117 (0, Some(0))
118 }
119}
120
121#[cfg(any(test, feature = "test-dependencies"))]
123#[cfg_attr(docsrs, doc(cfg(feature = "test-dependencies")))]
124pub(crate) mod testing {
125 use rand::{rngs::StdRng, SeedableRng};
126 use reddsa::orchard::SpendAuth;
127
128 use proptest::prelude::*;
129
130 use crate::{
131 note::{
132 commitment::ExtractedNoteCommitment, nullifier::testing::arb_nullifier,
133 testing::arb_note, TransmittedNoteCiphertext,
134 },
135 primitives::redpallas::{
136 self,
137 testing::{arb_spendauth_signing_key, arb_spendauth_verification_key},
138 },
139 value::{NoteValue, ValueCommitTrapdoor, ValueCommitment},
140 };
141
142 use super::Action;
143
144 prop_compose! {
145 pub fn arb_unauthorized_action(spend_value: NoteValue, output_value: NoteValue)(
147 nf in arb_nullifier(),
148 rk in arb_spendauth_verification_key(),
149 note in arb_note(output_value),
150 ) -> Action<()> {
151 let cmx = ExtractedNoteCommitment::from(note.commitment());
152 let cv_net = ValueCommitment::derive(
153 spend_value - output_value,
154 ValueCommitTrapdoor::zero()
155 );
156 let encrypted_note = TransmittedNoteCiphertext {
158 epk_bytes: [0u8; 32],
159 enc_ciphertext: [0u8; 580],
160 out_ciphertext: [0u8; 80]
161 };
162 Action {
163 nf,
164 rk,
165 cmx,
166 encrypted_note,
167 cv_net,
168 authorization: ()
169 }
170 }
171 }
172
173 prop_compose! {
174 pub fn arb_action(spend_value: NoteValue, output_value: NoteValue)(
176 nf in arb_nullifier(),
177 sk in arb_spendauth_signing_key(),
178 note in arb_note(output_value),
179 rng_seed in prop::array::uniform32(prop::num::u8::ANY),
180 fake_sighash in prop::array::uniform32(prop::num::u8::ANY),
181 ) -> Action<redpallas::Signature<SpendAuth>> {
182 let cmx = ExtractedNoteCommitment::from(note.commitment());
183 let cv_net = ValueCommitment::derive(
184 spend_value - output_value,
185 ValueCommitTrapdoor::zero()
186 );
187
188 let encrypted_note = TransmittedNoteCiphertext {
190 epk_bytes: [0u8; 32],
191 enc_ciphertext: [0u8; 580],
192 out_ciphertext: [0u8; 80]
193 };
194
195 let rng = StdRng::from_seed(rng_seed);
196
197 Action {
198 nf,
199 rk: redpallas::VerificationKey::from(&sk),
200 cmx,
201 encrypted_note,
202 cv_net,
203 authorization: sk.sign(rng, &fake_sighash),
204 }
205 }
206 }
207}