use gridiron::fp_256::Fp256;
use internal;
use internal::bytedecoder::{BytesDecoder, DecodeErr};
use internal::curve;
pub use internal::ed25519::{
Ed25519, Ed25519Signing, PrivateSigningKey, PublicSigningKey, Signature,
};
use internal::fp12elem::Fp12Elem;
use internal::fp2elem::Fp2Elem;
use internal::hashable::{Hashable, Hashable32};
use internal::homogeneouspoint::HomogeneousPoint;
use internal::pairing;
pub use internal::rand_bytes::*;
pub use internal::sha256::{Sha256, Sha256Hashing};
pub use internal::ByteVector;
use nonemptyvec::NonEmptyVec;
use rand;
use std;
use std::fmt;
/// Recrypt public API
#[derive(Debug)]
pub struct Api<H, S, R> {
random_bytes: R,
sha_256: H,
ed25519: S,
pairing: internal::pairing::Pairing<Fp256>,
curve_points: &'static internal::curve::CurvePoints<Fp256>,
}
impl Api<Sha256, Ed25519, RandomBytes<rand::rngs::ThreadRng>> {
pub fn new() -> Api<Sha256, Ed25519, RandomBytes<rand::rngs::ThreadRng>> {
Api::new_with_rand(rand::thread_rng())
}
}
impl<CR: rand::CryptoRng + rand::RngCore> Api<Sha256, Ed25519, RandomBytes<CR>> {
pub fn new_with_rand(r: CR) -> Api<Sha256, Ed25519, RandomBytes<CR>> {
let pairing = pairing::Pairing::new();
let curve_points = &*curve::FP_256_CURVE_POINTS;
Api {
random_bytes: RandomBytes::new(r),
sha_256: Sha256,
ed25519: Ed25519,
pairing,
curve_points,
}
}
}
/// Errors generated by the API
#[derive(Debug, PartialEq)]
pub enum ApiErr {
DecryptFailed,
InvalidAuthHash,
InvalidSignature,
InvalidPublicKey(String),
InvalidReencryptionKey,
InputWrongSize(usize), // necessary size
}
type Result<T> = std::result::Result<T, ApiErr>;
impl From<internal::InternalError> for ApiErr {
fn from(err: internal::InternalError) -> Self {
match err {
internal::InternalError::AuthHashMatchFailed => ApiErr::InvalidAuthHash,
internal::InternalError::SignatureFailed => ApiErr::InvalidSignature,
internal::InternalError::PrivateKeyFailed
| internal::InternalError::BytesDecodeFailed(_) => ApiErr::DecryptFailed,
internal::InternalError::PointInvalid(_) => {
ApiErr::InvalidPublicKey("The point was not on the curve".to_string())
}
internal::InternalError::CorruptReencryptionKey => ApiErr::InvalidReencryptionKey,
}
}
}
impl From<internal::bytedecoder::DecodeErr> for ApiErr {
fn from(e: DecodeErr) -> Self {
ApiErr::from(internal::InternalError::from(e))
}
}
/// Hashed but not encrypted Plaintext used for envelope encryption
new_bytes_type!(DerivedSymmetricKey, 32);
/// A value included in an encrypted message that can be used when the message is decrypted
/// to ensure that you got the same value out as the one that was originally encrypted.
/// It is a hash of the plaintext.
new_bytes_type!(AuthHash, 32);
/// Encrypted Plaintext (Fp12Elem)
new_bytes_type!(EncryptedMessage, Fp12Elem::<Fp256>::ENCODED_SIZE_BYTES);
/// Not hashed, not encrypted Fp12Elem
/// See DecryptedSymmetricKey and EncryptedMessage
#[derive(Clone, Copy)]
pub struct Plaintext {
bytes: [u8; Plaintext::ENCODED_SIZE_BYTES],
_internal_fp12: Fp12Elem<Fp256>,
}
impl Plaintext {
const ENCODED_SIZE_BYTES: usize = Fp12Elem::<Fp256>::ENCODED_SIZE_BYTES;
/// Construct a Plaintext from raw bytes
pub fn new(bytes: [u8; Plaintext::ENCODED_SIZE_BYTES]) -> Plaintext {
// since new takes a fixed size array, we know it is safe to decode the resultant vector
Plaintext::from(
Fp12Elem::<Fp256>::decode(bytes.to_vec())
.expect("Developer error: did you change ENCODED_SIZE_BYTES?"),
)
}
new_from_slice!(Plaintext);
pub fn bytes(&self) -> &[u8; Plaintext::ENCODED_SIZE_BYTES] {
&self.bytes
}
}
bytes_only_debug!(Plaintext);
impl PartialEq for Plaintext {
fn eq(&self, other: &Plaintext) -> bool {
self.bytes[..] == other.bytes[..] && self._internal_fp12 == other._internal_fp12
}
}
impl From<Fp12Elem<Fp256>> for Plaintext {
fn from(fp12: Fp12Elem<Fp256>) -> Self {
Plaintext {
bytes: fp12.to_bytes_fp256(),
_internal_fp12: fp12,
}
}
}
impl BytesDecoder for Plaintext {
const ENCODED_SIZE_BYTES: usize = Fp12Elem::<Fp256>::ENCODED_SIZE_BYTES;
fn decode(bytes: ByteVector) -> std::result::Result<Plaintext, DecodeErr> {
Ok(Plaintext::from(Fp12Elem::decode(bytes)?))
}
}
impl Hashable for Plaintext {
fn to_bytes(&self) -> Vec<u8> {
self.bytes.to_vec()
}
}
/// Describes a single transform. Multiple `TransformBlocks` (in series) describe multi-hop transforms.
#[derive(Debug, Clone, Copy)]
pub struct TransformBlock {
/// public key corresponding to private key used to encrypt the temp key.
public_key: PublicKey,
/// random value generated for the transform key and encrypted to the delegatee. Copied from the parent `TransformKey`
encrypted_temp_key: EncryptedTempKey,
/// public key corresponding to the private key used to encrypt the random re-encryption `encrypted_random_transform_temp_key`
random_transform_public_key: PublicKey,
/// encrypted temp key value. Used to go from the transformed value to the encrypted value
encrypted_random_transform_temp_key: EncryptedTempKey,
_internal_re_block: internal::ReencryptionBlock<Fp256>,
}
impl TransformBlock {
/// Construct TransformBlock from constituent parts.
/// - `public_key` - public key corresponding to private key used to encrypt the temp key
/// - `encrypted_temp_key` - random value generated for the transform key and encrypted to the delegatee. Copied from the parent `TransformKey`
/// - `random_transform_public_key` - public key corresponding to the private key used to encrypt the random re-encryption `encrypted_random_transform_temp_key`
/// - `encrypted_random_transform_temp_key` - encrypted temp key value. Used to go from the transformed value to the encrypted value
pub fn new(
public_key: &PublicKey,
encrypted_temp_key: &EncryptedTempKey,
random_transform_public_key: &PublicKey,
encrypted_random_transform_temp_key: &EncryptedTempKey,
) -> Result<TransformBlock> {
let re_block_internal = internal::ReencryptionBlock {
public_key: public_key._internal_key,
encrypted_temp_key: encrypted_temp_key._internal_fp12,
rand_re_public_key: random_transform_public_key._internal_key,
encrypted_rand_re_temp_key: encrypted_random_transform_temp_key._internal_fp12,
};
TransformBlock::try_from(re_block_internal)
}
pub fn public_key(&self) -> &PublicKey {
&self.public_key
}
pub fn encrypted_temp_key(&self) -> &EncryptedTempKey {
&self.encrypted_temp_key
}
pub fn random_transform_public_key(&self) -> &PublicKey {
&self.random_transform_public_key
}
pub fn encrypted_random_transform_temp_key(&self) -> &EncryptedTempKey {
&self.encrypted_random_transform_temp_key
}
fn try_from(re_block: internal::ReencryptionBlock<Fp256>) -> Result<Self> {
Ok(TransformBlock {
public_key: PublicKey::try_from(&re_block.public_key)?,
encrypted_temp_key: EncryptedTempKey::from_fp12(re_block.encrypted_temp_key),
random_transform_public_key: PublicKey::try_from(&re_block.rand_re_public_key)?,
encrypted_random_transform_temp_key: EncryptedTempKey::from_fp12(
re_block.encrypted_rand_re_temp_key,
),
_internal_re_block: re_block,
})
}
}
/// Encrypted value that is either initially encrypted or one that has been
/// transformed one or more times
#[derive(Debug, Clone)] //cannot derive Copy because of NonEmptyVec
pub enum EncryptedValue {
/// Value which has been encrypted, but not transformed
/// `ephemeral_public_key` - public key of the ephemeral private key that was used to encrypt
/// `encrypted_message` - encrypted symmetric key
/// `auth_hash` - authentication hash for the Plaintext
/// `public_signing_key` - public portion of Ed25519 signing key
/// `signature` - Ed25519-produced signature
EncryptedOnceValue {
ephemeral_public_key: PublicKey,
encrypted_message: EncryptedMessage,
auth_hash: AuthHash,
public_signing_key: PublicSigningKey,
signature: Signature,
},
/// Value which has been encrypted and then transformed n times for n > 0.
/// `ephemeral_public_key` - public key of the ephemeral private key that was used to encrypt
/// `encrypted_message` - encrypted symmetric key
/// `auth_hash` - authentication hash for the Plaintext
/// `transform_blocks` - information used in transformation process. One entry for each transform.
/// `public_signing_key` - public portion of Ed25519 signing key
/// `signature` - Ed25519-produced signature
TransformedValue {
ephemeral_public_key: PublicKey,
encrypted_message: EncryptedMessage,
auth_hash: AuthHash,
transform_blocks: NonEmptyVec<TransformBlock>,
public_signing_key: PublicSigningKey,
signature: Signature,
},
}
impl EncryptedValue {
fn try_from(
signed_value: internal::SignedValue<internal::EncryptedValue<Fp256>>,
) -> Result<EncryptedValue> {
use api::EncryptedValue as EncryptedValueP;
match signed_value.payload {
internal::EncryptedValue::EncryptedOnce(internal::EncryptedOnceValue {
ephemeral_public_key,
encrypted_message,
auth_hash,
}) => {
let result = EncryptedValueP::EncryptedOnceValue {
ephemeral_public_key: PublicKey::try_from(&ephemeral_public_key)?,
encrypted_message: EncryptedMessage::new(encrypted_message.to_bytes_fp256()),
auth_hash: AuthHash::new(auth_hash.bytes),
public_signing_key: signed_value.public_signing_key,
signature: signed_value.signature,
};
Ok(result)
}
internal::EncryptedValue::Reencrypted(internal::ReencryptedValue {
ephemeral_public_key,
encrypted_message,
auth_hash,
encryption_blocks,
}) => {
let maybe_first_block = TransformBlock::try_from(*encryption_blocks.first());
let maybe_transform_blocks_rest: Result<Vec<TransformBlock>> = encryption_blocks
.rest()
.iter()
.map(|re_block| TransformBlock::try_from(*re_block))
.collect();
match (maybe_first_block, maybe_transform_blocks_rest) {
(Ok(good_first), Ok(good_rest)) => {
let result = EncryptedValueP::TransformedValue {
ephemeral_public_key: PublicKey::try_from(&ephemeral_public_key)?,
encrypted_message: EncryptedMessage::new(
encrypted_message.to_bytes_fp256(),
),
auth_hash: AuthHash::new(auth_hash.bytes),
transform_blocks: NonEmptyVec::new(good_first, good_rest),
public_signing_key: signed_value.public_signing_key,
signature: signed_value.signature,
};
Ok(result)
}
(Err(e), _) => Err(e),
(_, Err(e)) => Err(e),
}
}
}
}
/// Convert an EncryptedValue into the internal API's SignedValue.
///
/// This is defined here instead of in the internal api to give more efficient access
/// to the Public API's PublickKey
fn try_into(
ev: EncryptedValue,
) -> std::result::Result<
internal::SignedValue<internal::EncryptedValue<Fp256>>,
internal::InternalError,
> {
match ev {
EncryptedValue::EncryptedOnceValue {
ephemeral_public_key: pub_key,
encrypted_message:
EncryptedMessage {
bytes: encrypted_message,
},
auth_hash,
public_signing_key,
signature,
} => {
let fp12 = Fp12Elem::<Fp256>::decode(encrypted_message.to_vec())?;
Ok(internal::SignedValue::<internal::EncryptedValue<Fp256>> {
public_signing_key,
signature,
payload: internal::EncryptedValue::EncryptedOnce(
internal::EncryptedOnceValue {
ephemeral_public_key: pub_key._internal_key,
encrypted_message: fp12,
auth_hash: internal::AuthHash {
bytes: auth_hash.bytes,
},
},
),
})
}
EncryptedValue::TransformedValue {
ephemeral_public_key: pub_key,
encrypted_message:
EncryptedMessage {
bytes: encrypted_message,
},
auth_hash,
transform_blocks,
public_signing_key,
signature,
} => {
let fp12 = Fp12Elem::<Fp256>::decode(encrypted_message.to_vec())?;
let first_block = transform_blocks.first()._internal_re_block;
let rest_blocks = transform_blocks
.rest()
.iter()
.map(|tb| tb._internal_re_block)
.collect();
Ok(internal::SignedValue::<internal::EncryptedValue<Fp256>> {
public_signing_key,
signature,
payload: internal::EncryptedValue::Reencrypted(internal::ReencryptedValue {
ephemeral_public_key: pub_key._internal_key,
encrypted_message: fp12,
auth_hash: internal::AuthHash {
bytes: auth_hash.bytes,
},
encryption_blocks: NonEmptyVec::new(first_block, rest_blocks),
}),
})
}
}
}
}
/// Random Fp12, encrypted to the delegatee. Used to unroll transforms.
#[derive(Clone, Copy)]
pub struct EncryptedTempKey {
bytes: [u8; EncryptedTempKey::ENCODED_SIZE_BYTES],
_internal_fp12: Fp12Elem<Fp256>,
}
impl EncryptedTempKey {
const ENCODED_SIZE_BYTES: usize = Fp12Elem::<Fp256>::ENCODED_SIZE_BYTES;
fn from_fp12(fp12: Fp12Elem<Fp256>) -> Self {
EncryptedTempKey {
bytes: fp12.to_bytes_fp256(),
_internal_fp12: fp12,
}
}
pub fn new(bytes: [u8; EncryptedTempKey::ENCODED_SIZE_BYTES]) -> Self {
EncryptedTempKey::from_fp12(
Fp12Elem::<Fp256>::decode(bytes.to_vec())
.expect("Developer error: did you change ENCODED_SIZE_BYTES?"),
)
}
pub fn bytes(&self) -> &[u8; EncryptedTempKey::ENCODED_SIZE_BYTES] {
&self.bytes
}
new_from_slice!(EncryptedTempKey);
}
bytes_only_debug!(EncryptedTempKey);
impl PartialEq for EncryptedTempKey {
fn eq(&self, other: &EncryptedTempKey) -> bool {
self.bytes[..] == other.bytes[..] && self._internal_fp12 == other._internal_fp12
}
}
/// A combination of the hash of `EncryptedTempKey` and the `PrivateKey` of the delegator.
/// Used to recover the plaintext from an `EncryptedTempKey`
#[derive(Clone, Copy)]
pub struct HashedValue {
bytes: [u8; HashedValue::ENCODED_SIZE_BYTES],
_internal_value: HomogeneousPoint<Fp2Elem<Fp256>>,
}
impl HashedValue {
const ENCODED_SIZE_BYTES: usize = HomogeneousPoint::<Fp2Elem<Fp256>>::ENCODED_SIZE_BYTES;
pub fn new(bytes: [u8; HashedValue::ENCODED_SIZE_BYTES]) -> Result<Self> {
HomogeneousPoint::<Fp2Elem<Fp256>>::decode(bytes.to_vec())
.map(|hpoint| HashedValue {
bytes,
_internal_value: hpoint,
}).map_err(ApiErr::from)
}
pub fn bytes(&self) -> &[u8; HashedValue::ENCODED_SIZE_BYTES] {
&self.bytes
}
pub fn new_from_slice(bytes: &[u8]) -> Result<Self> {
if bytes.len() == HashedValue::ENCODED_SIZE_BYTES {
let mut dest = [0u8; HashedValue::ENCODED_SIZE_BYTES];
dest.copy_from_slice(bytes);
Ok(HashedValue::new(dest)?)
} else {
Err(ApiErr::InputWrongSize(HashedValue::ENCODED_SIZE_BYTES))
}
}
}
bytes_only_debug!(HashedValue);
impl PartialEq for HashedValue {
fn eq(&self, other: &HashedValue) -> bool {
self.bytes[..] == other.bytes[..] && self._internal_value == other._internal_value
}
}
impl From<HomogeneousPoint<Fp2Elem<Fp256>>> for HashedValue {
fn from(hp: HomogeneousPoint<Fp2Elem<Fp256>>) -> Self {
// convert hashed_k to fixed array.
// Assume the point is valid (on the curve, etc) since we're coming from internal types
let src = &hp.to_bytes()[..];
let mut dest = [0u8; HashedValue::ENCODED_SIZE_BYTES];
dest.copy_from_slice(src);
HashedValue {
bytes: dest,
_internal_value: hp,
}
}
}
/// TransformKeys allow a message encrypted to one public key (the key of the delegator)
/// to be transformed and appear as if it was encrypted to another public key (the key of hte delegatee),
/// or put another way, a TransformKey changes which private_key can decrypt the data.
///
/// TransfomKeys cannot, themselves, decrypt any data!
///
/// `ephemeral_public_key` - ephemeral key unique to this TransforKey. Key that encrypted the `encrypted_k` value
/// `to_public_key` - public key of the delagatee
/// `encrypted_k` - random value K, encrypted to the delegatee; used to un-roll successive levels of multi-hop transform encryption
/// `hashed_k` - combination of the hash of K and the secret key of the delegator; used to recover K from `encrypted_k`
#[derive(Debug, Clone, PartialEq)] //can't derive Copy because of NonEmptyVec
pub struct TransformKey {
ephemeral_public_key: PublicKey,
to_public_key: PublicKey,
encrypted_temp_key: EncryptedTempKey,
hashed_temp_key: HashedValue,
public_signing_key: PublicSigningKey,
signature: Signature,
_internal_key: internal::SignedValue<internal::ReencryptionKey<Fp256>>,
}
impl TransformKey {
pub fn ephemeral_public_key(&self) -> &PublicKey {
&self.ephemeral_public_key
}
pub fn to_public_key(&self) -> &PublicKey {
&self.to_public_key
}
pub fn encrypted_temp_key(&self) -> &EncryptedTempKey {
&self.encrypted_temp_key
}
pub fn hashed_temp_key(&self) -> &HashedValue {
&self.hashed_temp_key
}
pub fn public_signing_key(&self) -> &PublicSigningKey {
&self.public_signing_key
}
pub fn signature(&self) -> &Signature {
&self.signature
}
fn try_from_internal(
re_key: internal::SignedValue<internal::ReencryptionKey<Fp256>>,
) -> Result<TransformKey> {
let result = TransformKey {
ephemeral_public_key: PublicKey::try_from(&re_key.payload.re_public_key)?,
to_public_key: PublicKey::try_from(&re_key.payload.to_public_key)?,
encrypted_temp_key: EncryptedTempKey::from_fp12(re_key.payload.encrypted_k),
hashed_temp_key: HashedValue::from(re_key.payload.hashed_k),
public_signing_key: re_key.public_signing_key,
signature: re_key.signature,
_internal_key: re_key,
};
Ok(result)
}
/// Public constructor. See [`TransformKey`].
pub fn new(
ephemeral_public_key: PublicKey, //The ephemeral public key who encrypted the value
to_public_key: PublicKey, //The person or device that can decrypt the result
encrypted_temp_key: EncryptedTempKey, //The encrypted K value, which is used to go from the reencrypted value to the encrypted value
hashed_temp_key: HashedValue,
public_signing_key: PublicSigningKey,
signature: Signature,
) -> TransformKey {
let reencryption_key = internal::ReencryptionKey {
re_public_key: ephemeral_public_key._internal_key,
to_public_key: to_public_key._internal_key,
encrypted_k: encrypted_temp_key._internal_fp12,
hashed_k: hashed_temp_key._internal_value,
};
let internal_key = internal::SignedValue {
payload: reencryption_key,
signature,
public_signing_key,
};
// we can use all the params directly as they are all valid by construction
TransformKey {
ephemeral_public_key,
to_public_key,
encrypted_temp_key,
hashed_temp_key,
public_signing_key,
signature,
_internal_key: internal_key,
}
}
///Augment the TransformKey using private_key. If the private_key the TransformKey was delegating from was unaugmented
///this can be used to make the TransformKey useful for delegation.
pub fn augment(&self, private_key: &PrivateKey) -> Result<TransformKey> {
let new_internal = self
._internal_key
.payload
.augment(&(*private_key).into(), &curve::FP_256_CURVE_POINTS.g1);
TransformKey::try_from_internal(internal::SignedValue {
payload: new_internal,
..self._internal_key
})
}
}
pub trait Ed25519Ops {
///Generate a signing key pair for use with the `Ed25519Signing` trait.
fn generate_ed25519_key_pair(&mut self) -> (PrivateSigningKey, PublicSigningKey);
}
impl<H, S, CR: rand::RngCore + rand::CryptoRng> Ed25519Ops for Api<H, S, RandomBytes<CR>> {
///Generate a signing key pair for use with the `Ed25519Signing` trait using the random number generator
///used to back the `RandomBytes` struct.
fn generate_ed25519_key_pair(&mut self) -> (PrivateSigningKey, PublicSigningKey) {
use ed25519_dalek;
use sha2::Sha512;
let keypair = ed25519_dalek::Keypair::generate::<Sha512, CR>(&mut self.random_bytes.rng);
(
PrivateSigningKey::new(keypair.secret.expand::<Sha512>().to_bytes()),
PublicSigningKey::new(keypair.public.to_bytes()),
)
}
}
/// Key generation operations
pub trait KeyGenOps {
/// Compute a `PublicKey` given a `PrivateKey`
fn compute_public_key(&self, private_key: &PrivateKey) -> Result<PublicKey>;
/// Generate a random private key.
///
/// Relies on `Api::random_bytes` to generate cryptographically secure random bytes
fn random_private_key(&mut self) -> PrivateKey;
/// Generate a public/private keypair.
///
/// Relies on `Api::random_bytes` to generate cryptographically secure random bytes
fn generate_key_pair(&mut self) -> Result<(PrivateKey, PublicKey)>;
/// Generate a transform key which is used to delegate to the `to_public_key` from the `from_private_key`.
///
/// # Arguments
/// - `from_private_key` - key that can currently decrypt the value. (delegator)
/// - `to_public_key` - key that we want to let decrypt the value. (delegatee)
/// - `from_public_signing_key` - The public signing key of the person (or device) who is generating this transform key
/// - `from_private_signing_key` - The private signing key of the person (or device) who is generating this transform key
///
/// # Return
/// Key which allows a proxy to compute the transform. See `EncryptOps.transform`.
///
fn generate_transform_key(
&mut self,
from_private_key: PrivateKey,
to_public_key: PublicKey,
public_signing_key: PublicSigningKey,
private_signing_key: PrivateSigningKey,
) -> Result<TransformKey>;
}
impl<R: RandomBytesGen, H: Sha256Hashing, S: Ed25519Signing> KeyGenOps for Api<H, S, R> {
fn compute_public_key(&self, private_key: &PrivateKey) -> Result<PublicKey> {
let pub_key_internal = internal::public_keygen(
internal::PrivateKey::from(*private_key),
self.curve_points.generator,
);
PublicKey::try_from(&pub_key_internal)
}
fn random_private_key(&mut self) -> PrivateKey {
let rand_bytes = self.random_bytes.random_bytes_32();
PrivateKey::new(rand_bytes)
}
fn generate_key_pair(&mut self) -> Result<(PrivateKey, PublicKey)> {
let priv_key = self.random_private_key();
let maybe_pub_key = self.compute_public_key(&priv_key);
maybe_pub_key.map(|pub_key| (priv_key, pub_key))
}
fn generate_transform_key(
&mut self,
from_private_key: PrivateKey,
to_public_key: PublicKey,
public_signing_key: PublicSigningKey,
private_signing_key: PrivateSigningKey,
) -> Result<TransformKey> {
let ephem_reencryption_private_key = self.random_private_key();
let temp_key = gen_random_fp12(&mut self.random_bytes);
let reencryption_key = internal::generate_reencryption_key(
from_private_key._internal_key,
to_public_key._internal_key,
ephem_reencryption_private_key._internal_key,
temp_key,
public_signing_key,
private_signing_key,
&self.curve_points,
&self.pairing,
&self.sha_256,
&self.ed25519,
);
TransformKey::try_from_internal(reencryption_key)
}
}
/// Encrypt, Decrypt, Transform, and supporting operations.
pub trait CryptoOps {
/// Using the random_bytes, generate a random element of G_T, which is one of the rth roots of unity in FP12.
fn gen_plaintext(&mut self) -> Plaintext;
/// Convert our plaintext into a DecryptedSymmetricKey by hashing it.
fn derive_symmetric_key(&self, decrypted_value: &Plaintext) -> DerivedSymmetricKey;
/// Encrypt the plaintext to the `to_public_key`.
///
/// # Arguments
/// - `plaintext` - value to encrypt.
/// - `to_public_key` - identity to encrypt to.
/// - `public_signing_key` - public signing key of the person (or device) who is encrypting this value
/// - `private_signing_key` - private signing key of the person (or device) who is encrypting this value
///
/// # Return
/// EncryptedValue which can be decrypted by the matching private key of `to_public_key` or ApiErr.
fn encrypt(
&mut self,
plaintext: Plaintext,
to_public_key: PublicKey,
public_signing_key: PublicSigningKey,
private_signing_key: PrivateSigningKey,
) -> Result<EncryptedValue>;
/// Decrypt the value using `private_key`.
///
/// # Arguments
/// - `encrypted_value` - value we want to decrypt.
/// - `private_key` - PrivateKey which we want to use to decrypt the EncryptedValue.
///
/// # Return
/// An error if the key didn't match or something was corrupted in the EncryptedValue, otherwise the recovered plaintext.
fn decrypt(
&self,
encrypted_value: EncryptedValue,
private_key: PrivateKey,
) -> Result<Plaintext>;
/// Transform the value `encrypted_value` using the `transform_key`.
/// The returned value can be decrypted by the private key associated to the `to_public_key` in the `transform_key`.
///
/// The transformed value will be signed using the `private_signing_key` and will embed
/// the `public_signing_key` into the returned value.
fn transform(
&mut self,
encrypted_value: EncryptedValue,
transform_key: TransformKey,
public_signing_key: PublicSigningKey,
private_signing_key: PrivateSigningKey,
) -> Result<EncryptedValue>;
}
impl<R: RandomBytesGen, H: Sha256Hashing, S: Ed25519Signing> CryptoOps for Api<H, S, R> {
fn gen_plaintext(&mut self) -> Plaintext {
let rand_fp12 = gen_random_fp12(&mut self.random_bytes);
Plaintext::from(rand_fp12)
}
fn derive_symmetric_key(&self, decrypted_value: &Plaintext) -> DerivedSymmetricKey {
DerivedSymmetricKey::new(self.sha_256.hash(decrypted_value))
}
fn encrypt(
&mut self,
plaintext: Plaintext,
to_public_key: PublicKey,
public_signing_key: PublicSigningKey,
private_signing_key: PrivateSigningKey,
) -> Result<EncryptedValue> {
//generate a ephemeral private key
let ephem_private_key = self.random_private_key();
let plaintext_fp12 = plaintext._internal_fp12;
let encrypted_value_internal = internal::encrypt(
to_public_key._internal_key,
plaintext_fp12,
internal::PrivateKey::from(ephem_private_key),
public_signing_key,
private_signing_key,
&self.pairing,
&self.curve_points,
&self.sha_256,
&self.ed25519,
);
EncryptedValue::try_from(encrypted_value_internal)
}
fn decrypt(
&self,
encrypted_value: EncryptedValue,
private_key: PrivateKey,
) -> Result<Plaintext> {
Ok(internal::decrypt(
internal::PrivateKey::from(private_key),
EncryptedValue::try_into(encrypted_value)?,
&self.pairing,
&self.curve_points,
&self.sha_256,
&self.ed25519,
).map(Plaintext::from)?)
}
fn transform(
&mut self,
encrypted_value: EncryptedValue,
transform_key: TransformKey,
public_signing_key: PublicSigningKey,
private_signing_key: PrivateSigningKey,
) -> Result<EncryptedValue> {
let plaintext = self.gen_plaintext();
let random_private_key = self.random_private_key();
internal::reencrypt(
transform_key._internal_key,
EncryptedValue::try_into(encrypted_value)?,
internal::PrivateKey::from(random_private_key),
plaintext._internal_fp12,
public_signing_key,
private_signing_key,
&self.ed25519,
&self.sha_256,
&self.curve_points,
&self.pairing,
).map_err(ApiErr::from)
.and_then(EncryptedValue::try_from)
}
}
fn gen_random_fp12<R: RandomBytesGen>(random_bytes: &mut R) -> Fp12Elem<Fp256> {
// generate 12 random Fp values
internal::gen_rth_root(
&pairing::Pairing::new(),
Fp12Elem::create_from_t(
Fp256::from(random_bytes.random_bytes_32()),
Fp256::from(random_bytes.random_bytes_32()),
Fp256::from(random_bytes.random_bytes_32()),
Fp256::from(random_bytes.random_bytes_32()),
Fp256::from(random_bytes.random_bytes_32()),
Fp256::from(random_bytes.random_bytes_32()),
Fp256::from(random_bytes.random_bytes_32()),
Fp256::from(random_bytes.random_bytes_32()),
Fp256::from(random_bytes.random_bytes_32()),
Fp256::from(random_bytes.random_bytes_32()),
Fp256::from(random_bytes.random_bytes_32()),
Fp256::from(random_bytes.random_bytes_32()),
),
)
}
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct PublicKey {
x: [u8; 32],
y: [u8; 32],
_internal_key: internal::PublicKey<Fp256>,
}
impl PublicKey {
pub const ENCODED_SIZE_BYTES: usize = Fp256::ENCODED_SIZE_BYTES * 2;
fn try_from(internal_key: &internal::PublicKey<Fp256>) -> Result<PublicKey> {
internal_key
.to_byte_vectors_32()
.map(|(x, y)| PublicKey {
x,
y,
_internal_key: *internal_key,
}).ok_or_else(|| ApiErr::InvalidPublicKey("Public key was invalid.".to_string()))
}
pub fn new(
(x_bytes, y_bytes): (
[u8; Fp256::ENCODED_SIZE_BYTES],
[u8; Fp256::ENCODED_SIZE_BYTES],
),
) -> Result<PublicKey> {
let x = Fp256::decode(x_bytes.to_vec())
.map_err(|e| ApiErr::InvalidPublicKey(format!("x decode failed: {:?}", e)))?;
let y = Fp256::decode(y_bytes.to_vec())
.map_err(|e| ApiErr::InvalidPublicKey(format!("y decode failed: {:?}", e)))?;
let i_pk = internal::PublicKey::from_x_y_fp256(x, y)?;
PublicKey::try_from(&i_pk)
}
pub fn new_from_slice(bytes: (&[u8], &[u8])) -> Result<Self> {
if bytes.0.len() == Fp256::ENCODED_SIZE_BYTES && bytes.1.len() == Fp256::ENCODED_SIZE_BYTES
{
let mut x_dest = [0u8; Fp256::ENCODED_SIZE_BYTES];
x_dest.copy_from_slice(bytes.0);
let mut y_dest = [0u8; Fp256::ENCODED_SIZE_BYTES];
y_dest.copy_from_slice(bytes.1);
Ok(PublicKey::new((x_dest, y_dest))?)
} else {
Err(ApiErr::InputWrongSize(PublicKey::ENCODED_SIZE_BYTES))
}
}
pub fn bytes_x_y(&self) -> (&[u8; 32], &[u8; 32]) {
(&self.x, &self.y)
}
///Augment the PublicKey so that messages encrypted to that key cannot be decrypted by this PublicKey's PrivateKey.
///This can be useful if you want to force delegation via transform. See `TransformKey.augment`.
///Note that by augmenting a PublicKey you're committing to augmenting all `TransformKeys` that are created from
///this keypair. Otherwise the transformed data will not be able to be correctly decrypted.
pub fn augment(&self, other: &PublicKey) -> Result<PublicKey> {
let new_point = self._internal_key.value + other._internal_key.value;
PublicKey::try_from(&internal::PublicKey::new(new_point))
}
}
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub struct PrivateKey {
bytes: [u8; Fp256::ENCODED_SIZE_BYTES],
_internal_key: internal::PrivateKey<Fp256>,
}
impl PrivateKey {
const ENCODED_SIZE_BYTES: usize = Fp256::ENCODED_SIZE_BYTES;
pub fn bytes(&self) -> &[u8; PrivateKey::ENCODED_SIZE_BYTES] {
&self.bytes
}
pub fn new(bytes: [u8; PrivateKey::ENCODED_SIZE_BYTES]) -> PrivateKey {
let internal_key = internal::PrivateKey::from_fp256(Fp256::from(bytes));
PrivateKey {
bytes: internal_key.value.to_bytes_32(),
_internal_key: internal_key,
}
}
new_from_slice!(PrivateKey);
}
impl Hashable32 for PrivateKey {
fn to_bytes_32(&self) -> [u8; 32] {
self.bytes
}
}
impl From<internal::PrivateKey<Fp256>> for PrivateKey {
fn from(internal_pk: internal::PrivateKey<Fp256>) -> Self {
PrivateKey {
bytes: internal_pk.value.to_bytes_32(),
_internal_key: internal_pk,
}
}
}
#[cfg(test)]
pub(crate) mod test {
use super::*;
use hex;
use internal::Square;
use num_traits::{One, Zero};
use rand;
use std::ops::Mul;
///Duplicated here for the generate plaintext test
fn pow_for_square<T: One + Mul<T, Output = T> + Copy + Square>(t: T, exp: Fp256) -> T {
use gridiron::digits::util::DigitsArray;
if exp == Fp256::zero() {
T::one()
} else {
let mut mut_exp = exp;
let mut y = T::one();
let mut x = t;
while mut_exp > Fp256::one() {
if !mut_exp.is_even() {
y = x * y;
x = x.square();
} else {
x = x.square();
}
mut_exp = Fp256::new(mut_exp.shift_right_bits(1));
}
y * x
}
}
pub struct DummyEd25519;
impl Ed25519Signing for DummyEd25519 {
fn sign<T: Hashable>(&self, _t: &T, _private_key: &PrivateSigningKey) -> Signature {
Signature::new([0; 64])
}
fn verify<T: Hashable>(
&self,
_t: &T,
_signature: &Signature,
_public_key: &PublicSigningKey,
) -> bool {
true
}
}
#[derive(Default)]
pub(crate) struct DummyRandomBytes;
impl RandomBytesGen for DummyRandomBytes {
fn random_bytes_32(&mut self) -> [u8; 32] {
[std::u8::MAX; 32]
}
}
fn api_with<R: RandomBytesGen + Default, S: Ed25519Signing>(
random_bytes: Option<R>,
ed25519: S,
) -> Api<Sha256, S, R> {
let api = Api::new();
Api {
random_bytes: random_bytes.unwrap_or_default(),
sha_256: api.sha_256,
ed25519,
pairing: api.pairing,
curve_points: api.curve_points,
}
}
#[test]
fn public_key_roundtrip_with_internal() {
let (_, pub_key_api) = Api::new().generate_key_pair().unwrap();
let internal_pk = pub_key_api._internal_key;
let roundtrip = PublicKey::try_from(&internal_pk).unwrap();
assert_eq!(pub_key_api, roundtrip)
}
#[test]
fn private_key_roundtrip_with_internal() {
let (priv_key_api, _) = Api::new().generate_key_pair().unwrap();
let internal_pk = internal::PrivateKey::<Fp256>::from(priv_key_api);
let roundtrip = PrivateKey::from(internal_pk);
assert_eq!(priv_key_api, roundtrip);
assert_eq!(internal_pk, priv_key_api._internal_key)
}
#[test]
fn gen_plaintext_len() {
let api = &mut Api::new();
let result = api.gen_plaintext();
assert_eq!(Fp12Elem::<Fp256>::ENCODED_SIZE_BYTES, result.bytes.len());
}
#[test]
fn test_compute_public_key() {
let api = &mut Api::new();
//37777967648492203239675772600961898148040325589588086812374811831221462604944
let parsed_priv_key = Fp256::new([
17189375727870516368,
18224873185075715024,
7861335034745733951,
6018377467983639816,
]);
let private_key = &PrivateKey::new(parsed_priv_key.to_bytes_32());
//56377452267431283559088187378398270325210563762492926393848580098576649271541
let parsed_pub_key_x = Fp256::new([
1788354481340266741,
6941240287463798938,
4130173504620995341,
8981446317750070851,
]);
//46643694276241842996939080253335644316475473619096522181405937227991761798154
let parsed_pub_key_y = Fp256::new([
3047215073141965834,
7252896082344953161,
7531499505638418112,
7430769205681594307,
]);
let public_key_expected = PublicKey::try_from(
&internal::PublicKey::from_x_y_fp256(parsed_pub_key_x, parsed_pub_key_y).unwrap(),
).unwrap();
let computed_pub_key = api
.compute_public_key(private_key)
.expect("compute_public_key FAILED");
assert_eq!(computed_pub_key, public_key_expected);
let _computed_pub_key2 = api.compute_public_key(private_key); //second invocation to prove move semantics
}
#[test]
fn test_generate_key_pair_max_private_key() {
let mut api = api_with(Some(DummyRandomBytes), DummyEd25519);
let (_, pub_key) = api.generate_key_pair().unwrap();
let internal_pk = internal::PublicKey::from_x_y_fp256(
//58483620629232886210555514960799664032881966270053836377116209031946678864174
Fp256::new([
16689358048857196846,
6008153970969623586,
15595859671902000750,
9316978295816992987,
]),
//39604663823550822619127054070927331080305575010367415285113646212320556073913
Fp256::new([
6198767802656867257,
14549110804132857103,
11657926921458149507,
6309386958041887471,
]),
).unwrap();
let expected_pub_key = PublicKey::try_from(&internal_pk).unwrap();
assert_eq!(expected_pub_key, pub_key)
}
#[test]
fn test_handle_zero_point() {
let mut api = api_with(Some(TestZeroBytes), DummyEd25519);
assert!(api.generate_key_pair().is_err())
}
#[derive(Default)]
struct TestZeroBytes;
impl RandomBytesGen for TestZeroBytes {
fn random_bytes_32(&mut self) -> [u8; 32] {
[0u8; 32]
}
}
fn good_transform_key() -> TransformKey {
let mut api = Api::new();
let pbsk = PublicSigningKey::new([0; 32]);
let pvsk = PrivateSigningKey::new([0; 64]);
let (master_priv, master_pub) = api.generate_key_pair().unwrap();
api.generate_transform_key(master_priv, master_pub, pbsk, pvsk)
.unwrap()
}
#[test]
fn roundtrip_hashedvalue() {
let tk = good_transform_key();
let hashedvalue = tk.hashed_temp_key;
assert_eq!(
tk._internal_key.payload.hashed_k,
HomogeneousPoint::<Fp2Elem<Fp256>>::decode(hashedvalue.bytes.to_vec()).unwrap()
)
}
#[test]
fn roundtrip_encrypted_temp_key() {
let tk = good_transform_key();
let etk = tk.encrypted_temp_key;
assert_eq!(
tk._internal_key.payload.encrypted_k,
Fp12Elem::decode(etk.bytes.to_vec()).unwrap()
)
}
#[test]
fn gen_plaintext_always_produce_rth_root() {
let mut api = api_with(None::<RandomBytes<rand::rngs::ThreadRng>>, DummyEd25519);
let pt = api.gen_plaintext();
let fp12 = <Fp12Elem<Fp256>>::decode(pt.bytes.to_vec()).unwrap();
let curve_order = Fp256::new([
1886713967064937057,
3354493509585025316,
12281294985516866593,
10355184993929758713,
]);
let rth_pow = pow_for_square(fp12, curve_order);
assert_eq!(rth_pow, Fp12Elem::one());
}
#[test]
fn roundtrip_transform_block() {
let mut api = Api::new();
let pub_key1 = api.generate_key_pair().unwrap().1;
let pub_key2 = api.generate_key_pair().unwrap().1;
let ee1 = EncryptedTempKey::new(api.gen_plaintext().bytes);
let ee2 = EncryptedTempKey::new(api.gen_plaintext().bytes);
let tb = TransformBlock::new(&pub_key1, &ee1, &pub_key2, &ee2).unwrap();
assert_eq!(pub_key1, tb.public_key);
assert_eq!(ee1, tb.encrypted_temp_key);
assert_eq!(pub_key2, tb.random_transform_public_key);
assert_eq!(ee2, tb.encrypted_random_transform_temp_key);
}
#[test]
fn encrypt_decrypt_roundtrip() {
let mut api = api_with(None::<RandomBytes<rand::rngs::ThreadRng>>, DummyEd25519);
let pt = api.gen_plaintext();
let (priv_key, pub_key) = api.generate_key_pair().unwrap();
let pub_signing_key = internal::ed25519::PublicSigningKey::new([0; 32]);
let priv_signing_key = internal::ed25519::PrivateSigningKey::new([0; 64]);
let encrypted_val = api
.encrypt(pt, pub_key, pub_signing_key, priv_signing_key)
.unwrap();
let decrypted_val = api.decrypt(encrypted_val, priv_key).unwrap();
// compare the bytes as a vec as Plaintext and [u8; 384] don't define Eq
assert_eq!(pt.bytes.to_vec(), decrypted_val.bytes.to_vec())
}
#[test]
fn derive_known_symmetric_key() {
let bytes = hex::decode("28c0f558c02d983d7c652f16acbe91a566ac420fe02e41cf6d4f09a107f75cf76b6776ebb53365100ebeb7fa332995ae7bdddf0779fe79e1f43d5c51a73ced0a8cf5789804a79960ccf1a64bd55a923f4786d31ec06bf33e739254016d077b838e739f85586087e52ab659471df3904035e5e1f7ad6ac7b9f9dba6daf39e3f882b583e309c03e35ae7dfd4ed063b6c226bb3338627772e4c9a556fee7f3f96030ae1e265654fc322015a1c2d50eb273cd8b0e1e0353e6b09749343b5fe72ae2f302bebc527aca6ec465a95c4b41efe174eb5165993a30a922434a6f45cbafda201d6540bf2202c65751c90e4cd87e1b690997d9cd23474ef9ace4def3f17cbdd648c8545eaceb3f28c166f720fd8dd87b47523c55a52e32f8c1595a586763276411e8bd4400fac41234277cc560e919f76b21d757cda7c253078927e75482ee2759b222bf4fb070ab3032c9556a069d754efc3c0e63533311b29334108a5121a7e4018782324bf2c1517b6fe4df7a1bbb34c985c6d0796ff1e18ed80fd78d402").unwrap();
let pt = Plaintext::from(Fp12Elem::decode(bytes).unwrap());
let src = &hex::decode("0e62a3e388cb0ca3279792353f7fcad75acf180d430a5c69e0a68be96520f454")
.unwrap()[..];
let mut dest: [u8; 32] = [0u8; 32];
dest.copy_from_slice(src);
let expected_result = DerivedSymmetricKey::new(dest);
let result = Api::new().derive_symmetric_key(&pt);
assert_eq!(expected_result, result)
}
use std::default::Default;
#[test]
fn transform_to_same_key() {
let mut api = api_with(Some(RandomBytes::default()), DummyEd25519);
// let mut api = api_with(RandomBytes::<ThreadRng>::new(), DummyEd25519);
let pbsk = PublicSigningKey::new([0; 32]);
let pvsk = PrivateSigningKey::new([0; 64]);
let plaintext = api.gen_plaintext();
let (master_priv, master_pub) = api.generate_key_pair().unwrap();
let enc_value = api.encrypt(plaintext, master_pub, pbsk, pvsk).unwrap();
let master_to_master_transform_key = api
.generate_transform_key(master_priv, master_pub, pbsk, pvsk.clone())
.unwrap();
let transformed_value = api
.transform(
enc_value,
master_to_master_transform_key,
pbsk.clone(),
pvsk.clone(),
).unwrap();
let decrypted_plaintext = api.decrypt(transformed_value, master_priv).unwrap();
assert_eq!(plaintext, decrypted_plaintext)
}
#[test]
fn encrypt_decrypt_roundtrip_unaugmented_keys() {
let pbsk = PublicSigningKey::new([0; 32]);
let pvsk = PrivateSigningKey::new([0; 64]);
let mut api = api_with(Some(RandomBytes::default()), DummyEd25519);
let pt = api.gen_plaintext();
let (master_private_key, master_public_key) = api.generate_key_pair().unwrap();
let (device_private_key, device_public_key) = api.generate_key_pair().unwrap();
let encrypted_msg = api
.encrypt(pt.clone(), master_public_key, pbsk.clone(), pvsk.clone())
.unwrap();
let master_to_device_transform_key = api
.generate_transform_key(
master_private_key,
device_public_key,
pbsk.clone(),
pvsk.clone(),
).unwrap();
let transformed_msg = api
.transform(
encrypted_msg,
master_to_device_transform_key,
pbsk.clone(),
pvsk.clone(),
).unwrap();
let decrypted_pt = api.decrypt(transformed_msg, device_private_key).unwrap();
assert_eq!(pt, decrypted_pt)
}
#[test]
fn encrypt_decrypt_roundtrip_augmented_keys() {
let mut api = Api::new();
let (pvsk, pbsk) = api.generate_ed25519_key_pair();
let pt = api.gen_plaintext();
let (master_private_key, client_generated_pub) = api.generate_key_pair().unwrap();
let (device_private_key, device_public_key) = api.generate_key_pair().unwrap();
let (server_private, server_public) = api.generate_key_pair().unwrap();
let master_public_key = client_generated_pub.augment(&server_public).unwrap();
let encrypted_msg = api.encrypt(pt, master_public_key, pbsk, pvsk).unwrap();
let master_to_device_transform_key = api
.generate_transform_key(master_private_key, device_public_key, pbsk, pvsk)
.unwrap();
let augmented_transform_key = master_to_device_transform_key
.augment(&server_private)
.unwrap();
let transformed_msg = api
.transform(encrypted_msg, augmented_transform_key, pbsk, pvsk)
.unwrap();
let decrypted_pt = api.decrypt(transformed_msg, device_private_key).unwrap();
assert_eq!(pt, decrypted_pt)
}
#[test]
fn two_level_transform_roundtrip() {
let mut api = api_with(Some(RandomBytes::default()), DummyEd25519);
let (pvsk, pbsk) = api.generate_ed25519_key_pair();
let pt = api.gen_plaintext();
let (group_master_private_key, group_master_public_key) = api.generate_key_pair().unwrap();
let (user_master_private_key, user_master_public_key) = api.generate_key_pair().unwrap();
let (device_private_key, device_public_key) = api.generate_key_pair().unwrap();
let encrypted_msg = api
.encrypt(
pt.clone(),
group_master_public_key,
pbsk.clone(),
pvsk.clone(),
).unwrap();
// now create two transform keys. Group -> User -> Device (arrows are the transform keys)
let group_to_user_transform_key = api
.generate_transform_key(
group_master_private_key,
user_master_public_key,
pbsk.clone(),
pvsk.clone(),
).unwrap();
let user_to_device_transform_key = api
.generate_transform_key(
user_master_private_key,
device_public_key,
pbsk.clone(),
pvsk.clone(),
).unwrap();
let transformed_to_user = api
.transform(
encrypted_msg,
group_to_user_transform_key,
pbsk.clone(),
pvsk.clone(),
).unwrap();
let transformed_to_device = api
.transform(
transformed_to_user,
user_to_device_transform_key,
pbsk.clone(),
pvsk.clone(),
).unwrap();
let decrypted_result = api
.decrypt(transformed_to_device, device_private_key)
.unwrap();
assert_eq!(pt, decrypted_result)
}
#[test]
fn generate_ed25519_key_pair() {
use rand::SeedableRng;
let mut api = Api::new_with_rand(rand::ChaChaRng::from_seed([0u8; 32]));
let (priv_key, pub_key) = api.generate_ed25519_key_pair();
let expected_priv = PrivateSigningKey::new([
128, 158, 62, 131, 66, 25, 23, 206, 184, 23, 214, 146, 76, 2, 181, 160, 66, 173, 184,
231, 114, 23, 209, 170, 153, 195, 175, 92, 100, 159, 30, 102, 124, 223, 173, 194, 89,
216, 8, 97, 198, 148, 91, 9, 162, 166, 151, 61, 109, 144, 114, 202, 55, 194, 4, 64,
247, 76, 165, 179, 168, 178, 109, 49,
]);
let expected_pub = PublicSigningKey::new([
32, 253, 186, 201, 177, 11, 117, 135, 187, 167, 181, 188, 22, 59, 206, 105, 231, 150,
215, 30, 78, 212, 76, 16, 252, 180, 72, 134, 137, 247, 161, 68,
]);
assert_eq!(priv_key, expected_priv);
assert_eq!(pub_key, expected_pub);
//Assert that the generation doesn't just return the same value.
let (priv_key_two, pub_key_two) = api.generate_ed25519_key_pair();
assert_ne!(priv_key_two, expected_priv);
assert_ne!(pub_key_two, expected_pub);
}
#[test]
//written against AuthHash, but valid for all types generated from that macro
fn new_byte_type_from_slice() {
let input: [u8; 32] = [42u8; 32];
let slice: &[u8] = &input;
let auth_hash_from_fixed = AuthHash::new(input);
let auth_hash_from_slice = AuthHash::new_from_slice(slice);
assert_eq!(auth_hash_from_fixed, auth_hash_from_slice.unwrap());
assert_eq!(
ApiErr::InputWrongSize(32),
AuthHash::new_from_slice(&input[..30]).unwrap_err()
)
}
#[test]
fn hashedvalue_new_from_slice() {
let input: [u8; 128] = good_transform_key().hashed_temp_key.bytes;
let slice: &[u8] = &input;
let hv_from_fixed = HashedValue::new(input);
let hv_from_slice = HashedValue::new_from_slice(slice);
assert_eq!(hv_from_fixed.unwrap(), hv_from_slice.unwrap());
assert_eq!(
ApiErr::InputWrongSize(128),
HashedValue::new_from_slice(&input[..30]).unwrap_err()
)
}
#[test]
fn publickey_new_from_slice() {
let mut api = Api::new();
let (_, pk1) = api.generate_key_pair().unwrap();
let input: ([u8; 32], [u8; 32]) = (pk1.x, pk1.y);
let slice: (&[u8], &[u8]) = (&input.0, &input.1);
let pk_from_fixed = PublicKey::new(input);
let pk_from_slice = PublicKey::new_from_slice(slice);
assert_eq!(pk_from_fixed.unwrap(), pk_from_slice.unwrap());
assert_eq!(
ApiErr::InputWrongSize(64),
PublicKey::new_from_slice((&input.0[..30], &input.1[..32])).unwrap_err()
)
}
}