oasis_runtime_sdk/crypto/signature/
digests.rs

1/// A digest that either passes through calls to an actual digest or returns
2/// pre-existing hash bytes..
3///
4/// For signing implementations that require a pre-filled digest instance to
5/// sign instead of plain digest bytes, construct an instance of `DummyDigest`
6/// with the bytes of the hash. The instance will return these bytes when
7/// finalized. It will panic if an attempt is made to update its state.
8///
9/// If it was initialized empty, it will pass all calls through to the actual
10/// digest function, useful for signers that do further internal hashing when
11/// signing.
12pub(crate) struct DummyDigest<D> {
13    underlying: Option<D>,
14    preexisting: Vec<u8>,
15}
16
17impl<D> DummyDigest<D> {
18    pub(crate) fn new_precomputed(bytes: &[u8]) -> Self {
19        Self {
20            underlying: None,
21            preexisting: bytes.to_vec(),
22        }
23    }
24}
25
26impl<D> Default for DummyDigest<D>
27where
28    D: Default,
29{
30    fn default() -> Self {
31        Self {
32            underlying: Some(D::default()),
33            preexisting: Vec::new(),
34        }
35    }
36}
37
38impl<D> Clone for DummyDigest<D>
39where
40    D: Clone,
41{
42    fn clone(&self) -> Self {
43        Self {
44            underlying: self.underlying.clone(),
45            preexisting: self.preexisting.clone(),
46        }
47    }
48}
49
50impl<D> digest::OutputSizeUser for DummyDigest<D>
51where
52    D: digest::OutputSizeUser,
53{
54    type OutputSize = <D as digest::OutputSizeUser>::OutputSize;
55}
56
57impl<D> digest::core_api::BlockSizeUser for DummyDigest<D>
58where
59    D: digest::core_api::BlockSizeUser,
60{
61    type BlockSize = <D as digest::core_api::BlockSizeUser>::BlockSize;
62}
63
64impl<D> digest::FixedOutput for DummyDigest<D>
65where
66    D: digest::FixedOutput,
67{
68    fn finalize_into(self, out: &mut digest::Output<Self>) {
69        if let Some(digest) = self.underlying {
70            digest.finalize_into(out);
71        } else {
72            out.as_mut_slice().copy_from_slice(&self.preexisting);
73        }
74    }
75}
76
77impl<D> digest::FixedOutputReset for DummyDigest<D>
78where
79    D: digest::FixedOutputReset,
80{
81    fn finalize_into_reset(&mut self, out: &mut digest::Output<Self>) {
82        if let Some(digest) = &mut self.underlying {
83            digest.finalize_into_reset(out);
84        } else {
85            out.as_mut_slice().copy_from_slice(&self.preexisting);
86        }
87    }
88}
89
90impl<D> digest::Reset for DummyDigest<D>
91where
92    D: digest::Reset,
93{
94    fn reset(&mut self) {
95        if let Some(ref mut digest) = self.underlying {
96            digest.reset();
97        } else {
98            panic!("mutating dummy digest with precomputed hash");
99        }
100    }
101}
102
103impl<D> digest::Update for DummyDigest<D>
104where
105    D: digest::Update,
106{
107    fn update(&mut self, data: &[u8]) {
108        if let Some(ref mut digest) = self.underlying {
109            digest.update(data);
110        } else {
111            panic!("mutating dummy digest with precomputed hash");
112        }
113    }
114}
115
116impl<D> digest::HashMarker for DummyDigest<D> where D: digest::HashMarker {}