tor_netdoc/doc/hsdesc/pow.rs
1//! Implement parsing for the `pow-params` line within the `HsDescInner` layer
2
3#[cfg_attr(not(feature = "hs-pow-full"), path = "pow/v1_stub.rs")]
4pub mod v1;
5
6use crate::doc::hsdesc::inner::HsInnerKwd;
7use crate::parse::tokenize::Item;
8use crate::{NetdocErrorKind as EK, Result};
9use std::collections::HashSet;
10use std::mem::Discriminant;
11use v1::PowParamsV1;
12
13/// A list of parsed `pow-params` lines, at most one per scheme
14///
15#[derive(Debug, Clone)]
16pub struct PowParamSet(Vec<PowParams>);
17
18impl PowParamSet {
19 /// Reference all parameters as a slice in arbitrary order
20 pub(super) fn slice(&self) -> &[PowParams] {
21 &self.0
22 }
23
24 /// Parse a slice of `pow-params` items
25 ///
26 /// Unrecognized schemes are ignored. Duplicate schemes result in an error.
27 ///
28 pub(super) fn from_items(items: &[Item<'_, HsInnerKwd>]) -> Result<Self> {
29 // Parse each one individually,
30 // verifying each time we don't have a duplicated enum discriminant.
31 let mut inner = Vec::new();
32 let mut schemes_seen: HashSet<Discriminant<PowParams>> = HashSet::new();
33 for item in items {
34 if let Some(parsed) = PowParams::try_from_item(item)? {
35 if schemes_seen.insert(std::mem::discriminant(&parsed)) {
36 // Parsed params with a scheme we haven't seen before
37 inner.push(parsed);
38 } else {
39 return Err(EK::DuplicateToken
40 .with_msg(item.kwd_str().to_owned())
41 .at_pos(item.pos()));
42 }
43 }
44 }
45 Ok(Self(inner))
46 }
47}
48
49/// The contents of a `pow-params` line with any recognized scheme.
50///
51/// These use a text format defined by:
52/// <https://spec.torproject.org/rend-spec/hsdesc-encrypt.html#second-layer-plaintext>
53///
54#[derive(Debug, Clone)]
55#[non_exhaustive]
56pub enum PowParams {
57 /// Parameters for the `v1` scheme
58 ///
59 /// This scheme uses the Equi-X asymmetric puzzle, in an iterated
60 /// construction with Blake2b for effort adjustment. The Tor specification
61 /// describes this puzzle construction and references the underlying
62 /// algorithms:
63 ///
64 /// <https://spec.torproject.org/hspow-spec/v1-equix.html>
65 V1(PowParamsV1),
66}
67
68impl PowParams {
69 /// Parse a single `pow-params` line from an `Item`
70 ///
71 /// If the scheme is recognized, returns a PowParams or a parse error.
72 /// If the scheme is unknown, returns None.
73 /// If the scheme field is missing entirely, returns a parse error.
74 fn try_from_item(item: &Item<'_, HsInnerKwd>) -> Result<Option<Self>> {
75 let scheme = item.required_arg(0)?;
76 if scheme == "v1" {
77 Ok(Some(PowParams::V1(PowParamsV1::from_item(item)?)))
78 } else {
79 Ok(None)
80 }
81 }
82}