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