1use core::ops::BitXor;
2use std_shims::{
3 vec,
4 vec::Vec,
5 io::{self, Read, BufRead, Write},
6};
7
8use zeroize::Zeroize;
9
10use curve25519_dalek::edwards::EdwardsPoint;
11
12use monero_oxide::io::*;
13
14pub(crate) const MAX_TX_EXTRA_PADDING_COUNT: usize = 255;
15const MAX_TX_EXTRA_NONCE_SIZE: usize = 255;
16
17const PAYMENT_ID_MARKER: u8 = 0;
18const ENCRYPTED_PAYMENT_ID_MARKER: u8 = 1;
19pub(crate) const ARBITRARY_DATA_MARKER: u8 = 127;
21
22pub const MAX_ARBITRARY_DATA_SIZE: usize = MAX_TX_EXTRA_NONCE_SIZE - 1;
25
26#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)]
30pub enum PaymentId {
31 Unencrypted([u8; 32]),
33 Encrypted([u8; 8]),
35}
36
37impl BitXor<[u8; 8]> for PaymentId {
38 type Output = PaymentId;
39
40 fn bitxor(self, bytes: [u8; 8]) -> PaymentId {
41 match self {
42 PaymentId::Unencrypted(_) => self,
44 PaymentId::Encrypted(id) => {
45 PaymentId::Encrypted((u64::from_le_bytes(id) ^ u64::from_le_bytes(bytes)).to_le_bytes())
46 }
47 }
48 }
49}
50
51impl PaymentId {
52 pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
54 match self {
55 PaymentId::Unencrypted(id) => {
56 w.write_all(&[PAYMENT_ID_MARKER])?;
57 w.write_all(id)?;
58 }
59 PaymentId::Encrypted(id) => {
60 w.write_all(&[ENCRYPTED_PAYMENT_ID_MARKER])?;
61 w.write_all(id)?;
62 }
63 }
64 Ok(())
65 }
66
67 pub fn serialize(&self) -> Vec<u8> {
69 let mut res = Vec::with_capacity(1 + 8);
70 self.write(&mut res).expect("write failed but <Vec as io::Write> doesn't fail");
71 res
72 }
73
74 pub fn read<R: Read>(r: &mut R) -> io::Result<PaymentId> {
76 Ok(match read_byte(r)? {
77 0 => PaymentId::Unencrypted(read_bytes(r)?),
78 1 => PaymentId::Encrypted(read_bytes(r)?),
79 _ => Err(io::Error::other("unknown payment ID type"))?,
80 })
81 }
82}
83
84#[derive(Clone, PartialEq, Eq, Debug, Zeroize)]
86pub enum ExtraField {
87 Padding(usize),
91 PublicKey(EdwardsPoint),
95 Nonce(Vec<u8>),
99 MergeMining(u64, [u8; 32]),
104 PublicKeys(Vec<EdwardsPoint>),
108 MysteriousMinergate(Vec<u8>),
113}
114
115impl ExtraField {
116 pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
118 match self {
119 ExtraField::Padding(size) => {
120 w.write_all(&[0])?;
121 for _ in 1 .. *size {
122 write_byte(&0u8, w)?;
123 }
124 }
125 ExtraField::PublicKey(key) => {
126 w.write_all(&[1])?;
127 w.write_all(&key.compress().to_bytes())?;
128 }
129 ExtraField::Nonce(data) => {
130 w.write_all(&[2])?;
131 write_vec(write_byte, data, w)?;
132 }
133 ExtraField::MergeMining(height, merkle) => {
134 w.write_all(&[3])?;
135 write_varint(height, w)?;
136 w.write_all(merkle)?;
137 }
138 ExtraField::PublicKeys(keys) => {
139 w.write_all(&[4])?;
140 write_vec(write_point, keys, w)?;
141 }
142 ExtraField::MysteriousMinergate(data) => {
143 w.write_all(&[0xDE])?;
144 write_vec(write_byte, data, w)?;
145 }
146 }
147 Ok(())
148 }
149
150 pub fn serialize(&self) -> Vec<u8> {
152 let mut res = Vec::with_capacity(1 + 8);
153 self.write(&mut res).expect("write failed but <Vec as io::Write> doesn't fail");
154 res
155 }
156
157 pub fn read<R: BufRead>(r: &mut R) -> io::Result<ExtraField> {
159 Ok(match read_byte(r)? {
160 0 => ExtraField::Padding({
161 let mut size: usize = 1;
163 loop {
164 let buf = r.fill_buf()?;
165 let mut n_consume = 0;
166 for v in buf {
167 if *v != 0u8 {
168 Err(io::Error::other("non-zero value after padding"))?
169 }
170 n_consume += 1;
171 size += 1;
172 if size > MAX_TX_EXTRA_PADDING_COUNT {
173 Err(io::Error::other("padding exceeded max count"))?
174 }
175 }
176 if n_consume == 0 {
177 break;
178 }
179 r.consume(n_consume);
180 }
181 size
182 }),
183 1 => ExtraField::PublicKey(read_point(r)?),
184 2 => ExtraField::Nonce(read_vec(read_byte, Some(MAX_TX_EXTRA_NONCE_SIZE), r)?),
185 3 => ExtraField::MergeMining(read_varint(r)?, read_bytes(r)?),
186 4 => ExtraField::PublicKeys(read_vec(read_point, None, r)?),
187 0xDE => ExtraField::MysteriousMinergate(read_vec(read_byte, None, r)?),
188 _ => Err(io::Error::other("unknown extra field"))?,
189 })
190 }
191}
192
193#[derive(Clone, PartialEq, Eq, Debug, Zeroize)]
195pub struct Extra(pub(crate) Vec<ExtraField>);
196impl Extra {
197 pub fn keys(&self) -> Option<(Vec<EdwardsPoint>, Option<Vec<EdwardsPoint>>)> {
206 let mut keys = vec![];
207 let mut additional = None;
208 for field in &self.0 {
209 match field.clone() {
210 ExtraField::PublicKey(this_key) => keys.push(this_key),
211 ExtraField::PublicKeys(these_additional) => {
212 additional = additional.or(Some(these_additional))
213 }
214 _ => (),
215 }
216 }
217 if keys.is_empty() {
219 None
220 } else {
221 Some((keys, additional))
222 }
223 }
224
225 pub fn payment_id(&self) -> Option<PaymentId> {
230 for field in &self.0 {
231 if let ExtraField::Nonce(data) = field {
232 return PaymentId::read::<&[u8]>(&mut data.as_ref()).ok();
233 }
234 }
235 None
236 }
237
238 pub fn data(&self) -> Vec<Vec<u8>> {
242 let mut res = vec![];
243 for field in &self.0 {
244 if let ExtraField::Nonce(data) = field {
245 if data[0] == ARBITRARY_DATA_MARKER {
246 res.push(data[1 ..].to_vec());
247 }
248 }
249 }
250 res
251 }
252
253 pub(crate) fn new(key: EdwardsPoint, additional: Vec<EdwardsPoint>) -> Extra {
254 let mut res = Extra(Vec::with_capacity(3));
255 res.0.push(ExtraField::PublicKey(key));
259 if !additional.is_empty() {
260 res.0.push(ExtraField::PublicKeys(additional));
261 }
262 res
263 }
264
265 pub(crate) fn push_nonce(&mut self, nonce: Vec<u8>) {
266 self.0.push(ExtraField::Nonce(nonce));
267 }
268
269 pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
274 for field in &self.0 {
275 field.write(w)?;
276 }
277 Ok(())
278 }
279
280 pub fn serialize(&self) -> Vec<u8> {
282 let mut buf = vec![];
283 self.write(&mut buf).expect("write failed but <Vec as io::Write> doesn't fail");
284 buf
285 }
286
287 #[allow(clippy::unnecessary_wraps)]
292 pub fn read<R: BufRead>(r: &mut R) -> io::Result<Extra> {
293 let mut res = Extra(vec![]);
294 while !r.fill_buf()?.is_empty() {
299 let Ok(field) = ExtraField::read(r) else { break };
300 res.0.push(field);
301 }
302 Ok(res)
303 }
304}