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}