Skip to content
Permalink
Browse files

Merge pull request #519 from atixlabs/IOHKCRB-10-add-functions-to-gen…

…erate-entropy

[IOHKCRB-10] Add functions to generate entropy
  • Loading branch information...
vincenthz committed Mar 15, 2019
2 parents e393f0b + c054867 commit 775263a968d95a4d4fa5e41ca6b78b9e34df60f9
Showing with 234 additions and 0 deletions.
  1. +48 −0 cardano-c/cardano.h
  2. +81 −0 cardano-c/src/bip39.rs
  3. +25 −0 cardano-c/src/types.rs
  4. +8 −0 cardano-c/test.sh
  5. +72 −0 cardano-c/test/test_bip39_entropy.c
@@ -14,6 +14,54 @@ typedef int cardano_result;
/* BIP39 */
/*********/

/* bip39 error definitions */
typedef enum _bip39_config_error
{
BIP39_SUCCESS = 0,
BIP39_INVALID_MNEMONIC = 1,
BIP39_INVALID_CHECKSUM = 2,
BIP39_INVALID_WORD_COUNT = 3
} cardano_bip39_error_t;

typedef uint8_t* cardano_entropy;

/*!
* \brief get entropy array from the given english mnemonics
* \param [in] mnemonics a string consisting of 9, 12, 15, 18, 21 or 24 english words
* \param [out] entropy the returned entropy array
* \param [out] entropy_size the size of the the returned array
* \returns BIP39_SUCCESS or either BIP39_INVALID_MNEMONIC or BIP39_INVALID_CHECKSUM
*/
cardano_bip39_error_t cardano_entropy_from_english_mnemonics(
const char *mnemonics,
cardano_entropy *entropy,
uint32_t *entropy_size
);

/*!
* \brief encode a entropy into its equivalent words represented by their index (0 to 2047) in the BIP39 dictionary
* \param [in] number_of_words one of 9, 12, 15, 18, 21 or 24 representing the number of words of the equivalent mnemonic
* \param [in] random_generator a function that generates random bytes
* \param [out] entropy the returned entropy array
* \param [out] entropy_size the size of the the returned array
* \returns BIP39_SUCCESS or BIP39_INVALID_WORD_COUNT
*/
cardano_bip39_error_t cardano_entropy_from_random(
uint8_t number_of_words,
uint8_t (*random_generator)(),
cardano_entropy *entropy,
uint32_t *entropy_size
);

/*!
* delete the allocated memory of entropy byte array
* \param [in] entropy the entropy array
* \param [in] entropy_size the length of the entropy array
* \sa cardano_entropy_from_random()
* \sa cardano_entropy_from_english_mnemonics()
*/
void cardano_delete_entropy_array(uint8_t *entropy, uint32_t entropy_size);

cardano_result cardano_bip39_encode(const char * const entropy_raw, unsigned long entropy_size, unsigned short *mnemonic_index, unsigned long mnemonic_size);

/*********/
@@ -1,8 +1,16 @@
use std::slice;

use cardano::bip::bip39;
use types::CardanoBIP39ErrorCode;
use types::CardanoResult;

use std::{
os::raw::{c_char, c_uchar, c_uint},
ptr,
};

use std::ffi::CStr;

/// encode a entropy into its equivalent words represented by their index (0 to 2047) in the BIP39 dictionary
#[no_mangle]
pub extern "C" fn cardano_bip39_encode(
@@ -20,3 +28,76 @@ pub extern "C" fn cardano_bip39_encode(
out_slice.copy_from_slice(entropy.to_mnemonics().as_ref());
CardanoResult::success()
}

///retrieve the entropy from the given english mnemonics
#[no_mangle]
pub extern "C" fn cardano_entropy_from_english_mnemonics(
mnemonics: *const c_char,
entropy_ptr: *mut *const c_uchar,
entropy_size: *mut c_uint,
) -> CardanoBIP39ErrorCode {
let rust_string = unsafe { CStr::from_ptr(mnemonics) }.to_string_lossy();

let dictionary = bip39::dictionary::ENGLISH;

let mnemonics = match bip39::Mnemonics::from_string(&dictionary, &rust_string) {
Ok(m) => m,
//The error happens when a word is not in the dictionary
Err(_) => return CardanoBIP39ErrorCode::invalid_word(),
};

let entropy = match bip39::Entropy::from_mnemonics(&mnemonics) {
Ok(e) => e,
//The error happens because the phrase doesn't have a valid checksum
Err(_) => return CardanoBIP39ErrorCode::invalid_checksum(),
};

out_return_vector(entropy.to_vec(), entropy_ptr, entropy_size);

CardanoBIP39ErrorCode::success()
}

///generate entropy from the given random generator
#[no_mangle]
pub extern "C" fn cardano_entropy_from_random(
words: u8,
gen: extern "C" fn() -> c_uchar,
entropy_ptr: *mut *const c_uchar,
entropy_size: *mut c_uint,
) -> CardanoBIP39ErrorCode {
let words = match bip39::Type::from_word_count(words as usize) {
Ok(v) => v,
Err(_) => return CardanoBIP39ErrorCode::invalid_word_count(),
};

let entropy = bip39::Entropy::generate(words, || gen()).to_vec();

out_return_vector(entropy, entropy_ptr, entropy_size);

CardanoBIP39ErrorCode::success()
}

///return C array as an out parameter, the memory must be then deallocated with cardano_delete_entropy_array
fn out_return_vector(mut to_return: Vec<u8>, out_pointer: *mut *const c_uchar, size: *mut c_uint) {
//Make sure the capacity is the same as the length to make deallocation simpler
to_return.shrink_to_fit();

let pointer = to_return.as_mut_ptr();
let length = to_return.len() as u32;

//To avoid running the destructor
std::mem::forget(to_return);

//Write the array length
unsafe { ptr::write(size, length) }

//Copy the pointer to the out parameter
unsafe { ptr::write(out_pointer, pointer) };
}

//Deallocate the rust-allocated memory for a Entropy array
#[no_mangle]
pub extern "C" fn cardano_delete_entropy_array(ptr: *mut c_uchar, size: u32) {
let len = size as usize;
unsafe { drop(Vec::from_raw_parts(ptr, len, len)) };
}
@@ -18,6 +18,31 @@ impl CardanoResult {
}
}

///Struct for representing the possible BIP39 error codes
#[repr(C)]
pub struct CardanoBIP39ErrorCode(c_int);

impl CardanoBIP39ErrorCode {
pub fn success() -> Self {
CardanoBIP39ErrorCode(0)
}

///Error representing a word not in the dictionary
pub fn invalid_word() -> Self {
CardanoBIP39ErrorCode(1)
}

///Error representing that a mnemonic phrase checksum is incorrect
pub fn invalid_checksum() -> Self {
CardanoBIP39ErrorCode(2)
}

///Error representing that the word count is not one of the supported ones
pub fn invalid_word_count() -> Self {
CardanoBIP39ErrorCode(3)
}
}

/// C pointer to an Extended Private Key
pub type XPrvPtr = *mut hdwallet::XPrv;

@@ -24,3 +24,11 @@ echo "######################################################################"
echo ""
echo "######################################################################"
rm test-cardano-c.$$


gcc -o test-cardano-c.$$ -I "${C_ROOT}" "${C_ROOT}test/test_bip39_entropy.c" "${C_ROOT}test/unity/unity.c" "${PROJECT_ROOT}target/debug/libcardano_c.a" -lpthread -lm -ldl
echo "######################################################################"
./test-cardano-c.$$
echo ""
echo "######################################################################"
rm test-cardano-c.$$
@@ -0,0 +1,72 @@
#include "../cardano.h"
#include "unity/unity.h"

void test_generate_entropy_from_mnemonics(void) {
static const char *mnemonics = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";

cardano_entropy entropy;
uint32_t bytes;
cardano_bip39_error_t error = cardano_entropy_from_english_mnemonics(mnemonics, &entropy, &bytes);

uint8_t expected[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
TEST_ASSERT_EQUAL_HEX8_ARRAY(expected, entropy, 16);

cardano_delete_entropy_array(entropy, bytes);
}

void test_generate_entropy_from_mnemonics_error_code_invalid_word(void) {
static const char *mnemonics = "notaword abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";

cardano_entropy entropy;
uint32_t bytes;
cardano_bip39_error_t error = cardano_entropy_from_english_mnemonics(mnemonics, &entropy, &bytes);

TEST_ASSERT_EQUAL_HEX32(BIP39_INVALID_MNEMONIC, error);
}

void test_generate_entropy_from_mnemonics_invalid_checksum(void) {
static const char *mnemonics = "about abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";

cardano_entropy entropy;
uint32_t bytes;
cardano_bip39_error_t error = cardano_entropy_from_english_mnemonics(mnemonics, &entropy, &bytes);

TEST_ASSERT_EQUAL_HEX32(BIP39_INVALID_CHECKSUM, error);
}

uint8_t gen() {
return 1;
}

void test_generate_entropy_from_random_generator(void) {
const uint8_t NUMBER_OF_WORDS = 12;
cardano_entropy entropy;
uint32_t bytes;
cardano_bip39_error_t error = cardano_entropy_from_random(NUMBER_OF_WORDS, gen, &entropy, &bytes);

uint8_t expected[16] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};

TEST_ASSERT_EQUAL(16, bytes);
TEST_ASSERT_EQUAL_HEX8_ARRAY(expected, entropy, 16);

cardano_delete_entropy_array(entropy, bytes);
}

void test_generate_entropy_from_random_generator_word_count_error(void) {
const uint8_t NUMBER_OF_WORDS = 13;
cardano_entropy entropy;
uint32_t bytes;
cardano_bip39_error_t error = cardano_entropy_from_random(NUMBER_OF_WORDS, gen, &entropy, &bytes);

TEST_ASSERT_EQUAL_HEX32(BIP39_INVALID_WORD_COUNT, error);
}

int main(void) {
UNITY_BEGIN();
RUN_TEST(test_generate_entropy_from_mnemonics);
RUN_TEST(test_generate_entropy_from_mnemonics_error_code_invalid_word);
RUN_TEST(test_generate_entropy_from_mnemonics_invalid_checksum);
RUN_TEST(test_generate_entropy_from_random_generator);
RUN_TEST(test_generate_entropy_from_random_generator_word_count_error);
return UNITY_END();
}

0 comments on commit 775263a

Please sign in to comment.
You can’t perform that action at this time.