Question: I am making a Rust based library for Python which implements different cryptographic protocols, and I'm having trouble working with EphemeralSecret, as I keep getting the error log: "no method named to_bytes found for struct EphemeralSecret in the current scope method not found in EphemeralSecret"  This is being used to create a Rust lib to use it in Python so I can implement different cryptographic protocols and I need to work with the created keys in my Python side of things. I understand I maybe shouldn´t need to have a privateKey serialized for security reasons, but this is my case, so how do I "pass" it? Or should I maybe convert it in another way to work with it and be able to pass it around? I also have the trouble when converting it "back" from python to rust as there is no conversion back to it from bytes. The trouble is in the following section: // Elliptic Curve Diffie-Hellman #[pyfunction] fn generate_ecdh_key() -> PyResult<(Vec<u8>, Vec<u8>)> { let private_key = EphemeralSecret::random_from_rng(OsRng); let public_key = PublicKey::from(&private_key); Ok((private_key.to_bytes().to_vec(), public_key.as_bytes().to_vec())) } #[pyfunction] fn derive_ecdh_shared_key(private_key_bytes: Vec<u8>, server_public_key_bytes: Vec<u8>) -> PyResult<Vec<u8>> { let private_key = EphemeralSecret::from(private_key_bytes.as_slice().try_into().unwrap()); let server_public_key = PublicKey::from(server_public_key_bytes.as_slice().try_into().unwrap()); let shared_secret = private_key.diffie_hellman(&server_public_key); Ok(shared_secret.as_bytes().to_vec()) }  It is part of the complete code: use pyo3::prelude::*; use pyo3::wrap_pyfunction; use x25519_dalek::{EphemeralSecret, PublicKey}; use rand::Rng; use rand::rngs::OsRng; use num_bigint::{BigUint, RandBigInt}; use rsa::{RsaPrivateKey, RsaPublicKey, Pkcs1v15Encrypt}; use rsa::pkcs1::{DecodeRsaPrivateKey, DecodeRsaPublicKey, EncodeRsaPrivateKey, EncodeRsaPublicKey}; use rsa::pkcs8::LineEnding; // Diffie-Hellman #[pyfunction] fn generate_dh_key(p: &str, g: &str) -> PyResult<(String, String)> { let p = BigUint::parse_bytes(p.as_bytes(), 10).ok_or_else(|| pyo3::exceptions::PyValueError::new_err("Invalid p"))?; let g = BigUint::parse_bytes(g.as_bytes(), 10).ok_or_else(|| pyo3::exceptions::PyValueError::new_err("Invalid g"))?; let mut rng = OsRng; let private_key = rng.gen_biguint_below(&p); let public_key = g.modpow(&private_key, &p); Ok((private_key.to_str_radix(10), public_key.to_str_radix(10))) } #[pyfunction] fn derive_dh_shared_key(private_key: &str, server_public_key: &str, p: &str) -> PyResult<String> { let p = BigUint::parse_bytes(p.as_bytes(), 10).ok_or_else(|| pyo3::exceptions::PyValueError::new_err("Invalid p"))?; let private_key = BigUint::parse_bytes(private_key.as_bytes(), 10).ok_or_else(|| pyo3::exceptions::PyValueError::new_err("Invalid private_key"))?; let server_public_key = BigUint::parse_bytes(server_public_key.as_bytes(), 10).ok_or_else(|| pyo3::exceptions::PyValueError::new_err("Invalid server_public_key"))?; let shared_secret = server_public_key.modpow(&private_key, &p); Ok(shared_secret.to_str_radix(10)) } // Elliptic Curve Diffie-Hellman #[pyfunction] fn generate_ecdh_key() -> PyResult<(Vec<u8>, Vec<u8>)> { let private_key = EphemeralSecret::random_from_rng(OsRng); let public_key = PublicKey::from(&private_key); Ok((private_key.to_bytes().to_vec(), public_key.as_bytes().to_vec())) } #[pyfunction] fn derive_ecdh_shared_key(private_key_bytes: Vec<u8>, server_public_key_bytes: Vec<u8>) -> PyResult<Vec<u8>> { let private_key = EphemeralSecret::from(private_key_bytes.as_slice().try_into().unwrap()); let server_public_key = PublicKey::from(server_public_key_bytes.as_slice().try_into().unwrap()); let shared_secret = private_key.diffie_hellman(&server_public_key); Ok(shared_secret.as_bytes().to_vec()) } // RSA Functions #[pyfunction] fn generate_rsa_key() -> (String, String) { let mut rng = OsRng; let bits = 2048; let private_key = RsaPrivateKey::new(&mut rng, bits).unwrap(); let public_key = RsaPublicKey::from(&private_key); let private_pem = private_key.to_pkcs1_pem(LineEnding::LF).unwrap(); let public_pem = public_key.to_pkcs1_pem(LineEnding::LF).unwrap(); (private_pem.to_string(), public_pem) } #[pyfunction] fn rsa_encrypt(public_key_pem: &str, message: &str) -> Vec<u8> { let public_key = RsaPublicKey::from_pkcs1_pem(public_key_pem).unwrap(); let mut rng = OsRng; public_key.encrypt(&mut rng, Pkcs1v15Encrypt, message.as_bytes()).unwrap() } #[pyfunction] fn rsa_decrypt(private_key_pem: &str, encrypted_data: Vec<u8>) -> String { let private_key = RsaPrivateKey::from_pkcs1_pem(private_key_pem).unwrap(); let decrypted_data = private_key.decrypt(Pkcs1v15Encrypt, &encrypted_data).unwrap(); String::from_utf8(decrypted_data).unwrap() } // Swoosh NIKE key generation and exchange #[pyfunction] fn swoosh_generate_keys(parameters: (usize, usize, usize)) -> PyResult<(Vec<i8>, Vec<i8>)> { let (q, _d, n) = parameters; let mut rng = rand::thread_rng(); let a: Vec<i8> = (0..n * n).map(|_| rng.gen_range(0..q) as i8).collect(); let s: Vec<i8> = (0..n).map(|_| rng.gen_range(-1..=1)).collect(); let e: Vec<i8> = (0..n).map(|_| rng.gen_range(-1..=1)).collect(); let public_key: Vec<i8> = a.chunks(n).zip(&s).map(|(row, &s)| (row.iter().sum::<i8>() + e[s as usize]) % q as i8).collect(); Ok((s, public_key)) } #[pyfunction] fn swoosh_derive_shared_key(private_key: Vec<i8>, public_key: Vec<i8>, q: usize) -> PyResult<Vec<i8>> { let shared_key: Vec<i8> = private_key.iter().zip(&public_key).map(|(&s, &p)| (s * p) % q as i8).collect(); Ok(shared_key) } #[pymodule] fn shadowCrypt(m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_function(wrap_pyfunction!(generate_dh_key, m)?)?; m.add_function(wrap_pyfunction!(derive_dh_shared_key, m)?)?; m.add_function(wrap_pyfunction!(generate_ecdh_key, m)?)?; m.add_function(wrap_pyfunction!(derive_ecdh_shared_key, m)?)?; m.add_function(wrap_pyfunction!(generate_rsa_key, m)?)?; m.add_function(wrap_pyfunction!(rsa_encrypt, m)?)?; m.add_function(wrap_pyfunction!(rsa_decrypt, m)?)?; m.add_function(wrap_pyfunction!(swoosh_generate_keys, m)?)?; m.add_function(wrap_pyfunction!(swoosh_derive_shared_key, m)?)?; Ok(()) } 

Answer: EphemeralSecret does not have a to_bytes method as Ephemeral Secrets cannot be serialized to Vec as mentioned in the docs.  This type is identical to the StaticSecret type, except that the EphemeralSecret::diffie_hellman method consumes and then wipes the secret key, and there are no serialization methods defined  To convert to Vec<u8> you can use StaticSecret which has a StaticSecret::to_bytes method and can be used multiple times as well as serialized. So the final code would be something like use num_bigint::{BigUint, RandBigInt}; use pyo3::prelude::*; use pyo3::wrap_pyfunction; use rand::rngs::OsRng; use rand::Rng; use rsa::pkcs1::{ DecodeRsaPrivateKey, DecodeRsaPublicKey, EncodeRsaPrivateKey, EncodeRsaPublicKey, }; use rsa::pkcs8::LineEnding; use rsa::{Pkcs1v15Encrypt, RsaPrivateKey, RsaPublicKey}; use x25519_dalek::{PublicKey, StaticSecret}; // Diffie-Hellman #[pyfunction] fn generate_dh_key(p: &str, g: &str) -> PyResult<(String, String)> { let p = BigUint::parse_bytes(p.as_bytes(), 10) .ok_or_else(|| pyo3::exceptions::PyValueError::new_err("Invalid p"))?; let g = BigUint::parse_bytes(g.as_bytes(), 10) .ok_or_else(|| pyo3::exceptions::PyValueError::new_err("Invalid g"))?; let mut rng = OsRng; let private_key = rng.gen_biguint_below(&p); let public_key = g.modpow(&private_key, &p); Ok((private_key.to_str_radix(10), public_key.to_str_radix(10))) } #[pyfunction] fn derive_dh_shared_key(private_key: &str, server_public_key: &str, p: &str) -> PyResult<String> { let p = BigUint::parse_bytes(p.as_bytes(), 10) .ok_or_else(|| pyo3::exceptions::PyValueError::new_err("Invalid p"))?; let private_key = BigUint::parse_bytes(private_key.as_bytes(), 10) .ok_or_else(|| pyo3::exceptions::PyValueError::new_err("Invalid private_key"))?; let server_public_key = BigUint::parse_bytes(server_public_key.as_bytes(), 10) .ok_or_else(|| pyo3::exceptions::PyValueError::new_err("Invalid server_public_key"))?; let shared_secret = server_public_key.modpow(&private_key, &p); Ok(shared_secret.to_str_radix(10)) } // Elliptic Curve Diffie-Hellman #[pyfunction] fn generate_ecdh_key() -> PyResult<(Vec<u8>, Vec<u8>)> { let private_key = StaticSecret::random_from_rng(OsRng); let public_key = PublicKey::from(&private_key); Ok(( private_key.to_bytes().to_vec(), public_key.as_bytes().to_vec(), )) } #[pyfunction] fn derive_ecdh_shared_key( private_key_bytes: Vec<u8>, server_public_key_bytes: Vec<u8>, ) -> PyResult<Vec<u8>> { let private_key = StaticSecret::from(private_key_bytes.as_slice().try_into().unwrap()); let server_public_key = PublicKey::from(server_public_key_bytes.as_slice().try_into().unwrap()); let shared_secret = private_key.diffie_hellman(&server_public_key); Ok(shared_secret.as_bytes().to_vec()) } // RSA Functions #[pyfunction] fn generate_rsa_key() -> (String, String) { let mut rng = OsRng; let bits = 2048; let private_key = RsaPrivateKey::new(&mut rng, bits).unwrap(); let public_key = RsaPublicKey::from(&private_key); let private_pem = private_key.to_pkcs1_pem(LineEnding::LF).unwrap(); let public_pem = public_key.to_pkcs1_pem(LineEnding::LF).unwrap(); (private_pem.to_string(), public_pem) } #[pyfunction] fn rsa_encrypt(public_key_pem: &str, message: &str) -> Vec<u8> { let public_key = RsaPublicKey::from_pkcs1_pem(public_key_pem).unwrap(); let mut rng = OsRng; public_key .encrypt(&mut rng, Pkcs1v15Encrypt, message.as_bytes()) .unwrap() } #[pyfunction] fn rsa_decrypt(private_key_pem: &str, encrypted_data: Vec<u8>) -> String { let private_key = RsaPrivateKey::from_pkcs1_pem(private_key_pem).unwrap(); let decrypted_data = private_key .decrypt(Pkcs1v15Encrypt, &encrypted_data) .unwrap(); String::from_utf8(decrypted_data).unwrap() } // Swoosh NIKE key generation and exchange #[pyfunction] fn swoosh_generate_keys(parameters: (usize, usize, usize)) -> PyResult<(Vec<i8>, Vec<i8>)> { let (q, _d, n) = parameters; let mut rng = rand::thread_rng(); let a: Vec<i8> = (0..n * n).map(|_| rng.gen_range(0..q) as i8).collect(); let s: Vec<i8> = (0..n).map(|_| rng.gen_range(-1..=1)).collect(); let e: Vec<i8> = (0..n).map(|_| rng.gen_range(-1..=1)).collect(); let public_key: Vec<i8> = a .chunks(n) .zip(&s) .map(|(row, &s)| (row.iter().sum::<i8>() + e[s as usize]) % q as i8) .collect(); Ok((s, public_key)) } #[pyfunction] fn swoosh_derive_shared_key( private_key: Vec<i8>, public_key: Vec<i8>, q: usize, ) -> PyResult<Vec<i8>> { let shared_key: Vec<i8> = private_key .iter() .zip(&public_key) .map(|(&s, &p)| (s * p) % q as i8) .collect(); Ok(shared_key) } #[pymodule] fn shadow_crypt(m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_function(wrap_pyfunction!(generate_dh_key, m)?)?; m.add_function(wrap_pyfunction!(derive_dh_shared_key, m)?)?; m.add_function(wrap_pyfunction!(generate_ecdh_key, m)?)?; m.add_function(wrap_pyfunction!(derive_ecdh_shared_key, m)?)?; m.add_function(wrap_pyfunction!(generate_rsa_key, m)?)?; m.add_function(wrap_pyfunction!(rsa_encrypt, m)?)?; m.add_function(wrap_pyfunction!(rsa_decrypt, m)?)?; m.add_function(wrap_pyfunction!(swoosh_generate_keys, m)?)?; m.add_function(wrap_pyfunction!(swoosh_derive_shared_key, m)?)?; Ok(()) }  Note: The Cargo.toml file needs to be modified as follows: x25519_dalek = { version = "2.0.1", features = ["static_secrets"] }