1#[allow(unused_imports)]
2use std_shims::prelude::*;
3use std_shims::io;
4
5#[rustfmt::skip]
6use subtle::{Choice, ConstantTimeEq as _, ConstantTimeLess as _, ConstantTimeGreater as _, ConditionallySelectable as _};
7use zeroize::{Zeroize, ZeroizeOnDrop};
8
9use monero_io::*;
10use monero_ed25519::*;
11
12#[derive(Clone, Zeroize, ZeroizeOnDrop)]
14pub struct Decoys {
15 offsets: Vec<u64>,
16 signer_index: u8,
17 ring: Vec<[Point; 2]>,
18}
19
20impl core::fmt::Debug for Decoys {
21 fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
23 fmt
24 .debug_struct("Decoys")
25 .field("offsets", &self.offsets)
26 .field("ring", &self.ring)
27 .finish_non_exhaustive()
28 }
29}
30
31pub(crate) const MAX_RING_SIZE: u8 = u8::MAX;
38
39#[allow(clippy::len_without_is_empty)]
40impl Decoys {
41 #[doc(hidden)]
45 pub fn ct_eq(&self, other: &Self) -> Choice {
46 let ring = self.ring.len().ct_eq(&other.ring.len()) &
47 self.ring.iter().zip(&other.ring).fold(Choice::from(1u8), |accum, (lhs, rhs)| {
48 accum & lhs.as_slice().ct_eq(rhs.as_slice())
49 });
50 self.offsets.ct_eq(&other.offsets) & self.signer_index.ct_eq(&other.signer_index) & ring
51 }
52
53 pub fn new(offsets: Vec<u64>, signer_index: u8, ring: Vec<[Point; 2]>) -> Option<Self> {
61 #[allow(clippy::as_conversions, clippy::cast_possible_truncation)]
64 let ring_len_does_not_exceed_max =
65 (ring.len() >> 8).ct_eq(&0) & (!(ring.len() as u8).ct_gt(&MAX_RING_SIZE));
66 #[allow(clippy::as_conversions, clippy::cast_possible_truncation)]
68 let signer_index_points_to_ring_member = signer_index.ct_lt(&(ring.len() as u8));
69 let offsets_align_with_ring = offsets.len().ct_eq(&ring.len());
70
71 let mut offsets_representable = Choice::from(1u8);
73 {
74 let mut sum = 0u64;
75 for (i, offset) in offsets.iter().enumerate() {
76 let new_sum = sum.wrapping_add(*offset);
77 if i != 0 {
78 offsets_representable &= new_sum.ct_gt(&sum);
80 }
81 sum = new_sum;
82 }
83 }
84
85 bool::from(
86 ring_len_does_not_exceed_max &
87 signer_index_points_to_ring_member &
88 offsets_align_with_ring &
89 offsets_representable,
90 )
91 .then_some(Decoys { offsets, signer_index, ring })
92 }
93
94 pub fn len(&self) -> usize {
96 self.offsets.len()
97 }
98
99 pub fn offsets(&self) -> &[u64] {
104 &self.offsets
105 }
106
107 pub fn positions(&self) -> Vec<u64> {
111 let mut res = Vec::with_capacity(self.len());
112 res.push(self.offsets[0]);
113 for m in 1 .. self.len() {
114 res.push(res[m - 1] + self.offsets[m]);
115 }
116 res
117 }
118
119 pub fn signer_index(&self) -> u8 {
121 self.signer_index
122 }
123
124 pub fn ring(&self) -> &[[Point; 2]] {
126 &self.ring
127 }
128
129 pub fn signer_ring_members(&self) -> [Point; 2] {
133 let mut result = self.ring[0];
134 for (i, member) in self.ring.iter().enumerate().skip(1) {
135 let select = i.ct_eq(&usize::from(self.signer_index));
136 result[0] = <_>::conditional_select(&result[0], &member[0], select);
137 result[1] = <_>::conditional_select(&result[1], &member[1], select);
138 }
139 result
140 }
141
142 pub fn write(&self, w: &mut impl io::Write) -> io::Result<()> {
147 write_vec(VarInt::write, &self.offsets, w)?;
148 w.write_all(&[self.signer_index])?;
149 write_raw_vec(
150 |pair, w| {
151 pair[0].compress().write(w)?;
152 pair[1].compress().write(w)
153 },
154 &self.ring,
155 w,
156 )
157 }
158
159 pub fn serialize(&self) -> Vec<u8> {
164 let mut res =
165 Vec::with_capacity((1 + (2 * self.offsets.len())) + 1 + 1 + (self.ring.len() * 64));
166 self.write(&mut res).expect("write failed but <Vec as io::Write> doesn't fail");
167 res
168 }
169
170 pub fn read(r: &mut impl io::Read) -> io::Result<Decoys> {
175 let offsets = read_vec(VarInt::read, Some(usize::from(MAX_RING_SIZE)), r)?;
176 let len = offsets.len();
177 Decoys::new(
178 offsets,
179 read_byte(r)?,
180 read_raw_vec(
181 |r| {
182 Ok([
183 CompressedPoint::read(r)?
184 .decompress()
185 .ok_or(io::Error::other("Decoys had invalid key in ring"))?,
186 CompressedPoint::read(r)?
187 .decompress()
188 .ok_or(io::Error::other("Decoys had invalid commitment in ring"))?,
189 ])
190 },
191 len,
192 r,
193 )?,
194 )
195 .ok_or_else(|| io::Error::other("invalid Decoys"))
196 }
197}