Skip to content
This repository has been archived by the owner on Jun 11, 2022. It is now read-only.

Commit

Permalink
add function to generate random entropy
Browse files Browse the repository at this point in the history
  • Loading branch information
ecioppettini committed Mar 12, 2019
1 parent 3705f4c commit e9962ed
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 37 deletions.
21 changes: 14 additions & 7 deletions cardano-c/cardano.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,14 @@ typedef int cardano_result;
/*********/

/* bip39 error definitions */
enum _bip39_config_error
typedef enum _bip39_config_error
{
SUCCESS = 0,
INVALID_MNEMONIC = 1,
INVALID_CHECKSUM = 2
};
INVALID_CHECKSUM = 2,
INVALID_WORD_COUNT = 3
} cardano_bip39_error_t;

/* type for the API user */
typedef enum _config_error cardano_bip39_error_t;

/* Error descriptions */
struct _errordesc {
Expand All @@ -33,16 +32,24 @@ struct _errordesc {
{ SUCCESS, "No error" },
{ INVALID_MNEMONIC, "Invalid mnemonic word" },
{ INVALID_CHECKSUM, "Invalid checksum" },
{ INVALID_WORD_COUNT, "The word count should be one of: 9, 12, 15, 18, 21, 24"}
};

typedef uint8_t* cardano_entropy;

int cardano_entropy_from_mnemonics(
cardano_bip39_error_t cardano_entropy_from_english_mnemonics(
const char *mnemonics,
cardano_entropy *entropy,
uint32_t *entropy_size
);
void cardano_delete_entropy_array(uint8_t *entropy, size_t bytes);
cardano_bip39_error_t cardano_generate_random_entropy(
uint8_t number_of_words,
uint8_t (*random_generator)(),
cardano_entropy *entropy,
uint32_t *entropy_size
);

void cardano_delete_entropy_array(uint8_t *entropy, uint32_t bytes);

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

Expand Down
68 changes: 41 additions & 27 deletions cardano-c/src/bip39.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ use std::slice;

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

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

use std::ffi::CStr;
Expand All @@ -28,58 +29,71 @@ pub extern "C" fn cardano_bip39_encode(
CardanoResult::success()
}

///
/// Error status:
/// 0: Success
/// 1: The words were not in the english dictionary
/// 2: The checksum was invalid
///
///retrieve the entropy from the given english mnemonics
#[no_mangle]
pub extern "C" fn cardano_entropy_from_mnemonics(
pub extern "C" fn cardano_entropy_from_english_mnemonics(
mnemonics: *const c_char,
entropy_ptr: *mut *const c_uchar,
entropy_size: *mut c_uint
) -> c_int {
) -> 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,
Err(_) => return 1,
//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,
Err(_) => return 2,
//The error happens because the phrase doesn't have a valid checksum
Err(_) => return CardanoBIP39ErrorCode::invalid_checksum(),
};

let mut entropy_vec = match entropy {
bip39::Entropy::Entropy9(arr) => arr.to_vec(),
bip39::Entropy::Entropy12(arr) => arr.to_vec(),
bip39::Entropy::Entropy15(arr) => arr.to_vec(),
bip39::Entropy::Entropy18(arr) => arr.to_vec(),
bip39::Entropy::Entropy21(arr) => arr.to_vec(),
bip39::Entropy::Entropy24(arr) => arr.to_vec(),
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_generate_random_entropy(
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
entropy_vec.shrink_to_fit();
to_return.shrink_to_fit();

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

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

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

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

0
unsafe { ptr::write(out_pointer, pointer) };
}

//Deallocate the rust-allocated memory for a Entropy array
Expand Down
25 changes: 25 additions & 0 deletions cardano-c/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
36 changes: 33 additions & 3 deletions cardano-c/test/test_bip39_entropy.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ void test_generate_entropy_from_mnemonics(void) {

cardano_entropy entropy;
uint32_t bytes;
int error = cardano_entropy_from_mnemonics(mnemonics, &entropy, &bytes);
int 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);
Expand All @@ -19,7 +19,7 @@ void test_generate_entropy_from_mnemonics_error_code_invalid_word(void) {

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

TEST_ASSERT_EQUAL_HEX32(INVALID_MNEMONIC, error);
}
Expand All @@ -29,15 +29,45 @@ void test_generate_entropy_from_mnemonics_invalid_checksum(void) {

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

TEST_ASSERT_EQUAL_HEX32(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_generate_random_entropy(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_generate_random_entropy(NUMBER_OF_WORDS, gen, &entropy, &bytes);

TEST_ASSERT_EQUAL_HEX32(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 e9962ed

Please sign in to comment.