1extern crate alloc;
18
19use alloc::{collections::VecDeque, vec::Vec};
20
21use borsh::{BorshDeserialize, BorshSerialize};
22use ruint::aliases::{U160, U256, U64};
23use serde::{Deserialize, Serialize};
24
25#[cfg(feature = "rand")]
26use rand::{
27 distr::{Distribution, StandardUniform},
28 Rng,
29};
30
31use crate::DecodeError;
32
33pub type PovwLogId = U160;
39
40#[derive(
46 Copy,
47 Clone,
48 Debug,
49 Default,
50 Serialize,
51 Deserialize,
52 BorshSerialize,
53 BorshDeserialize,
54 PartialEq,
55 Eq,
56)]
57pub struct PovwJobId {
58 pub log: PovwLogId,
60 pub job: u64,
62}
63
64impl PovwJobId {
65 pub fn nonce(self, segment_index: u32) -> PovwNonce {
67 PovwNonce {
68 log: self.log,
69 job: self.job,
70 segment: segment_index,
71 }
72 }
73
74 pub fn to_bytes(self) -> [u8; U160::BYTES + U64::BYTES] {
76 [
77 self.job.to_le_bytes().as_slice(),
78 self.log.to_le_bytes::<{ U160::BYTES }>().as_slice(),
79 ]
80 .concat()
81 .try_into()
82 .unwrap()
83 }
84
85 pub fn from_bytes(bytes: [u8; U160::BYTES + U64::BYTES]) -> Self {
87 Self {
88 job: u64::from_le_bytes(bytes[..U64::BYTES].try_into().unwrap()),
89 log: U160::from_le_bytes::<{ U160::BYTES }>(bytes[U64::BYTES..].try_into().unwrap()),
90 }
91 }
92}
93
94impl From<(PovwLogId, u64)> for PovwJobId {
95 fn from((log, job): (PovwLogId, u64)) -> Self {
96 Self { log, job }
97 }
98}
99
100impl TryFrom<&[u8]> for PovwJobId {
101 type Error = core::array::TryFromSliceError;
102
103 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
104 Ok(Self::from_bytes(value.try_into()?))
105 }
106}
107
108#[cfg(feature = "rand")]
109impl Distribution<PovwJobId> for StandardUniform {
110 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> PovwJobId {
111 PovwJobId {
112 log: rng.random(),
113 job: rng.random(),
114 }
115 }
116}
117
118#[derive(
124 Copy,
125 Clone,
126 Debug,
127 Default,
128 Serialize,
129 Deserialize,
130 BorshSerialize,
131 BorshDeserialize,
132 PartialEq,
133 Eq,
134)]
135pub struct PovwNonce {
136 pub log: PovwLogId,
138 pub job: u64,
140 pub segment: u32,
142}
143
144impl PovwNonce {
145 pub const ZERO: Self = Self {
147 log: PovwLogId::ZERO,
148 job: 0,
149 segment: 0,
150 };
151
152 pub fn to_bytes(self) -> [u8; U256::BYTES] {
154 <U256 as From<Self>>::from(self).to_le_bytes()
155 }
156
157 pub fn from_bytes(bytes: [u8; U256::BYTES]) -> Self {
159 U256::from_le_bytes::<{ U256::BYTES }>(bytes).into()
160 }
161
162 pub fn to_u256(self) -> U256 {
164 (self.log.to::<U256>() << 96) | (U256::from(self.job) << 32) | U256::from(self.segment)
165 }
166
167 pub fn to_u32s(self) -> [u32; 8] {
169 let mut u32s = bytemuck::cast::<_, [u32; 8]>(self.to_bytes());
170 for x in u32s.iter_mut() {
172 *x = u32::from_le(*x);
173 }
174 u32s
175 }
176
177 pub fn to_u16s(self) -> [u16; 16] {
179 let mut u16s = bytemuck::cast::<_, [u16; 16]>(self.to_bytes());
180 for x in u16s.iter_mut() {
182 *x = u16::from_le(*x);
183 }
184 u16s
185 }
186
187 pub fn from_u16s(mut u16s: [u16; 16]) -> Self {
189 for x in u16s.iter_mut() {
191 *x = u16::from_le(*x);
192 }
193 Self::from_bytes(bytemuck::cast(u16s))
194 }
195
196 pub fn encode_to_seal(&self, buf: &mut Vec<u32>) {
198 buf.extend(self.to_u16s().into_iter().map(u32::from));
199 }
200
201 pub fn decode_from_seal(buf: &mut VecDeque<u32>) -> Result<Self, DecodeError> {
203 if buf.len() < 16 {
204 return Err(DecodeError::EndOfStream);
205 }
206 fn u16_from_u32(x: u32) -> Result<u16, DecodeError> {
207 x.try_into().map_err(|_| DecodeError::OutOfRange)
208 }
209 Ok(Self::from_u16s(
210 buf.drain(..16)
211 .map(u16_from_u32)
212 .collect::<Result<Vec<_>, _>>()?
213 .try_into()
214 .unwrap(),
215 ))
216 }
217}
218
219impl From<PovwNonce> for U256 {
220 fn from(value: PovwNonce) -> Self {
222 value.to_u256()
223 }
224}
225
226impl From<U256> for PovwNonce {
227 fn from(value: U256) -> Self {
231 Self {
232 log: (value >> 96usize).to(),
233 job: ((value >> 32usize) & U256::from(u64::MAX)).to(),
234 segment: (value & U256::from(u32::MAX)).to(),
235 }
236 }
237}
238
239impl TryFrom<&[u8]> for PovwNonce {
240 type Error = core::array::TryFromSliceError;
241
242 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
243 Ok(Self::from_bytes(value.try_into()?))
244 }
245}
246
247impl TryFrom<Vec<u8>> for PovwNonce {
248 type Error = core::array::TryFromSliceError;
249
250 fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
251 value.as_slice().try_into()
252 }
253}
254
255#[cfg(feature = "rand")]
256impl Distribution<PovwNonce> for StandardUniform {
257 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> PovwNonce {
258 PovwNonce {
259 log: rng.random(),
260 job: rng.random(),
261 segment: rng.random(),
262 }
263 }
264}
265
266#[cfg(test)]
267mod tests {
268 use super::{PovwJobId, PovwNonce};
269
270 #[test]
271 fn test_povw_job_id_round_trip() {
272 let original: PovwJobId = rand::random();
273 let bytes = original.to_bytes();
274 let reconstructed = PovwJobId::from_bytes(bytes);
275 assert_eq!(original, reconstructed);
276 }
277
278 #[test]
279 fn test_povw_nonce_bytes_round_trip() {
280 let original: PovwNonce = rand::random();
281 let bytes = original.to_bytes();
282 let reconstructed = PovwNonce::from_bytes(bytes);
283 assert_eq!(original, reconstructed);
284 }
285
286 #[test]
287 fn test_povw_nonce_u16s_round_trip() {
288 let original: PovwNonce = rand::random();
289 let u16s = original.to_u16s();
290 let reconstructed = PovwNonce::from_u16s(u16s);
291 assert_eq!(original, reconstructed);
292 }
293}