oxedyne/fe2o3/fe2o3_shield/src/srv/msg/packet.rs
22.7 KiB, 107 runs
created by r1870400018:884, which is this file's identity for as long as the history lasts, whatever it is later renamed to
download · who wrote it · its history
| 1 | use crate::{ |
| 2 | srv::{ |
| 3 | constant, |
| 4 | msg::{ |
| 5 | app::AppMsgKind, |
| 6 | core::MsgType, |
| 7 | handshake::HandshakeType, |
| 8 | }, |
| 9 | }, |
| 10 | }; |
| 11 | |
| 12 | use oxedyne_fe2o3_core::{ |
| 13 | prelude::*, |
| 14 | byte::{ |
| 15 | FromBytes, |
| 16 | ToBytes, |
| 17 | }, |
| 18 | }; |
| 19 | use oxedyne_fe2o3_iop_crypto::sign::Signer; |
| 20 | use oxedyne_fe2o3_jdat::{ |
| 21 | id::NumIdDat, |
| 22 | version::SemVer, |
| 23 | }; |
| 24 | use oxedyne_fe2o3_hash::{ |
| 25 | pow::{ |
| 26 | PowCreateParams, |
| 27 | PowSearchResult, |
| 28 | PowVars, |
| 29 | Pristine, |
| 30 | ProofOfWork, |
| 31 | }, |
| 32 | }; |
| 33 | use oxedyne_fe2o3_iop_hash::api::Hasher; |
| 34 | use oxedyne_fe2o3_namex::id::LocalId; |
| 35 | |
| 36 | use std::{ |
| 37 | convert::TryFrom, |
| 38 | ops::Range, |
| 39 | }; |
| 40 | |
| 41 | pub type PacketCount = u32; |
| 42 | pub const PACKET_COUNT_BYTE_LEN: usize = 4; |
| 43 | |
| 44 | /// A more economical form of `oxedyne_fe2o3_jdat::chunk::ChunkState`. |
| 45 | #[derive(Clone, Debug, Default)] |
| 46 | pub struct PacketChunkState { |
| 47 | pub index: PacketCount, |
| 48 | pub num_chunks: PacketCount, |
| 49 | pub chunk_size: u16, |
| 50 | pub pad_last: bool, |
| 51 | } |
| 52 | |
| 53 | impl ToBytes for PacketChunkState { |
| 54 | fn to_bytes(&self, mut buf: Vec<u8>) -> Outcome<Vec<u8>> { |
| 55 | buf.extend_from_slice(&self.index.to_be_bytes()); |
| 56 | buf.extend_from_slice(&self.num_chunks.to_be_bytes()); |
| 57 | buf.extend_from_slice(&self.chunk_size.to_be_bytes()); |
| 58 | buf.push(if self.pad_last { 1 } else { 0 }); |
| 59 | Ok(buf) |
| 60 | } |
| 61 | } |
| 62 | |
| 63 | impl FromBytes for PacketChunkState { |
| 64 | fn from_bytes(buf: &[u8]) -> Outcome<(Self, usize)> { |
| 65 | let mut result = Self::default(); |
| 66 | if buf.len() < Self::BYTE_LEN { |
| 67 | return Err(err!( |
| 68 | "Not enough bytes to decode, require at least {}, found only {}.", |
| 69 | Self::BYTE_LEN, buf.len(); |
| 70 | Bytes, Input, Decode, Missing)); |
| 71 | } |
| 72 | let mut n: usize = 0; |
| 73 | result.index = PacketCount::from_be_bytes(res!( |
| 74 | <[u8; PACKET_COUNT_BYTE_LEN]>::try_from(&buf[n..n + PACKET_COUNT_BYTE_LEN]), |
| 75 | Decode, Bytes)); |
| 76 | n += PACKET_COUNT_BYTE_LEN; |
| 77 | |
| 78 | result.num_chunks = PacketCount::from_be_bytes(res!( |
| 79 | <[u8; PACKET_COUNT_BYTE_LEN]>::try_from( |
| 80 | &buf[n..n + PACKET_COUNT_BYTE_LEN] |
| 81 | ), Decode, Bytes)); |
| 82 | n += PACKET_COUNT_BYTE_LEN; |
| 83 | |
| 84 | result.chunk_size = u16::from_be_bytes(res!( |
| 85 | <[u8; 2]>::try_from( |
| 86 | &buf[n..n + 2] |
| 87 | ), Decode, Bytes)); |
| 88 | n += 2; |
| 89 | |
| 90 | result.pad_last = match u8::from_be_bytes(res!( |
| 91 | <[u8; 1]>::try_from( |
| 92 | &buf[n..n + 1] |
| 93 | ), Decode, Bytes)) { |
| 94 | 0 => false, |
| 95 | _ => true, |
| 96 | }; |
| 97 | n += 1; |
| 98 | |
| 99 | Ok((result, n)) |
| 100 | } |
| 101 | } |
| 102 | |
| 103 | impl PacketChunkState { |
| 104 | pub const BYTE_LEN: usize = 2 * PACKET_COUNT_BYTE_LEN + 2 + 1; |
| 105 | } |
| 106 | |
| 107 | #[derive(Clone, Debug)] |
| 108 | pub struct PacketMeta< |
| 109 | const MIDL: usize, |
| 110 | const UIDL: usize, |
| 111 | MID: NumIdDat<MIDL>, |
| 112 | UID: NumIdDat<UIDL>, |
| 113 | > { |
| 114 | pub typ: MsgType, |
| 115 | pub ver: SemVer, |
| 116 | pub mid: MID, |
| 117 | pub uid: UID, |
| 118 | pub chnk: PacketChunkState, |
| 119 | } |
| 120 | |
| 121 | impl< |
| 122 | const MIDL: usize, |
| 123 | const UIDL: usize, |
| 124 | MID: NumIdDat<MIDL>, |
| 125 | UID: NumIdDat<UIDL>, |
| 126 | > |
| 127 | Default for PacketMeta<MIDL, UIDL, MID, UID> |
| 128 | { |
| 129 | fn default() -> Self { |
| 130 | Self { |
| 131 | typ: 0, |
| 132 | ver: SemVer::default(), |
| 133 | mid: MID::default(), |
| 134 | uid: UID::default(), |
| 135 | chnk: PacketChunkState::default(), |
| 136 | } |
| 137 | } |
| 138 | } |
| 139 | |
| 140 | /// ```ignore |
| 141 | /// |
| 142 | /// Byte map: |
| 143 | /// |
| 144 | /// □□ □□□ □□□□□□□□ □□□□□□□□□□□□□□□□ □□□□ □□□□ □□ □□□□□□□□ |
| 145 | /// | | mid uid | | | tstamp |
| 146 | /// typ | index | chunk_ |
| 147 | /// ver+ | size |
| 148 | /// num_ |
| 149 | /// chunks |
| 150 | /// \___________/ |
| 151 | /// | |
| 152 | /// chunk state |
| 153 | /// ``` |
| 154 | impl< |
| 155 | const MIDL: usize, |
| 156 | const UIDL: usize, |
| 157 | MID: NumIdDat<MIDL>, |
| 158 | UID: NumIdDat<UIDL>, |
| 159 | > |
| 160 | ToBytes for PacketMeta<MIDL, UIDL, MID, UID> |
| 161 | { |
| 162 | fn to_bytes(&self, mut buf: Vec<u8>) -> Outcome<Vec<u8>> { |
| 163 | buf.extend_from_slice(&self.typ.to_be_bytes()); |
| 164 | buf = res!(self.ver.to_bytes(buf)); |
| 165 | buf = res!(self.mid.to_bytes(buf)); |
| 166 | buf = res!(self.uid.to_bytes(buf)); |
| 167 | buf = res!(self.chnk.to_bytes(buf)); |
| 168 | //buf.extend_from_slice(&self.tstamp.to_be_bytes()); |
| 169 | Ok(buf) |
| 170 | } |
| 171 | } |
| 172 | |
| 173 | impl< |
| 174 | const MIDL: usize, |
| 175 | const UIDL: usize, |
| 176 | MID: NumIdDat<MIDL>, |
| 177 | UID: NumIdDat<UIDL>, |
| 178 | > |
| 179 | FromBytes for PacketMeta<MIDL, UIDL, MID, UID> |
| 180 | { |
| 181 | fn from_bytes(buf: &[u8]) -> Outcome<(Self, usize)> { |
| 182 | let mut result = Self::default(); |
| 183 | if buf.len() < Self::BYTE_LEN { |
| 184 | return Err(err!( |
| 185 | "Not enough bytes to decode, require at least {}, found only {}.", |
| 186 | Self::BYTE_LEN, buf.len(); |
| 187 | Bytes, Input, Decode, Missing)); |
| 188 | } |
| 189 | |
| 190 | let mut n = constant::MSG_TYPE_BYTE_LEN; |
| 191 | result.typ = MsgType::from_be_bytes(res!( |
| 192 | <[u8; constant::MSG_TYPE_BYTE_LEN]>::try_from(&buf[0..n]), |
| 193 | Decode, Bytes) |
| 194 | ); |
| 195 | |
| 196 | let (ver, n2) = res!(SemVer::from_bytes(&buf[n..])); |
| 197 | result.ver = ver; |
| 198 | n += n2; |
| 199 | |
| 200 | let (mid, n_mid) = res!(MID::from_bytes(&buf[n..])); |
| 201 | result.mid = mid; |
| 202 | n += n_mid; |
| 203 | |
| 204 | let (uid, n_uid) = res!(UID::from_bytes(&buf[n..])); |
| 205 | result.uid = uid; |
| 206 | n += n_uid; |
| 207 | |
| 208 | let (chnk, n0) = res!(PacketChunkState::from_bytes(&buf[n..])); |
| 209 | result.chnk = chnk; |
| 210 | n += n0; |
| 211 | |
| 212 | Ok((result, n)) |
| 213 | } |
| 214 | } |
| 215 | |
| 216 | impl< |
| 217 | const MIDL: usize, |
| 218 | const UIDL: usize, |
| 219 | MID: NumIdDat<MIDL>, |
| 220 | UID: NumIdDat<UIDL>, |
| 221 | > |
| 222 | PacketMeta<MIDL, UIDL, MID, UID> |
| 223 | { |
| 224 | pub const BYTE_LEN: usize = |
| 225 | constant::MSG_TYPE_BYTE_LEN + // message type |
| 226 | SemVer::BYTE_LEN + |
| 227 | MIDL + |
| 228 | UIDL + |
| 229 | PacketChunkState::BYTE_LEN;// + |
| 230 | //8; // time since Unix epoch in seconds |
| 231 | } |
| 232 | |
| 233 | #[repr(u8)] |
| 234 | pub enum PacketValidatorId { |
| 235 | Pow = 1, |
| 236 | BareSignature = 2, |
| 237 | SignatureWithKey = 3, |
| 238 | } |
| 239 | |
| 240 | impl TryFrom<u8> for PacketValidatorId { |
| 241 | type Error = Error<ErrTag>; |
| 242 | fn try_from(n: u8) -> std::result::Result<Self, Self::Error> { |
| 243 | match n { |
| 244 | 1 => Ok(Self::Pow), |
| 245 | 2 => Ok(Self::BareSignature), |
| 246 | 3 => Ok(Self::SignatureWithKey), |
| 247 | _ => Err(err!( |
| 248 | "Number {} not recognised as a PacketValidatorId.", n; |
| 249 | Input, Invalid)), |
| 250 | } |
| 251 | } |
| 252 | } |
| 253 | |
| 254 | /// Contains the optional ranges for the validation artefacts in a byte slice, including: |
| 255 | /// - Proof of work artefact p0..p1, |
| 256 | /// - Signature artefact s0..s1 and s2..s3, s4..s5 when the public key is included. |
| 257 | #[derive(Default)] |
| 258 | pub struct PacketValidationArtefactRelativeIndices { |
| 259 | pub pow: Option<Range<usize>>, |
| 260 | pub sig: Option<(Range<usize>, Option<(Range<usize>, Range<usize>)>)>, |
| 261 | } |
| 262 | |
| 263 | ///```ignore |
| 264 | /// |
| 265 | /// Case of no public key with (bare) signature: |
| 266 | /// |
| 267 | /// u16 len u16 len |
| 268 | /// | | signature |
| 269 | /// --+ --+ / artefact |
| 270 | /// □□□ □□□□□□□□□□□□□□□□□□□□□□□□ □□□ □□□□□□□□ |
| 271 | /// | | | | | | | |
| 272 | /// id | pow artefact | id | | |
| 273 | /// | p0 p1 s0 s1 |
| 274 | /// n=0 |
| 275 | /// |
| 276 | /// Case of public key with signature: |
| 277 | /// |
| 278 | /// u16 len u16 len u16 len |
| 279 | /// u16 len artefact pub key signature |
| 280 | /// | | | | |
| 281 | /// --+ +-- --+ --+ |
| 282 | /// □□□ □□□□□□□□□□□□□□□□□□□□□□□□ □□□ □□ □□□□□□ □□ □□□□□□□□ |
| 283 | /// | | | | | | | | | | | | |
| 284 | /// id | pow artefact | id | | | | | | | |
| 285 | /// p0 p1 s0 s2 | s3 s4 | s1,s5 |
| 286 | /// | | |
| 287 | /// signature signature |
| 288 | /// public key |
| 289 | ///``` |
| 290 | impl FromBytes for PacketValidationArtefactRelativeIndices { |
| 291 | fn from_bytes(buf: &[u8]) -> Outcome<(Self, usize)> { |
| 292 | let mut result = Self::default(); |
| 293 | let mut n: usize = 0; |
| 294 | match PacketValidatorId::try_from(buf[n] as u8) { |
| 295 | Ok(PacketValidatorId::Pow) => { |
| 296 | n += 1; |
| 297 | let (len, ns) = res!(Self::read_size(&buf, n)); |
| 298 | n += ns; |
| 299 | result.pow = Some(n..n + len); |
| 300 | n += len; |
| 301 | }, |
| 302 | _ => result.pow = None, |
| 303 | } |
| 304 | match PacketValidatorId::try_from(buf[n] as u8) { |
| 305 | Ok(pvid) => { |
| 306 | match pvid { |
| 307 | PacketValidatorId::BareSignature | PacketValidatorId::SignatureWithKey => { |
| 308 | // Get the overall artefact range. |
| 309 | n += 1; |
| 310 | let (len, ns) = res!(Self::read_size(&buf, n)); |
| 311 | n += ns; |
| 312 | let sigval_rng = n..n + len; |
| 313 | //result.sig = Some(n..n + len); |
| 314 | let withkey_ranges = if let PacketValidatorId::SignatureWithKey = pvid { |
| 315 | // Get the ranges for the key and the signature. |
| 316 | let (pk_len, ns) = res!(Self::read_size(&buf, n)); |
| 317 | n += ns; |
| 318 | let pk_rng = n..n + pk_len; |
| 319 | n += pk_len; |
| 320 | let (sig_len, ns) = res!(Self::read_size(&buf, n)); |
| 321 | n += ns; |
| 322 | let sig_rng = n..n + sig_len; |
| 323 | n += sig_len; |
| 324 | if sigval_rng.end != sig_rng.end { |
| 325 | return Err(err!( |
| 326 | "The end point of the overall relative signature artefact range, \ |
| 327 | {:?}, should match the end point of the relative range of the actual \ |
| 328 | signature, {:?}, when the public key (range {:?}) is included.", |
| 329 | sigval_rng, sig_rng, pk_rng; |
| 330 | Bug, Index, Mismatch)); |
| 331 | } |
| 332 | Some((pk_rng, sig_rng)) |
| 333 | } else { |
| 334 | n += len; |
| 335 | None |
| 336 | }; |
| 337 | result.sig = Some((sigval_rng, withkey_ranges)); |
| 338 | }, |
| 339 | _ => result.sig = None, |
| 340 | } |
| 341 | }, |
| 342 | _ => result.sig = None, |
| 343 | } |
| 344 | Ok((result, n)) |
| 345 | } |
| 346 | } |
| 347 | |
| 348 | impl PacketValidationArtefactRelativeIndices { |
| 349 | |
| 350 | pub const BYTE_PREFIX_LEN: usize = 1 + 2; |
| 351 | |
| 352 | fn read_size(buf: &[u8], n: usize) -> Outcome<(usize, usize)> { |
| 353 | Ok(( |
| 354 | u16::from_be_bytes(res!(<[u8; 2]>::try_from(&buf[n..n+2]), |
| 355 | Decode, Bytes)) as usize, |
| 356 | 2, |
| 357 | )) |
| 358 | } |
| 359 | } |
| 360 | |
| 361 | /// Contains the algorithmic schemes for shield packet validation. |
| 362 | #[derive(Clone, Debug, Default)] |
| 363 | pub struct PacketValidator< |
| 364 | // Proof of work validation. |
| 365 | H: Hasher, // Proof of work hasher. |
| 366 | // Digital signature validation. |
| 367 | S: Signer, |
| 368 | > { |
| 369 | //pub pow: Option<(ProofOfWork<H>, Option<PowParams<P0, P1, PRIS>>)>, |
| 370 | pub pow: Option<ProofOfWork<H>>, |
| 371 | pub sig: Option<S>, |
| 372 | } |
| 373 | |
| 374 | impl< |
| 375 | // Proof of work validator. |
| 376 | H: Hasher + Send + 'static, // Proof of work hasher. |
| 377 | // Digital signature validation. |
| 378 | S: Signer, |
| 379 | > |
| 380 | PacketValidator<H, S> |
| 381 | { |
| 382 | pub fn to_bytes< |
| 383 | const N: usize, // Pristine + Nonce size. |
| 384 | const P0: usize, // Length of pristine prefix bytes (i.e. not included in artefact). |
| 385 | const P1: usize, // Length of pristine bytes (i.e. included in artefact). |
| 386 | PRIS: Pristine<P0, P1>, // Pristine supplied to hasher. |
| 387 | >( |
| 388 | &self, |
| 389 | mut buf: Vec<u8>, |
| 390 | powparams: &PowCreateParams<P0, P1, PRIS>, |
| 391 | inc_sigpk: bool, |
| 392 | ) |
| 393 | -> Outcome<Vec<u8>> |
| 394 | { |
| 395 | if let Some(power) = &self.pow { |
| 396 | match power.create::<N, P0, P1, PRIS>(powparams) { |
| 397 | Ok(PowSearchResult{ |
| 398 | found, |
| 399 | mut artefact, |
| 400 | elapsed, |
| 401 | err, |
| 402 | .. |
| 403 | }) => { |
| 404 | if let Some(e) = err { |
| 405 | return Err(e); |
| 406 | } |
| 407 | if !found { |
| 408 | return Err(err!( |
| 409 | "Proof of work validator: search timed out after {:?}.", |
| 410 | elapsed; |
| 411 | Timeout, Missing)); |
| 412 | } |
| 413 | |
| 414 | /////// Debugging only. |
| 415 | trace!(async_log::stream(), "POW tx:"); |
| 416 | res!(self.trace( |
| 417 | Some(&powparams.pvars), |
| 418 | &artefact, |
| 419 | )); |
| 420 | /////// |
| 421 | |
| 422 | buf.extend_from_slice(&(PacketValidatorId::Pow as u8).to_be_bytes()); |
| 423 | buf.extend_from_slice(&(artefact.len() as u16).to_be_bytes()); |
| 424 | buf.append(&mut artefact); |
| 425 | }, |
| 426 | Err(e) => return Err(e), |
| 427 | } |
| 428 | } |
| 429 | if let Some(signer) = &self.sig { |
| 430 | match inc_sigpk { |
| 431 | true => { |
| 432 | let mut sig = res!(signer.sign(&buf)); |
| 433 | let pk = match res!(signer.get_public_key()) { |
| 434 | Some(k) => k, |
| 435 | None => return Err(err!( |
| 436 | "Signature validator: public key not available."; |
| 437 | Bug, Configuration, Missing)), |
| 438 | }; |
| 439 | let mut artefact = Vec::new(); |
| 440 | artefact.extend_from_slice(&(pk.len() as u16).to_be_bytes()); |
| 441 | artefact.extend_from_slice(&pk[..]); // Key first.. |
| 442 | artefact.extend_from_slice(&(sig.len() as u16).to_be_bytes()); |
| 443 | artefact.append(&mut sig); // then signature |
| 444 | |
| 445 | buf.extend_from_slice(&(PacketValidatorId::SignatureWithKey as u8).to_be_bytes()); |
| 446 | buf.extend_from_slice(&(artefact.len() as u16).to_be_bytes()); |
| 447 | buf.append(&mut artefact); |
| 448 | }, |
| 449 | false => { |
| 450 | let mut artefact = res!(signer.sign(&buf)); |
| 451 | buf.extend_from_slice(&(PacketValidatorId::BareSignature as u8).to_be_bytes()); |
| 452 | buf.extend_from_slice(&(artefact.len() as u16).to_be_bytes()); |
| 453 | buf.append(&mut artefact); |
| 454 | }, |
| 455 | } |
| 456 | } |
| 457 | Ok(buf) |
| 458 | } |
| 459 | |
| 460 | pub fn may_carry_signing_key(msg_typ: MsgType) -> bool { |
| 461 | if HandshakeType::from(msg_typ) == HandshakeType::Req1 { |
| 462 | return true; |
| 463 | } |
| 464 | AppMsgKind::from_msg_type(msg_typ).is_some() |
| 465 | } |
| 466 | |
| 467 | /// The signature is based on the entire packet up to but not including the signature artefact. |
| 468 | pub fn validate< |
| 469 | const P0: usize, |
| 470 | const P1: usize, |
| 471 | PRIS: Pristine<P0, P1>, |
| 472 | >( |
| 473 | self, |
| 474 | buf: &[u8], // Entire packet. |
| 475 | n0: usize, // Start index of validation artefacts within packet. |
| 476 | afact_rel_ind: PacketValidationArtefactRelativeIndices, |
| 477 | //powvals: Option<([u8; P0], pow::ZeroBits)>, // (pristine prefix, reqd zbits) |
| 478 | powvars: Option<PowVars<P0, P1, PRIS>>, |
| 479 | msg_typ: MsgType, |
| 480 | ) |
| 481 | -> Outcome<PacketValidationResult> |
| 482 | { |
| 483 | let pow = match self.pow { |
| 484 | Some(power) => { |
| 485 | let powvars = res!(powvars.ok_or(err!( |
| 486 | "Proof of work validation missing requirements."; |
| 487 | Bug, Configuration, Missing))); |
| 488 | match afact_rel_ind.pow { |
| 489 | Some(range) => { |
| 490 | Some(res!(power.validate( |
| 491 | &powvars, |
| 492 | &buf[n0 + range.start..n0 + range.end], |
| 493 | ))) |
| 494 | } |
| 495 | None => return Err(err!( |
| 496 | "Proof of work validation missing artefact."; |
| 497 | Bug, Configuration, Missing)), |
| 498 | } |
| 499 | }, |
| 500 | None => None, |
| 501 | }; |
| 502 | let sig = match self.sig { |
| 503 | Some(mut signer) => match afact_rel_ind.sig { |
| 504 | Some((range, None)) => { // range covers only the signature. |
| 505 | let len = range.len() + PacketValidationArtefactRelativeIndices::BYTE_PREFIX_LEN; |
| 506 | Some(( |
| 507 | res!(signer.verify( |
| 508 | &buf[..buf.len() - len], // Sign against everything up to the signature. |
| 509 | &buf[n0 + range.start..n0 + range.end], |
| 510 | )), |
| 511 | None, |
| 512 | )) |
| 513 | }, |
| 514 | Some((range, Some((pk_rng, sig_rng)))) => { // range covers the public key and the signature. |
| 515 | // A packet may carry the key it was signed with only where the |
| 516 | // receiver could not be expected to hold one already: the handshake's |
| 517 | // opening request, and an application payload, which is outside any |
| 518 | // session and so has nothing to have exchanged a key through. |
| 519 | // |
| 520 | // Anywhere else the key is refused, and refused as a *failed* |
| 521 | // signature rather than as no signature at all. Reporting it as |
| 522 | // unchecked let a packet that carried its own key be accepted on its |
| 523 | // proof of work alone, which is to say by anybody willing to spend |
| 524 | // the work. |
| 525 | if !Self::may_carry_signing_key(msg_typ) { |
| 526 | return Ok(PacketValidationResult { |
| 527 | pow, |
| 528 | sig: Some((false, None)), |
| 529 | }); |
| 530 | } |
| 531 | let len = range.len() + PacketValidationArtefactRelativeIndices::BYTE_PREFIX_LEN; |
| 532 | let pk = &buf[n0 + pk_rng.start..n0 + pk_rng.end]; |
| 533 | signer = res!(signer.set_public_key(Some(&pk[..]))); |
| 534 | Some(( |
| 535 | res!(signer.verify( |
| 536 | &buf[..buf.len() - len], // Sign against everything up to the signature. |
| 537 | &buf[n0 + sig_rng.start..n0 + sig_rng.end], |
| 538 | )), |
| 539 | Some((signer.local_id(), pk)), |
| 540 | )) |
| 541 | }, |
| 542 | None => return Err(err!( |
| 543 | "Validator requires a signature but no artefact has been included."; |
| 544 | Bug, Configuration, Missing)), |
| 545 | }, |
| 546 | None => None, |
| 547 | }; |
| 548 | |
| 549 | Ok(PacketValidationResult { |
| 550 | pow, |
| 551 | sig, |
| 552 | }) |
| 553 | } |
| 554 | |
| 555 | pub fn trace< |
| 556 | const P0: usize, |
| 557 | const P1: usize, |
| 558 | PRIS: Pristine<P0, P1>, |
| 559 | >( |
| 560 | &self, |
| 561 | powvars: Option<&PowVars<P0, P1, PRIS>>, |
| 562 | artefact: &[u8], |
| 563 | ) |
| 564 | -> Outcome<()> |
| 565 | { |
| 566 | match &self.pow { |
| 567 | Some(power) => { |
| 568 | match powvars { |
| 569 | Some(powvars) => { |
| 570 | let gnomon = power.hasher.hash_length(); |
| 571 | let hlen = res!(gnomon.required("hash length")); |
| 572 | let alen = artefact.len(); |
| 573 | let nlen = alen - hlen - (P1-P0); |
| 574 | let h_start = alen - hlen; |
| 575 | let n_start = h_start - nlen; |
| 576 | let pristine = res!(powvars.pristine.to_bytes()); |
| 577 | trace!(async_log::stream(), "\nPristine [{:>4}]: {:02x?}\ |
| 578 | \n Prefix [{:>4}]: {:02x?}\ |
| 579 | \nArtefact [{:>4}]: {:02x?}\ |
| 580 | \n Nonce [{:>4}]: {:02x?}\ |
| 581 | \n Hash [{:>4}]: {:02x?}", |
| 582 | P1, pristine, |
| 583 | P0, &pristine[..P0], |
| 584 | alen, artefact, |
| 585 | nlen, &artefact[n_start..h_start], |
| 586 | hlen, &artefact[h_start..], |
| 587 | ); |
| 588 | }, |
| 589 | None => return Err(err!( |
| 590 | "Proof of work validation missing requirements."; |
| 591 | Bug, Configuration, Missing)), |
| 592 | } |
| 593 | }, |
| 594 | None => trace!(async_log::stream(), "No proof of work hasher provided."), |
| 595 | } |
| 596 | Ok(()) |
| 597 | } |
| 598 | } |
| 599 | |
| 600 | #[derive(Debug)] |
| 601 | pub struct PacketValidationResult<'a> { |
| 602 | pow: Option<bool>, |
| 603 | sig: Option<(bool, Option<(LocalId, &'a[u8])>)>, // Public signing key may have been included. |
| 604 | } |
| 605 | |
| 606 | impl<'a> PacketValidationResult<'a> { |
| 607 | /// ```ignore |
| 608 | /// |
| 609 | /// pow |
| 610 | /// +-------+-------+-------+ |
| 611 | /// | T | F | None | |
| 612 | /// +------+-------+-------+-------+ |
| 613 | /// | T | T | F | T | |
| 614 | /// +------+-------+-------+-------+ |
| 615 | /// sig | F | F | F | F | |
| 616 | /// +------+-------+-------+-------+ |
| 617 | /// | None | T | F | None | |
| 618 | /// +------+-------+-------+-------+ |
| 619 | /// |
| 620 | /// ``` |
| 621 | /// Combines the proof-of-work and signature results into an overall |
| 622 | /// verdict, per the truth table above, returning the signer's local id and |
| 623 | /// public key when one was supplied. `None` means no check applied. |
| 624 | pub fn is_valid(self) -> Option<(bool, Option<(LocalId, &'a[u8])>)> { |
| 625 | match self.pow { |
| 626 | Some(pb) => match self.sig { |
| 627 | Some((sb, pk_opt)) => Some((pb && sb, pk_opt)), |
| 628 | None => Some((pb, None)), |
| 629 | }, |
| 630 | None => match self.sig { |
| 631 | Some((sb, pk_opt)) => Some((sb, pk_opt)), |
| 632 | None => None, |
| 633 | }, |
| 634 | } |
| 635 | } |
| 636 | |
| 637 | pub fn pow_invalid(&self) -> bool { |
| 638 | match self.pow { |
| 639 | Some(b) => !b, |
| 640 | None => false, |
| 641 | } |
| 642 | } |
| 643 | |
| 644 | pub fn sig_invalid(&self) -> bool { |
| 645 | match self.sig { |
| 646 | Some((b, _)) => !b, |
| 647 | None => false, |
| 648 | } |
| 649 | } |
| 650 | |
| 651 | pub fn pow_state(&self) -> &'static str { |
| 652 | match self.pow { |
| 653 | Some(true) => "PASS", |
| 654 | Some(false) => "FAIL", |
| 655 | None => "NONE", |
| 656 | } |
| 657 | } |
| 658 | |
| 659 | pub fn sig_state(&self) -> &'static str { |
| 660 | match self.sig { |
| 661 | Some((true, _)) => "PASS", |
| 662 | Some((false, _)) => "FAIL", |
| 663 | None => "NONE", |
| 664 | } |
| 665 | } |
| 666 | |
| 667 | } |