1//! Support for the proof-of-work intro payload extension
23#[cfg_attr(not(feature = "hs-pow-full"), path = "pow/v1_stub.rs")]
4pub mod v1;
56use self::v1::ProofOfWorkV1;
7use crate::relaycell::{extend::CircRequestExtType, extlist::Ext};
8use caret::caret_int;
9use tor_bytes::{EncodeResult, Reader, Result, Writer};
1011/// Extension to provide a proof of work for denial of service mitigation
12///
13/// Documented at <https://spec.torproject.org/rend-spec/introduction-protocol.html#INTRO1_POW_EXT>
14///
15/// The extension has a variable format depending on the specific scheme that was chosen.
16///
17#[derive(Debug, Clone, PartialEq)]
18#[non_exhaustive]
19pub enum ProofOfWork {
20/// A potential solution with unrecognized scheme
21Unrecognized(UnrecognizedProofOfWork),
22/// A potential solution using the `v1` scheme
23V1(v1::ProofOfWorkV1),
24}
2526impl Ext for ProofOfWork {
27type Id = CircRequestExtType;
2829fn type_id(&self) -> CircRequestExtType {
30 CircRequestExtType::PROOF_OF_WORK
31 }
3233fn take_body_from(b: &mut Reader<'_>) -> Result<Self> {
34let scheme = b.take_u8()?;
35if let Some(v1) = ProofOfWorkV1::try_take_body_from(scheme, b)? {
36return Ok(ProofOfWork::V1(v1));
37 }
38Ok(ProofOfWork::Unrecognized(
39 UnrecognizedProofOfWork::take_body_from(scheme, b),
40 ))
41 }
4243fn write_body_onto<B: Writer + ?Sized>(&self, b: &mut B) -> EncodeResult<()> {
44match self {
45 ProofOfWork::V1(v1) => v1.write_onto(b),
46 ProofOfWork::Unrecognized(unrecognized) => {
47 unrecognized.write_onto(b);
48Ok(())
49 }
50 }
51 }
52}
5354caret_int! {
55/// Recognized numeric codes for the scheme-specific [`ProofOfWork`] formats
56#[non_exhaustive]
57pub struct ProofOfWorkType(u8) {
58/// Solution for the `v1` scheme
59V1 = 1,
60 }
61}
6263/// A proof of work with unknown scheme
64///
65/// The reader needs a way to represent future schemes when we can't fail to parse.
66/// This is similar to [`super::UnrecognizedExt`], but specific to an unrecognized scheme
67/// within a known type of extension.
68///
69#[derive(Debug, Clone, Eq, PartialEq, amplify::Getters, derive_more::Constructor)]
70pub struct UnrecognizedProofOfWork {
71/// The `scheme` byte
72 ///
73 /// Intended usage is that this won't be any of the known `ProofOfWorkType`
74 /// values. We don't strictly verify this, to avoid breaking the API every
75 /// time a new type is added.
76 ///
77#[getter(as_copy)]
78scheme: u8,
79/// Arbitrary contents with an unknown format
80#[getter(as_ref)]
81data: Vec<u8>,
82}
8384impl UnrecognizedProofOfWork {
85/// Construct by taking the remaining scheme-specific unknown data
86pub(super) fn take_body_from(scheme: u8, b: &mut Reader<'_>) -> Self {
87Self::new(scheme, b.take_rest().to_vec())
88 }
8990/// Write the unrecognized proof's scheme and data
91pub(super) fn write_onto<B: Writer + ?Sized>(&self, b: &mut B) {
92 b.write_u8(self.scheme());
93 b.write_all(self.data());
94 }
95}