1use anyhow::{Context, Result};
2use chacha20poly1305::aead::Aead;
3use chacha20poly1305::{AeadCore, ChaCha20Poly1305, KeyInit};
4use rand::rngs::OsRng;
5
6pub fn encrypt_secrets(pubkey_hex: &str, plaintext: &str) -> Result<String> {
14 let key_bytes = hex::decode(pubkey_hex).context("Invalid hex pubkey")?;
15 anyhow::ensure!(key_bytes.len() == 32, "Pubkey must be 32 bytes");
16
17 let key = chacha20poly1305::Key::from_slice(&key_bytes);
18 let cipher = ChaCha20Poly1305::new(key);
19 let nonce = ChaCha20Poly1305::generate_nonce(&mut OsRng);
20
21 let ciphertext = cipher
22 .encrypt(&nonce, plaintext.as_bytes())
23 .map_err(|e| anyhow::anyhow!("Encryption failed: {e}"))?;
24
25 let mut encrypted = Vec::with_capacity(12 + ciphertext.len());
27 encrypted.extend_from_slice(&nonce);
28 encrypted.extend_from_slice(&ciphertext);
29
30 Ok(base64::Engine::encode(
31 &base64::engine::general_purpose::STANDARD,
32 &encrypted,
33 ))
34}
35
36pub fn generate_payment_key_secret() -> String {
38 let mut bytes = [0u8; 32];
39 rand::RngCore::fill_bytes(&mut OsRng, &mut bytes);
40 hex::encode(bytes)
41}
42
43pub fn sign_nep413(
50 private_key: &str,
51 message: &str,
52 recipient: &str,
53) -> Result<(String, String, String)> {
54 use borsh::BorshSerialize;
55 use near_crypto::SecretKey;
56 use sha2::{Digest, Sha256};
57
58 let secret_key: SecretKey = private_key
59 .parse()
60 .context("Invalid private key for NEP-413 signing")?;
61 let public_key = secret_key.public_key();
62
63 let mut nonce = [0u8; 32];
65 rand::RngCore::fill_bytes(&mut OsRng, &mut nonce);
66
67 #[derive(BorshSerialize)]
69 struct Nep413Payload {
70 message: String,
71 nonce: [u8; 32],
72 recipient: String,
73 callback_url: Option<String>,
74 }
75
76 let payload = Nep413Payload {
77 message: message.to_string(),
78 nonce,
79 recipient: recipient.to_string(),
80 callback_url: None,
81 };
82
83 let tag: u32 = 2_147_484_061;
85 let mut data = borsh::to_vec(&tag)?;
86 let payload_bytes = borsh::to_vec(&payload)?;
87 data.extend_from_slice(&payload_bytes);
88
89 let hash = Sha256::digest(&data);
91 let signature = secret_key.sign(&hash);
92
93 let nonce_base64 = base64::Engine::encode(
94 &base64::engine::general_purpose::STANDARD,
95 &nonce,
96 );
97
98 Ok((signature.to_string(), public_key.to_string(), nonce_base64))
99}