Skip to content

Commit

Permalink
feat(ton): Add C++ FFI interface
Browse files Browse the repository at this point in the history
  • Loading branch information
satoshiotomakan committed Aug 1, 2024
1 parent d0da206 commit aaa336b
Show file tree
Hide file tree
Showing 12 changed files with 395 additions and 0 deletions.
40 changes: 40 additions & 0 deletions include/TrustWalletCore/TWCryptoBox.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// SPDX-License-Identifier: Apache-2.0
//
// Copyright © 2017 Trust Wallet.

#pragma once

#include "TWBase.h"
#include "TWCryptoBoxPublicKey.h"
#include "TWCryptoBoxSecretKey.h"
#include "TWData.h"
#include "TWString.h"

TW_EXTERN_C_BEGIN

/// `crypto_box` encryption algorithms.
TW_EXPORT_STRUCT
struct TWCryptoBox;

/// Encrypts message using `my_secret` and `other_pubkey`.
/// The output will have a randomly generated nonce prepended to it.
/// The output will be Overhead + 24 bytes longer than the original.
///
/// \param mySecret *non-null* pointer to my secret key.
/// \param otherPubkey *non-null* pointer to other's public key.
/// \param message *non-null* pointer to the message to be encrypted.
/// \return *nullable* pointer to the encrypted message with randomly generated nonce prepended to it.
TW_EXPORT_STATIC_METHOD
TWData* _Nonnull TWCryptoBoxEncryptEasy(struct TWCryptoBoxSecretKey* _Nonnull mySecret, struct TWCryptoBoxPublicKey* _Nonnull otherPubkey, TWData* _Nonnull message);

/// Decrypts box produced by `TWCryptoBoxEncryptEasy`.
/// We assume a 24-byte nonce is prepended to the encrypted text in box.
///
/// \param mySecret *non-null* pointer to my secret key.
/// \param otherPubkey *non-null* pointer to other's public key.
/// \param encrypted *non-null* pointer to the encrypted message with nonce prepended to it.
/// \return *nullable* pointer to the decrypted message.
TW_EXPORT_STATIC_METHOD
TWData* _Nullable TWCryptoBoxDecryptEasy(struct TWCryptoBoxSecretKey* _Nonnull mySecret, struct TWCryptoBoxPublicKey* _Nonnull otherPubkey, TWData* _Nonnull encrypted);

TW_EXTERN_C_END
45 changes: 45 additions & 0 deletions include/TrustWalletCore/TWCryptoBoxPublicKey.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// SPDX-License-Identifier: Apache-2.0
//
// Copyright © 2017 Trust Wallet.

#pragma once

#include "TWBase.h"
#include "TWData.h"
#include "TWString.h"

TW_EXTERN_C_BEGIN

/// Public key used in `crypto_box` cryptography.
TW_EXPORT_STRUCT
struct TWCryptoBoxPublicKey;

/// Determines if the given public key is valid or not.
///
/// \param data *non-null* byte array.
/// \return true if the public key is valid, false otherwise.
TW_EXPORT_STATIC_METHOD
bool TWCryptoBoxPublicKeyIsValid(TWData* _Nonnull data);

/// Create a `crypto_box` public key with the given block of data.
///
/// \param data *non-null* byte array. Expected to have 32 bytes.
/// \note Should be deleted with \tw_crypto_box_public_key_delete.
/// \return Nullable pointer to Public Key.
TW_EXPORT_STATIC_METHOD
struct TWCryptoBoxPublicKey* _Nullable TWCryptoBoxPublicKeyCreateWithData(TWData* _Nonnull data);

/// Delete the given public key.
///
/// \param publicKey *non-null* pointer to public key.
TW_EXPORT_METHOD
void TWCryptoBoxPublicKeyDelete(struct TWCryptoBoxPublicKey* _Nonnull publicKey);

/// Returns the raw data of the given public-key.
///
/// \param publicKey *non-null* pointer to a public key.
/// \return C-compatible result with a C-compatible byte array.
TW_EXPORT_PROPERTY
TWData* _Nonnull TWCryptoBoxPublicKeyData(struct TWCryptoBoxPublicKey* _Nonnull publicKey);

TW_EXTERN_C_END
38 changes: 38 additions & 0 deletions include/TrustWalletCore/TWCryptoBoxSecretKey.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// SPDX-License-Identifier: Apache-2.0
//
// Copyright © 2017 Trust Wallet.

#pragma once

#include "TWBase.h"
#include "TWCryptoBoxPublicKey.h"
#include "TWData.h"
#include "TWString.h"

TW_EXTERN_C_BEGIN

/// Secret key used in `crypto_box` cryptography.
TW_EXPORT_CLASS
struct TWCryptoBoxSecretKey;

/// Create a random secret key.
///
/// \note Should be deleted with \tw_crypto_box_secret_key_delete.
/// \return *non-null* pointer to Secret Key.
TW_EXPORT_STATIC_METHOD
struct TWCryptoBoxSecretKey* _Nonnull TWCryptoBoxSecretKeyCreate();

/// Delete the given secret `key`.
///
/// \param key *non-null* pointer to secret key.
TW_EXPORT_METHOD
void TWCryptoBoxSecretKeyDelete(struct TWCryptoBoxSecretKey* _Nonnull key);

/// Returns the public key associated with the given `key`.
///
/// \param key *non-null* pointer to the private key.
/// \return *non-null* pointer to the corresponding public key.
TW_EXPORT_METHOD
struct TWCryptoBoxPublicKey* TWCryptoBoxSecretKeyGetPublicKey(struct TWCryptoBoxSecretKey* _Nonnull key);

TW_EXTERN_C_END
1 change: 1 addition & 0 deletions rust/tw_keypair/src/ffi/crypto_box/public_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use tw_memory::ffi::tw_data::TWData;
use tw_memory::ffi::RawPtrTrait;
use tw_misc::{try_or_else, try_or_false};

/// Public key used in `crypto_box` cryptography.
pub struct TWCryptoBoxPublicKey(pub(crate) PublicKey);

impl RawPtrTrait for TWCryptoBoxPublicKey {}
Expand Down
1 change: 1 addition & 0 deletions rust/tw_keypair/src/ffi/crypto_box/secret_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::nacl_crypto_box::secret_key::SecretKey;
use tw_memory::ffi::RawPtrTrait;
use tw_misc::try_or_else;

/// Secret key used in `crypto_box` cryptography.
pub struct TWCryptoBoxSecretKey(pub(crate) SecretKey);

impl RawPtrTrait for TWCryptoBoxSecretKey {}
Expand Down
28 changes: 28 additions & 0 deletions rust/tw_keypair/tests/crypto_box_ffi_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,34 @@ fn test_encrypt_decrypt_easy() {
assert_eq!(decrypted.to_vec().unwrap(), message);
}

#[test]
fn test_encrypt_decrypt_easy_error() {
let (my_secret, _my_pubkey) = random_key_pair();

let other_pubkey_data = TWDataHelper::create(
"afccabc5b28a8a1fd1cd880516f9c854ae2498d0d1b978b53a59f38e4ae55747"
.decode_hex()
.unwrap(),
);
let other_pubkey = TWWrapper::wrap(unsafe {
tw_crypto_box_public_key_create_with_data(other_pubkey_data.ptr())
});

// The given encrypted box cannot be decrypted by using `my_secret` and `other_pubkey`.
let invalid_encrypted = "7a7b9c8fee6e3c597512848c7d513e7131193cdfd410ff6611522fdeea99d7160873182019d7a18502f22c5e3644d26a2b669365".decode_hex().unwrap();
let invalid_encrypted_data = TWDataHelper::create(invalid_encrypted);

let decrypted = TWDataHelper::wrap(unsafe {
tw_crypto_box_decrypt_easy(
my_secret.ptr(),
other_pubkey.ptr(),
invalid_encrypted_data.ptr(),
)
});

assert!(decrypted.is_null());
}

#[test]
fn test_public_key() {
let pubkey_bytes = "afccabc5b28a8a1fd1cd880516f9c854ae2498d0d1b978b53a59f38e4ae55747"
Expand Down
53 changes: 53 additions & 0 deletions src/CryptoBox.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// SPDX-License-Identifier: Apache-2.0
//
// Copyright © 2017 Trust Wallet.

#include "CryptoBox.h"

namespace TW::CryptoBox {

bool PublicKey::isValid(const Data& bytes) {
Rust::TWDataWrapper data = bytes;
return Rust::tw_crypto_box_public_key_is_valid(data.get());
}

std::optional<PublicKey> PublicKey::fromBytes(const Data& bytes) {
Rust::TWDataWrapper data = bytes;
if (!Rust::tw_crypto_box_public_key_is_valid(data.get())) {
return std::nullopt;
}
auto* publicKey = Rust::tw_crypto_box_public_key_create_with_data(data.get());
return PublicKey(PublicKeyPtr(publicKey, Rust::tw_crypto_box_public_key_delete));
}

Data PublicKey::getData() const {
Rust::TWDataWrapper data = Rust::tw_crypto_box_public_key_data(impl.get());
return data.toDataOrDefault();
}

SecretKey::SecretKey() {
auto* secretKey = Rust::tw_crypto_box_secret_key_create();
impl = SecretKeyPtr(secretKey, Rust::tw_crypto_box_secret_key_delete);
}

PublicKey SecretKey::getPublicKey() const noexcept {
auto* publicKey = Rust::tw_crypto_box_secret_key_get_public_key(impl.get());
return PublicKey(PublicKeyPtr(publicKey, Rust::tw_crypto_box_public_key_delete));
}

Data encryptEasy(const SecretKey& mySecret, const PublicKey& otherPubkey, const Data& message) {
Rust::TWDataWrapper messageData = message;
Rust::TWDataWrapper encrypted = Rust::tw_crypto_box_encrypt_easy(mySecret.impl.get(), otherPubkey.impl.get(), messageData.get());
return encrypted.toDataOrDefault();
}

std::optional<Data> decryptEasy(const SecretKey& mySecret, const PublicKey& otherPubkey, const Data& encrypted) {
Rust::TWDataWrapper encryptedData = encrypted;
Rust::TWDataWrapper decryptedData = Rust::tw_crypto_box_decrypt_easy(mySecret.impl.get(), otherPubkey.impl.get(), encryptedData.get());
if (!decryptedData.ptr) {
return std::nullopt;
}
return decryptedData.toDataOrDefault();
}

} // namespace TW::CryptoBox
62 changes: 62 additions & 0 deletions src/CryptoBox.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// SPDX-License-Identifier: Apache-2.0
//
// Copyright © 2017 Trust Wallet.

#pragma once

#include "rust/Wrapper.h"

namespace TW::CryptoBox {

using PublicKeyPtr = std::shared_ptr<Rust::TWCryptoBoxPublicKey>;
using SecretKeyPtr = std::shared_ptr<Rust::TWCryptoBoxSecretKey>;

/// Public key used in `crypto_box` cryptography.
struct PublicKey {
explicit PublicKey(PublicKeyPtr ptr): impl(std::move(ptr)) {
}

/// Determines if the given public key is valid or not.
static bool isValid(const Data& bytes);

/// Create a `crypto_box` public key with the given block of data.
static std::optional<PublicKey> fromBytes(const Data& bytes);

/// Returns the raw data of the given public-key.
Data getData() const;

PublicKeyPtr impl;
};

/// Secret key used in `crypto_box` cryptography.
class SecretKey {
public:
/// Create a random secret key.
SecretKey();

/// Returns the public key associated with the given `key`.
PublicKey getPublicKey() const noexcept;

SecretKeyPtr impl;
};

/// Encrypts message using `my_secret` and `other_pubkey`.
/// The output will have a randomly generated nonce prepended to it.
/// The output will be Overhead + 24 bytes longer than the original.
Data encryptEasy(const SecretKey& mySecret, const PublicKey& otherPubkey, const Data& message);

/// Decrypts box produced by `TWCryptoBoxEncryptEasy`.
/// We assume a 24-byte nonce is prepended to the encrypted text in box.
std::optional<Data> decryptEasy(const SecretKey& mySecret, const PublicKey& otherPubkey, const Data& encrypted);

} // namespace TW::CryptoBox

/// Wrapper for C interface.
struct TWCryptoBoxSecretKey {
TW::CryptoBox::SecretKey impl;
};

/// Wrapper for C interface.
struct TWCryptoBoxPublicKey {
TW::CryptoBox::PublicKey impl;
};
23 changes: 23 additions & 0 deletions src/interface/TWCryptoBox.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: Apache-2.0
//
// Copyright © 2017 Trust Wallet.

#include "TrustWalletCore/TWCryptoBox.h"
#include "CryptoBox.h"

using namespace TW;

TWData* _Nonnull TWCryptoBoxEncryptEasy(struct TWCryptoBoxSecretKey* _Nonnull mySecret, struct TWCryptoBoxPublicKey* _Nonnull otherPubkey, TWData* _Nonnull message) {
auto& messageBytes = *reinterpret_cast<const Data*>(message);
auto encrypted = CryptoBox::encryptEasy(mySecret->impl, otherPubkey->impl, messageBytes);
return TWDataCreateWithBytes(encrypted.data(), encrypted.size());
}

TWData* _Nullable TWCryptoBoxDecryptEasy(struct TWCryptoBoxSecretKey* _Nonnull mySecret, struct TWCryptoBoxPublicKey* _Nonnull otherPubkey, TWData* _Nonnull encrypted) {
auto& encryptedBytes = *reinterpret_cast<const Data*>(encrypted);
auto decrypted = CryptoBox::decryptEasy(mySecret->impl, otherPubkey->impl, encryptedBytes);
if (!decrypted) {
return nullptr;
}
return TWDataCreateWithBytes(decrypted->data(), decrypted->size());
}
31 changes: 31 additions & 0 deletions src/interface/TWCryptoBoxPublicKey.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: Apache-2.0
//
// Copyright © 2017 Trust Wallet.

#include "TrustWalletCore/TWCryptoBoxPublicKey.h"
#include "CryptoBox.h"

using namespace TW;

bool TWCryptoBoxPublicKeyIsValid(TWData* _Nonnull data) {
auto& bytes = *reinterpret_cast<const Data*>(data);
return CryptoBox::PublicKey::isValid(bytes);
}

struct TWCryptoBoxPublicKey* _Nullable TWCryptoBoxPublicKeyCreateWithData(TWData* _Nonnull data) {
auto& bytes = *reinterpret_cast<const Data*>(data);
auto publicKey = CryptoBox::PublicKey::fromBytes(bytes);
if (!publicKey) {
return nullptr;
}
return new TWCryptoBoxPublicKey { publicKey.value() };
}

void TWCryptoBoxPublicKeyDelete(struct TWCryptoBoxPublicKey* _Nonnull publicKey) {
delete publicKey;
}

TWData* _Nonnull TWCryptoBoxPublicKeyData(struct TWCryptoBoxPublicKey* _Nonnull publicKey) {
auto bytes = publicKey->impl.getData();
return TWDataCreateWithBytes(bytes.data(), bytes.size());
}
22 changes: 22 additions & 0 deletions src/interface/TWCryptoBoxSecretKey.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: Apache-2.0
//
// Copyright © 2017 Trust Wallet.

#include "TrustWalletCore/TWCryptoBoxSecretKey.h"
#include "CryptoBox.h"

using namespace TW;

struct TWCryptoBoxSecretKey* _Nonnull TWCryptoBoxSecretKeyCreate() {
CryptoBox::SecretKey secretKey;
return new TWCryptoBoxSecretKey { secretKey };
}

void TWCryptoBoxSecretKeyDelete(struct TWCryptoBoxSecretKey* _Nonnull key) {
delete key;
}

struct TWCryptoBoxPublicKey* TWCryptoBoxSecretKeyGetPublicKey(struct TWCryptoBoxSecretKey* _Nonnull key) {
auto publicKey = key->impl.getPublicKey();
return new TWCryptoBoxPublicKey { publicKey };
}
Loading

0 comments on commit aaa336b

Please sign in to comment.