ed25519_dalek/
context.rs

1use crate::{InternalError, SignatureError};
2
3/// Ed25519 contexts as used by Ed25519ph.
4///
5/// Contexts are domain separator strings that can be used to isolate uses of
6/// the algorithm between different protocols (which is very hard to reliably do
7/// otherwise) and between different uses within the same protocol.
8///
9/// To create a context, call either of the following:
10///
11/// - [`SigningKey::with_context`](crate::SigningKey::with_context)
12/// - [`VerifyingKey::with_context`](crate::VerifyingKey::with_context)
13///
14/// For more information, see [RFC8032 ยง 8.3](https://www.rfc-editor.org/rfc/rfc8032#section-8.3).
15///
16/// # Example
17///
18#[cfg_attr(all(feature = "digest", feature = "rand_core"), doc = "```")]
19#[cfg_attr(
20    any(not(feature = "digest"), not(feature = "rand_core")),
21    doc = "```ignore"
22)]
23/// # fn main() {
24/// use ed25519_dalek::{Signature, SigningKey, VerifyingKey, Sha512};
25/// # use curve25519_dalek::digest::Digest;
26/// # use rand::rngs::OsRng;
27/// use ed25519_dalek::{DigestSigner, DigestVerifier};
28///
29/// # let mut csprng = OsRng;
30/// # let signing_key = SigningKey::generate(&mut csprng);
31/// # let verifying_key = signing_key.verifying_key();
32/// let context_str = b"Local Channel 3";
33/// let prehashed_message = Sha512::default().chain_update(b"Stay tuned for more news at 7");
34///
35/// // Signer
36/// let signing_context = signing_key.with_context(context_str).unwrap();
37/// let signature = signing_context.sign_digest(prehashed_message.clone());
38///
39/// // Verifier
40/// let verifying_context = verifying_key.with_context(context_str).unwrap();
41/// let verified: bool = verifying_context
42///     .verify_digest(prehashed_message, &signature)
43///     .is_ok();
44///
45/// # assert!(verified);
46/// # }
47/// ```
48#[derive(Clone, Debug)]
49pub struct Context<'k, 'v, K> {
50    /// Key this context is being used with.
51    key: &'k K,
52
53    /// Context value: a bytestring no longer than 255 octets.
54    value: &'v [u8],
55}
56
57impl<'k, 'v, K> Context<'k, 'v, K> {
58    /// Maximum length of the context value in octets.
59    pub const MAX_LENGTH: usize = 255;
60
61    /// Create a new Ed25519ph context.
62    pub(crate) fn new(key: &'k K, value: &'v [u8]) -> Result<Self, SignatureError> {
63        if value.len() <= Self::MAX_LENGTH {
64            Ok(Self { key, value })
65        } else {
66            Err(SignatureError::from(InternalError::PrehashedContextLength))
67        }
68    }
69
70    /// Borrow the key.
71    pub fn key(&self) -> &'k K {
72        self.key
73    }
74
75    /// Borrow the context string value.
76    pub fn value(&self) -> &'v [u8] {
77        self.value
78    }
79}
80
81#[cfg(all(test, feature = "digest"))]
82mod test {
83    #![allow(clippy::unwrap_used)]
84
85    use crate::{Signature, SigningKey, VerifyingKey};
86    use curve25519_dalek::digest::Digest;
87    use ed25519::signature::{DigestSigner, DigestVerifier};
88    use rand::rngs::OsRng;
89    use sha2::Sha512;
90
91    #[test]
92    fn context_correctness() {
93        let mut csprng = OsRng;
94        let signing_key: SigningKey = SigningKey::generate(&mut csprng);
95        let verifying_key: VerifyingKey = signing_key.verifying_key();
96
97        let context_str = b"Local Channel 3";
98        let prehashed_message = Sha512::default().chain_update(b"Stay tuned for more news at 7");
99
100        // Signer
101        let signing_context = signing_key.with_context(context_str).unwrap();
102        let signature: Signature = signing_context.sign_digest(prehashed_message.clone());
103
104        // Verifier
105        let verifying_context = verifying_key.with_context(context_str).unwrap();
106        let verified: bool = verifying_context
107            .verify_digest(prehashed_message, &signature)
108            .is_ok();
109
110        assert!(verified);
111    }
112}