Skip to main content

rings_core/session/
signing_key.rs

1use std::str::FromStr;
2
3use rings_derive::wasm_export;
4use serde::Deserialize;
5use serde::Serialize;
6
7use super::Session;
8use super::SessionSkBuilder;
9use crate::dht::Did;
10use crate::ecc::keccak256;
11use crate::ecc::keys::AccountVerifier;
12use crate::ecc::signers;
13use crate::ecc::PublicKey;
14use crate::ecc::SecretKey;
15use crate::error::Error;
16use crate::error::Result;
17
18/// A verified [`Session`] and its delegated private signing key.
19///
20/// Clone law: cloning a `SessionSk` duplicates the same in-memory signing and decryption authority.
21/// The clone preserves the account DID, session identity, and session public key; it does not mint,
22/// rotate, or narrow the capability.
23#[wasm_export]
24#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
25pub struct SessionSk {
26    session: Session,
27    sk: SecretKey,
28}
29
30impl FromStr for SessionSk {
31    type Err = Error;
32
33    fn from_str(s: &str) -> Result<Self> {
34        let s = base58_monero::decode_check(s).map_err(|_| Error::Decode)?;
35        serde_json::from_slice(&s).map_err(Error::Deserialize)
36    }
37}
38
39impl SessionSk {
40    pub(super) const fn from_parts(session: Session, sk: SecretKey) -> Self {
41        Self { session, sk }
42    }
43
44    /// Generate a session with a private key. Only use this for unit tests.
45    ///
46    /// To protect account private keys in production, use [`SessionSkBuilder`] instead.
47    pub fn new_with_seckey(key: &SecretKey) -> Result<Self> {
48        let account_entity = Did::from(key.address()).to_string();
49        let account_type = "secp256k1".to_string();
50        let builder = SessionSkBuilder::new(account_entity, account_type);
51        let sig = key.sign(&builder.unsigned_proof());
52        builder.set_session_sig(sig.to_vec()).build()
53    }
54
55    /// Clone the public session proof.
56    pub fn session(&self) -> Session {
57        self.session.clone()
58    }
59
60    /// Return the secp256k1 session public key used for encryption.
61    pub fn session_public_key(&self) -> PublicKey<33> {
62        self.sk.pubkey()
63    }
64
65    /// Decrypt an ElGamal-AEAD envelope with this session key.
66    pub fn decrypt_elgamal_aead(
67        &self,
68        sealed: &crate::ecc::elgamal::impls::secp256k1::AeadCiphertext,
69        aad: &[u8],
70    ) -> Result<Vec<u8>> {
71        crate::ecc::elgamal::impls::secp256k1::decrypt_aead(sealed, aad, self.sk)
72    }
73
74    /// Sign a message with the delegated session key.
75    pub fn sign(&self, msg: &[u8]) -> Result<Vec<u8>> {
76        let h = keccak256(msg);
77        Ok(signers::secp256k1::sign(self.sk, &h).to_vec())
78    }
79
80    /// Get the authorizing account DID.
81    pub fn account_did(&self) -> Did {
82        self.session.account_did()
83    }
84
85    /// Get the typed account verifier from the session.
86    pub fn account_verifier(&self) -> AccountVerifier {
87        self.session.account_verifier()
88    }
89
90    /// Encode this session key for storage in a configuration file.
91    ///
92    /// Restore it with [`SessionSk::from_str`].
93    pub fn dump(&self) -> Result<String> {
94        let s = serde_json::to_string(self).map_err(|_| Error::SerializeError)?;
95        base58_monero::encode_check(s.as_bytes()).map_err(|_| Error::Encode)
96    }
97}