use crate::{Result, SodiumError};
use ct_codecs;
use ct_codecs::Encoder;
use libsodium_sys;
pub const PUBLICKEYBYTES: usize = libsodium_sys::crypto_box_PUBLICKEYBYTES as usize;
pub const SECRETKEYBYTES: usize = libsodium_sys::crypto_box_SECRETKEYBYTES as usize;
pub const NONCEBYTES: usize = libsodium_sys::crypto_box_NONCEBYTES as usize;
#[derive(Clone, Eq, PartialEq)]
pub struct Nonce([u8; NONCEBYTES]);
impl Nonce {
pub fn generate() -> Self {
let mut bytes = [0u8; NONCEBYTES];
crate::random::fill_bytes(&mut bytes);
Self(bytes)
}
pub const fn from_bytes_exact(bytes: [u8; NONCEBYTES]) -> Self {
Self(bytes)
}
pub fn as_bytes(&self) -> &[u8; NONCEBYTES] {
&self.0
}
pub fn as_bytes_mut(&mut self) -> &mut [u8; NONCEBYTES] {
&mut self.0
}
}
impl AsRef<[u8]> for Nonce {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl TryFrom<&[u8]> for Nonce {
type Error = crate::SodiumError;
fn try_from(slice: &[u8]) -> std::result::Result<Self, Self::Error> {
if slice.len() != NONCEBYTES {
return Err(crate::SodiumError::InvalidNonce(format!(
"nonce must be exactly {NONCEBYTES} bytes"
)));
}
let mut bytes = [0u8; NONCEBYTES];
bytes.copy_from_slice(slice);
Ok(Self(bytes))
}
}
impl std::fmt::Debug for Nonce {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let hex = ct_codecs::Hex::encode_to_string(&self.0[..4]).unwrap_or_default();
write!(f, "Nonce({hex})...")
}
}
pub const MACBYTES: usize = libsodium_sys::crypto_box_MACBYTES as usize;
pub const BEFORENMBYTES: usize = libsodium_sys::crypto_box_BEFORENMBYTES as usize;
pub const ZEROBYTES: usize = libsodium_sys::crypto_box_ZEROBYTES as usize;
pub const BOXZEROBYTES: usize = libsodium_sys::crypto_box_BOXZEROBYTES as usize;
pub const SEALBYTES: usize = libsodium_sys::crypto_box_SEALBYTES as usize;
#[derive(Clone, Eq, PartialEq)]
pub struct PublicKey([u8; PUBLICKEYBYTES]);
#[derive(Clone, Eq, PartialEq, zeroize::Zeroize, zeroize::ZeroizeOnDrop)]
pub struct SecretKey([u8; SECRETKEYBYTES]);
pub struct KeyPair {
pub public_key: PublicKey,
pub secret_key: SecretKey,
}
impl PublicKey {
pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
if bytes.len() != libsodium_sys::crypto_box_PUBLICKEYBYTES as usize {
return Err(SodiumError::InvalidKey(format!(
"public key must be exactly {} bytes",
libsodium_sys::crypto_box_PUBLICKEYBYTES
)));
}
let mut key = [0u8; libsodium_sys::crypto_box_PUBLICKEYBYTES as usize];
key.copy_from_slice(bytes);
Ok(PublicKey(key))
}
pub const fn from_bytes_exact(
bytes: [u8; libsodium_sys::crypto_box_PUBLICKEYBYTES as usize],
) -> Self {
Self(bytes)
}
pub fn as_bytes(&self) -> &[u8; libsodium_sys::crypto_box_PUBLICKEYBYTES as usize] {
&self.0
}
}
impl AsRef<[u8]> for PublicKey {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl TryFrom<&[u8]> for PublicKey {
type Error = SodiumError;
fn try_from(slice: &[u8]) -> std::result::Result<Self, Self::Error> {
Self::from_bytes(slice)
}
}
impl From<[u8; libsodium_sys::crypto_box_PUBLICKEYBYTES as usize]> for PublicKey {
fn from(bytes: [u8; libsodium_sys::crypto_box_PUBLICKEYBYTES as usize]) -> Self {
Self(bytes)
}
}
impl From<PublicKey> for [u8; PUBLICKEYBYTES] {
fn from(key: PublicKey) -> [u8; PUBLICKEYBYTES] {
key.0
}
}
impl std::fmt::Debug for PublicKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let hex = ct_codecs::Hex::encode_to_string(&self.0[..4]).unwrap_or_default();
write!(f, "PublicKey({hex})...")
}
}
impl std::fmt::Display for PublicKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let hex = ct_codecs::Hex::encode_to_string(&self.0[..4]).unwrap_or_default();
write!(f, "PublicKey({hex})...")
}
}
impl SecretKey {
pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
if bytes.len() != libsodium_sys::crypto_box_SECRETKEYBYTES as usize {
return Err(SodiumError::InvalidKey(format!(
"secret key must be exactly {} bytes",
libsodium_sys::crypto_box_SECRETKEYBYTES
)));
}
let mut key = [0u8; libsodium_sys::crypto_box_SECRETKEYBYTES as usize];
key.copy_from_slice(bytes);
Ok(SecretKey(key))
}
pub const fn from_bytes_exact(
bytes: [u8; libsodium_sys::crypto_box_SECRETKEYBYTES as usize],
) -> Self {
Self(bytes)
}
pub fn as_bytes(&self) -> &[u8; libsodium_sys::crypto_box_SECRETKEYBYTES as usize] {
&self.0
}
}
impl AsRef<[u8]> for SecretKey {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl TryFrom<&[u8]> for SecretKey {
type Error = SodiumError;
fn try_from(slice: &[u8]) -> std::result::Result<Self, Self::Error> {
Self::from_bytes(slice)
}
}
impl From<[u8; libsodium_sys::crypto_box_SECRETKEYBYTES as usize]> for SecretKey {
fn from(bytes: [u8; libsodium_sys::crypto_box_SECRETKEYBYTES as usize]) -> Self {
Self(bytes)
}
}
impl From<SecretKey> for [u8; SECRETKEYBYTES] {
fn from(key: SecretKey) -> [u8; SECRETKEYBYTES] {
key.0
}
}
impl std::fmt::Debug for SecretKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("SecretKey(*****)")
}
}
impl std::fmt::Display for SecretKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("SecretKey(*****)")
}
}
#[derive(Debug, Clone, Eq, PartialEq, zeroize::Zeroize, zeroize::ZeroizeOnDrop)]
pub struct PrecomputedKey([u8; BEFORENMBYTES]);
impl PrecomputedKey {
pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
if bytes.len() != BEFORENMBYTES {
return Err(SodiumError::InvalidInput(format!(
"precomputed key must be exactly {BEFORENMBYTES} bytes"
)));
}
let mut k = [0u8; BEFORENMBYTES];
k.copy_from_slice(bytes);
Ok(PrecomputedKey(k))
}
pub fn as_bytes(&self) -> &[u8; BEFORENMBYTES] {
&self.0
}
pub const fn from_bytes_exact(bytes: [u8; BEFORENMBYTES]) -> Self {
Self(bytes)
}
}
impl AsRef<[u8]> for PrecomputedKey {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl TryFrom<&[u8]> for PrecomputedKey {
type Error = SodiumError;
fn try_from(slice: &[u8]) -> std::result::Result<Self, Self::Error> {
Self::from_bytes(slice)
}
}
impl From<[u8; BEFORENMBYTES]> for PrecomputedKey {
fn from(bytes: [u8; BEFORENMBYTES]) -> Self {
Self(bytes)
}
}
impl From<PrecomputedKey> for [u8; BEFORENMBYTES] {
fn from(key: PrecomputedKey) -> [u8; BEFORENMBYTES] {
key.0
}
}
impl KeyPair {
pub fn generate() -> Self {
let mut pk = [0u8; PUBLICKEYBYTES];
let mut sk = [0u8; SECRETKEYBYTES];
let result = unsafe { libsodium_sys::crypto_box_keypair(pk.as_mut_ptr(), sk.as_mut_ptr()) };
assert_eq!(result, 0, "Failed to generate keypair");
Self {
public_key: PublicKey(pk),
secret_key: SecretKey(sk),
}
}
pub fn from_seed(seed: &[u8]) -> Result<Self> {
if seed.len() != SECRETKEYBYTES {
return Err(SodiumError::InvalidInput(format!(
"invalid seed length: expected {}, got {}",
SECRETKEYBYTES,
seed.len()
)));
}
let mut pk = [0u8; PUBLICKEYBYTES];
let mut sk = [0u8; SECRETKEYBYTES];
let result = unsafe {
libsodium_sys::crypto_box_seed_keypair(pk.as_mut_ptr(), sk.as_mut_ptr(), seed.as_ptr())
};
if result != 0 {
return Err(SodiumError::OperationError(
"failed to generate keypair from seed".into(),
));
}
Ok(Self {
public_key: PublicKey(pk),
secret_key: SecretKey(sk),
})
}
pub fn into_tuple(self) -> (PublicKey, SecretKey) {
(self.public_key, self.secret_key)
}
}
pub fn seal(
message: &[u8],
nonce: &Nonce,
recipient_pk: &PublicKey,
sender_sk: &SecretKey,
) -> Result<Vec<u8>> {
let mut ciphertext = vec![0u8; message.len() + MACBYTES];
let result = unsafe {
libsodium_sys::crypto_box_easy(
ciphertext.as_mut_ptr(),
message.as_ptr(),
message.len() as u64,
nonce.as_ref().as_ptr(),
recipient_pk.as_bytes().as_ptr(),
sender_sk.as_bytes().as_ptr(),
)
};
if result != 0 {
return Err(SodiumError::EncryptionError(
"crypto_box encryption failed".into(),
));
}
Ok(ciphertext)
}
pub fn seal_afternm(
message: &[u8],
nonce: &Nonce,
precomputed_key: &PrecomputedKey,
) -> Result<Vec<u8>> {
let ciphertext_len = message.len() + MACBYTES;
let mut ciphertext = vec![0u8; ciphertext_len];
let result = unsafe {
libsodium_sys::crypto_box_easy_afternm(
ciphertext.as_mut_ptr(),
message.as_ptr(),
message.len() as u64,
nonce.as_ref().as_ptr(),
precomputed_key.as_bytes().as_ptr(),
)
};
if result != 0 {
return Err(SodiumError::OperationError("encryption failed".into()));
}
Ok(ciphertext)
}
pub fn open(ciphertext: &[u8], nonce: &Nonce, pk: &PublicKey, sk: &SecretKey) -> Result<Vec<u8>> {
if ciphertext.len() < MACBYTES {
return Err(SodiumError::InvalidInput("ciphertext too short".into()));
}
let mut message = vec![0u8; ciphertext.len() - MACBYTES];
let result = unsafe {
libsodium_sys::crypto_box_open_easy(
message.as_mut_ptr(),
ciphertext.as_ptr(),
ciphertext.len() as u64,
nonce.as_ref().as_ptr(),
pk.as_bytes().as_ptr(),
sk.as_bytes().as_ptr(),
)
};
if result != 0 {
return Err(SodiumError::AuthenticationError);
}
Ok(message)
}
pub fn open_afternm(
ciphertext: &[u8],
nonce: &Nonce,
precomputed_key: &PrecomputedKey,
) -> Result<Vec<u8>> {
if ciphertext.len() < MACBYTES {
return Err(SodiumError::InvalidInput("ciphertext too short".into()));
}
let mut message = vec![0u8; ciphertext.len() - MACBYTES];
let result = unsafe {
libsodium_sys::crypto_box_open_easy_afternm(
message.as_mut_ptr(),
ciphertext.as_ptr(),
ciphertext.len() as u64,
nonce.as_ref().as_ptr(),
precomputed_key.as_bytes().as_ptr(),
)
};
if result != 0 {
return Err(SodiumError::OperationError("decryption failed".into()));
}
Ok(message)
}
pub fn beforenm(public_key: &PublicKey, secret_key: &SecretKey) -> Result<PrecomputedKey> {
let mut k = [0u8; BEFORENMBYTES];
let result = unsafe {
libsodium_sys::crypto_box_beforenm(
k.as_mut_ptr(),
public_key.as_bytes().as_ptr(),
secret_key.as_bytes().as_ptr(),
)
};
if result != 0 {
return Err(SodiumError::OperationError(
"precomputed key generation failed".into(),
));
}
Ok(PrecomputedKey(k))
}
pub fn seal_detached(
message: &[u8],
nonce: &Nonce,
recipient_pk: &PublicKey,
sender_sk: &SecretKey,
) -> Result<(Vec<u8>, [u8; MACBYTES])> {
let mut ciphertext = vec![0u8; message.len()];
let mut mac = [0u8; MACBYTES];
let result = unsafe {
libsodium_sys::crypto_box_detached(
ciphertext.as_mut_ptr(),
mac.as_mut_ptr(),
message.as_ptr(),
message.len() as u64,
nonce.as_ref().as_ptr(),
recipient_pk.as_bytes().as_ptr(),
sender_sk.as_bytes().as_ptr(),
)
};
if result != 0 {
return Err(SodiumError::EncryptionError(
"crypto_box detached encryption failed".into(),
));
}
Ok((ciphertext, mac))
}
pub fn open_detached(
ciphertext: &[u8],
mac: &[u8],
nonce: &Nonce,
pk: &PublicKey,
sk: &SecretKey,
) -> Result<Vec<u8>> {
let mut message = vec![0u8; ciphertext.len()];
let result = unsafe {
libsodium_sys::crypto_box_open_detached(
message.as_mut_ptr(),
ciphertext.as_ptr(),
mac.as_ptr(),
ciphertext.len() as u64,
nonce.as_ref().as_ptr(),
pk.as_bytes().as_ptr(),
sk.as_bytes().as_ptr(),
)
};
if result != 0 {
return Err(SodiumError::AuthenticationError);
}
Ok(message)
}
pub fn seal_detached_afternm(
message: &[u8],
nonce: &Nonce,
precomputed_key: &PrecomputedKey,
) -> Result<(Vec<u8>, Vec<u8>)> {
let mut ciphertext = vec![0u8; message.len()];
let mut mac = vec![0u8; MACBYTES];
let result = unsafe {
libsodium_sys::crypto_box_detached_afternm(
ciphertext.as_mut_ptr(),
mac.as_mut_ptr(),
message.as_ptr(),
message.len() as u64,
nonce.as_ref().as_ptr(),
precomputed_key.as_bytes().as_ptr(),
)
};
if result != 0 {
return Err(SodiumError::OperationError("encryption failed".into()));
}
Ok((ciphertext, mac))
}
pub fn open_detached_afternm(
ciphertext: &[u8],
mac: &[u8],
nonce: &Nonce,
precomputed_key: &PrecomputedKey,
) -> Result<Vec<u8>> {
let mut message = vec![0u8; ciphertext.len()];
let result = unsafe {
libsodium_sys::crypto_box_open_detached_afternm(
message.as_mut_ptr(),
ciphertext.as_ptr(),
mac.as_ptr(),
ciphertext.len() as u64,
nonce.as_ref().as_ptr(),
precomputed_key.as_bytes().as_ptr(),
)
};
if result != 0 {
return Err(SodiumError::OperationError("decryption failed".into()));
}
Ok(message)
}
pub fn seal_box(message: &[u8], recipient_pk: &PublicKey) -> Result<Vec<u8>> {
let mut sealed_box = vec![0u8; message.len() + SEALBYTES];
let result = unsafe {
libsodium_sys::crypto_box_seal(
sealed_box.as_mut_ptr(),
message.as_ptr(),
message.len() as u64,
recipient_pk.as_bytes().as_ptr(),
)
};
if result != 0 {
return Err(SodiumError::EncryptionError(
"sealed box encryption failed".into(),
));
}
Ok(sealed_box)
}
pub fn open_sealed_box(
sealed_box: &[u8],
recipient_pk: &PublicKey,
recipient_sk: &SecretKey,
) -> Result<Vec<u8>> {
if sealed_box.len() < SEALBYTES {
return Err(SodiumError::InvalidInput("sealed box too short".into()));
}
let mut message = vec![0u8; sealed_box.len() - SEALBYTES];
let result = unsafe {
libsodium_sys::crypto_box_seal_open(
message.as_mut_ptr(),
sealed_box.as_ptr(),
sealed_box.len() as u64,
recipient_pk.as_bytes().as_ptr(),
recipient_sk.as_bytes().as_ptr(),
)
};
if result != 0 {
return Err(SodiumError::OperationError(
"sealed box decryption failed".into(),
));
}
Ok(message)
}
pub fn seal_nacl(
padded_message: &[u8],
nonce: &Nonce,
pk: &PublicKey,
sk: &SecretKey,
) -> Result<Vec<u8>> {
if padded_message.len() < ZEROBYTES {
return Err(SodiumError::InvalidInput(format!(
"padded message must be at least {ZEROBYTES} bytes"
)));
}
if padded_message.iter().take(ZEROBYTES).any(|&byte| byte != 0) {
return Err(SodiumError::InvalidInput(format!(
"first {ZEROBYTES} bytes of padded message must be zero"
)));
}
let mut ciphertext = vec![0u8; padded_message.len()];
let result = unsafe {
libsodium_sys::crypto_box(
ciphertext.as_mut_ptr(),
padded_message.as_ptr(),
padded_message.len() as u64,
nonce.as_ref().as_ptr(),
pk.as_bytes().as_ptr(),
sk.as_bytes().as_ptr(),
)
};
if result != 0 {
return Err(SodiumError::OperationError("encryption failed".into()));
}
Ok(ciphertext)
}
pub fn open_nacl(
padded_ciphertext: &[u8],
nonce: &Nonce,
pk: &PublicKey,
sk: &SecretKey,
) -> Result<Vec<u8>> {
if padded_ciphertext.len() < BOXZEROBYTES {
return Err(SodiumError::InvalidInput(format!(
"padded ciphertext must be at least {BOXZEROBYTES} bytes"
)));
}
if padded_ciphertext
.iter()
.take(BOXZEROBYTES)
.any(|&byte| byte != 0)
{
return Err(SodiumError::InvalidInput(format!(
"first {BOXZEROBYTES} bytes of padded ciphertext must be zero"
)));
}
let mut message = vec![0u8; padded_ciphertext.len()];
let result = unsafe {
libsodium_sys::crypto_box_open(
message.as_mut_ptr(),
padded_ciphertext.as_ptr(),
padded_ciphertext.len() as u64,
nonce.as_ref().as_ptr(),
pk.as_bytes().as_ptr(),
sk.as_bytes().as_ptr(),
)
};
if result != 0 {
return Err(SodiumError::OperationError("decryption failed".into()));
}
Ok(message)
}
pub fn seal_nacl_afternm(
padded_message: &[u8],
nonce: &Nonce,
precomputed_key: &PrecomputedKey,
) -> Result<Vec<u8>> {
if padded_message.len() < ZEROBYTES {
return Err(SodiumError::InvalidInput(format!(
"padded message must be at least {ZEROBYTES} bytes"
)));
}
if padded_message.iter().take(ZEROBYTES).any(|&byte| byte != 0) {
return Err(SodiumError::InvalidInput(format!(
"first {ZEROBYTES} bytes of padded message must be zero"
)));
}
let mut ciphertext = vec![0u8; padded_message.len()];
let result = unsafe {
libsodium_sys::crypto_box_afternm(
ciphertext.as_mut_ptr(),
padded_message.as_ptr(),
padded_message.len() as u64,
nonce.as_ref().as_ptr(),
precomputed_key.as_bytes().as_ptr(),
)
};
if result != 0 {
return Err(SodiumError::OperationError("encryption failed".into()));
}
Ok(ciphertext)
}
pub fn open_nacl_afternm(
padded_ciphertext: &[u8],
nonce: &Nonce,
precomputed_key: &PrecomputedKey,
) -> Result<Vec<u8>> {
if padded_ciphertext.len() < BOXZEROBYTES {
return Err(SodiumError::InvalidInput(format!(
"padded ciphertext must be at least {BOXZEROBYTES} bytes"
)));
}
if padded_ciphertext
.iter()
.take(BOXZEROBYTES)
.any(|&byte| byte != 0)
{
return Err(SodiumError::InvalidInput(format!(
"first {BOXZEROBYTES} bytes of padded ciphertext must be zero"
)));
}
let mut message = vec![0u8; padded_ciphertext.len()];
let result = unsafe {
libsodium_sys::crypto_box_open_afternm(
message.as_mut_ptr(),
padded_ciphertext.as_ptr(),
padded_ciphertext.len() as u64,
nonce.as_ref().as_ptr(),
precomputed_key.as_bytes().as_ptr(),
)
};
if result != 0 {
return Err(SodiumError::OperationError("decryption failed".into()));
}
Ok(message)
}
pub mod curve25519xsalsa20poly1305;
pub mod curve25519xchacha20poly1305;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_keypair_generation() {
let keypair = KeyPair::generate();
let (pk, sk) = (keypair.public_key, keypair.secret_key);
assert_eq!(pk.as_bytes().len(), PUBLICKEYBYTES);
assert_eq!(sk.as_bytes().len(), SECRETKEYBYTES);
}
#[test]
fn test_seed_keypair() {
let mut seed = [0u8; SECRETKEYBYTES];
crate::random::fill_bytes(&mut seed);
let keypair1 = KeyPair::from_seed(&seed).unwrap();
let keypair2 = KeyPair::from_seed(&seed).unwrap();
assert_eq!(keypair1.public_key, keypair2.public_key);
assert_eq!(keypair1.secret_key, keypair2.secret_key);
let invalid_seed = [0u8; SECRETKEYBYTES - 1];
assert!(KeyPair::from_seed(&invalid_seed).is_err());
}
#[test]
fn test_seal_open() {
let alice_keypair = KeyPair::generate();
let (alice_pk, alice_sk) = (alice_keypair.public_key, alice_keypair.secret_key);
let bob_keypair = KeyPair::generate();
let (bob_pk, bob_sk) = (bob_keypair.public_key, bob_keypair.secret_key);
let nonce = Nonce::generate();
let message = b"Hello, world!";
let ciphertext = seal(message, &nonce, &bob_pk, &alice_sk).unwrap();
let decrypted = open(&ciphertext, &nonce, &alice_pk, &bob_sk).unwrap();
assert_eq!(decrypted, message);
}
#[test]
fn test_beforenm_afternm() {
let alice_keypair = KeyPair::generate();
let (alice_pk, alice_sk) = (alice_keypair.public_key, alice_keypair.secret_key);
let bob_keypair = KeyPair::generate();
let (bob_pk, bob_sk) = (bob_keypair.public_key, bob_keypair.secret_key);
let nonce = Nonce::generate();
let message = b"Hello, precomputed key!";
let alice_precomputed = beforenm(&bob_pk, &alice_sk).unwrap();
let bob_precomputed = beforenm(&alice_pk, &bob_sk).unwrap();
let ciphertext = seal_afternm(message, &nonce, &alice_precomputed).unwrap();
let decrypted = open_afternm(&ciphertext, &nonce, &bob_precomputed).unwrap();
assert_eq!(decrypted, message);
}
#[test]
fn test_seal_detached_open_detached() {
let alice_keypair = KeyPair::generate();
let (alice_pk, alice_sk) = (alice_keypair.public_key, alice_keypair.secret_key);
let bob_keypair = KeyPair::generate();
let (bob_pk, bob_sk) = (bob_keypair.public_key, bob_keypair.secret_key);
let nonce = Nonce::generate();
let message = b"Hello, detached authentication!";
let (ciphertext, mac) = seal_detached(message, &nonce, &bob_pk, &alice_sk).unwrap();
let decrypted = open_detached(&ciphertext, &mac, &nonce, &alice_pk, &bob_sk).unwrap();
assert_eq!(decrypted, message);
}
#[test]
fn test_seal_detached_open_detached_afternm() {
let alice_keypair = KeyPair::generate();
let (alice_pk, alice_sk) = (alice_keypair.public_key, alice_keypair.secret_key);
let bob_keypair = KeyPair::generate();
let (bob_pk, bob_sk) = (bob_keypair.public_key, bob_keypair.secret_key);
let nonce = Nonce::generate();
let message = b"Hello, detached authentication with precomputed key!";
let alice_precomputed = beforenm(&bob_pk, &alice_sk).unwrap();
let bob_precomputed = beforenm(&alice_pk, &bob_sk).unwrap();
let (ciphertext, mac) = seal_detached_afternm(message, &nonce, &alice_precomputed).unwrap();
let decrypted = open_detached_afternm(&ciphertext, &mac, &nonce, &bob_precomputed).unwrap();
assert_eq!(decrypted, message);
}
#[test]
fn test_seal_box_open_sealed_box() {
let bob_keypair = KeyPair::generate();
let (bob_pk, bob_sk) = (bob_keypair.public_key, bob_keypair.secret_key);
let message = b"Hello, anonymous sender!";
let sealed_box = seal_box(message, &bob_pk).unwrap();
let decrypted = open_sealed_box(&sealed_box, &bob_pk, &bob_sk).unwrap();
assert_eq!(decrypted, message);
}
#[test]
fn test_nacl_compatibility() {
let alice_keypair = KeyPair::generate();
let (alice_pk, alice_sk) = (alice_keypair.public_key, alice_keypair.secret_key);
let bob_keypair = KeyPair::generate();
let (bob_pk, bob_sk) = (bob_keypair.public_key, bob_keypair.secret_key);
let nonce = Nonce::generate();
let message = b"Hello, NaCl!";
let mut padded_message = vec![0u8; ZEROBYTES + message.len()];
padded_message[ZEROBYTES..].copy_from_slice(message);
let padded_ciphertext = seal_nacl(&padded_message, &nonce, &bob_pk, &alice_sk).unwrap();
let decrypted_padded = open_nacl(&padded_ciphertext, &nonce, &alice_pk, &bob_sk).unwrap();
assert_eq!(decrypted_padded, padded_message);
}
#[test]
fn test_nacl_compatibility_afternm() {
let alice_keypair = KeyPair::generate();
let (alice_pk, alice_sk) = (alice_keypair.public_key, alice_keypair.secret_key);
let bob_keypair = KeyPair::generate();
let (bob_pk, bob_sk) = (bob_keypair.public_key, bob_keypair.secret_key);
let nonce = Nonce::generate();
let message = b"Hello, NaCl afternm!";
let mut padded_message = vec![0u8; ZEROBYTES + message.len()];
padded_message[ZEROBYTES..].copy_from_slice(message);
let alice_precomputed = beforenm(&bob_pk, &alice_sk).unwrap();
let bob_precomputed = beforenm(&alice_pk, &bob_sk).unwrap();
let padded_ciphertext =
seal_nacl_afternm(&padded_message, &nonce, &alice_precomputed).unwrap();
let decrypted_padded =
open_nacl_afternm(&padded_ciphertext, &nonce, &bob_precomputed).unwrap();
assert_eq!(decrypted_padded, padded_message);
}
#[test]
fn test_publickey_traits() {
let keypair = KeyPair::generate();
let pk = keypair.public_key;
let bytes: [u8; PUBLICKEYBYTES] = pk.clone().into();
let pk2 = PublicKey::from(bytes);
assert_eq!(pk.as_bytes(), pk2.as_bytes());
let extracted: [u8; PUBLICKEYBYTES] = pk.into();
assert_eq!(extracted, bytes);
}
#[test]
fn test_secretkey_traits() {
let keypair = KeyPair::generate();
let sk = keypair.secret_key;
let bytes: [u8; SECRETKEYBYTES] = sk.clone().into();
let sk2 = SecretKey::from(bytes);
assert_eq!(sk.as_bytes(), sk2.as_bytes());
let extracted: [u8; SECRETKEYBYTES] = sk.into();
assert_eq!(extracted, bytes);
}
#[test]
fn test_precomputedkey_traits() {
let alice_keypair = KeyPair::generate();
let bob_keypair = KeyPair::generate();
let precomputed = beforenm(&bob_keypair.public_key, &alice_keypair.secret_key).unwrap();
let bytes = precomputed.as_bytes();
let pk2 = PrecomputedKey::try_from(&bytes[..]).unwrap();
assert_eq!(precomputed.as_bytes(), pk2.as_bytes());
let invalid_bytes = [0u8; BEFORENMBYTES - 1];
assert!(PrecomputedKey::try_from(&invalid_bytes[..]).is_err());
let bytes: [u8; BEFORENMBYTES] = precomputed.clone().into();
let pk3 = PrecomputedKey::from(bytes);
assert_eq!(precomputed.as_bytes(), pk3.as_bytes());
let extracted: [u8; BEFORENMBYTES] = precomputed.into();
assert_eq!(extracted, bytes);
let precomputed2 = beforenm(&alice_keypair.public_key, &bob_keypair.secret_key).unwrap();
let slice_ref: &[u8] = precomputed2.as_ref();
assert_eq!(slice_ref.len(), BEFORENMBYTES);
}
}