%module wallycore %{ #include "../include/wally_core.h" #include "../include/wally_address.h" #include "../include/wally_bip32.h" #include "bip32_int.h" #include "../include/wally_bip38.h" #include "../include/wally_bip39.h" #include "../include/wally_crypto.h" #include "../include/wally_script.h" #include "../include/wally_transaction.h" #include "transaction_int.h" #include "../include/wally_elements.h" #include "../internal.h" #include static int check_result(JNIEnv *jenv, int result) { switch (result) { case WALLY_OK: break; case WALLY_EINVAL: SWIG_JavaThrowException(jenv, SWIG_JavaIllegalArgumentException, "Invalid argument"); break; case WALLY_ENOMEM: SWIG_JavaThrowException(jenv, SWIG_JavaOutOfMemoryError, "Out of memory"); break; default: /* WALLY_ERROR */ SWIG_JavaThrowException(jenv, SWIG_JavaRuntimeException, "Failed"); break; } return result; } static int int_cast(JNIEnv *jenv, size_t value) { if (value > INT_MAX) SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Invalid length"); return (int)value; } static uint32_t uint32_cast(JNIEnv *jenv, jlong value) { if (value < 0 || value > UINT_MAX) SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Invalid uint32_t"); return (uint32_t)value; } /* Use a static class to hold our opaque pointers */ #define OBJ_CLASS "com/blockstream/libwally/Wally$Obj" /* Create and return a java object to hold an opaque pointer */ static jobject create_obj(JNIEnv *jenv, void *p, int id) { jclass clazz; jmethodID ctor; if (!(clazz = (*jenv)->FindClass(jenv, OBJ_CLASS))) return NULL; if (!(ctor = (*jenv)->GetMethodID(jenv, clazz, "", "(JI)V"))) return NULL; return (*jenv)->NewObject(jenv, clazz, ctor, (jlong)(uintptr_t)p, id); } /* Fetch an opaque pointer from a java object */ static void *get_obj(JNIEnv *jenv, jobject obj, int id) { jclass clazz; jmethodID getter; void *ret; if (!obj || !(clazz = (*jenv)->GetObjectClass(jenv, obj))) return NULL; getter = (*jenv)->GetMethodID(jenv, clazz, "get_id", "()I"); if (!getter || (*jenv)->CallIntMethod(jenv, obj, getter) != id || (*jenv)->ExceptionOccurred(jenv)) return NULL; getter = (*jenv)->GetMethodID(jenv, clazz, "get", "()J"); if (!getter) return NULL; ret = (void *)(uintptr_t)((*jenv)->CallLongMethod(jenv, obj, getter)); return (*jenv)->ExceptionOccurred(jenv) ? NULL : ret; } static void* get_obj_or_throw(JNIEnv *jenv, jobject obj, int id, const char *name) { void *ret = get_obj(jenv, obj, id); if (!ret) SWIG_JavaThrowException(jenv, SWIG_JavaIllegalArgumentException, name); return ret; } static unsigned char* malloc_or_throw(JNIEnv *jenv, size_t len) { unsigned char *p = (unsigned char *)wally_malloc(len); if (!p) SWIG_JavaThrowException(jenv, SWIG_JavaOutOfMemoryError, "Out of memory"); return p; } static void clear_and_free(void *p, size_t len) { if (p) { wally_bzero(p, len); wally_free(p); } } static jbyteArray create_array(JNIEnv *jenv, const unsigned char* p, size_t len) { jbyteArray ret = (*jenv)->NewByteArray(jenv, len); if (ret) (*jenv)->SetByteArrayRegion(jenv, ret, 0, len, (const jbyte*)p); return ret; } #define member_size(struct_, member) sizeof(((struct struct_ *)0)->member) %} %javaconst(1); %ignore wally_free_string; %ignore wally_bzero; %pragma(java) jniclasscode=%{ private static boolean loadLibrary() { try { System.loadLibrary("wallycore"); return true; } catch (final UnsatisfiedLinkError e) { System.err.println("Native code library failed to load.\n" + e); return false; } } private static final boolean enabled = loadLibrary(); public static boolean isEnabled() { return enabled; } static final class Obj { private final transient long ptr; private final int id; private Obj(final long ptr, final int id) { this.ptr = ptr; this.id = id; } private long get() { return ptr; } private int get_id() { return id; } } %} /* Raise an exception whenever a function fails */ %exception { if (!(*jenv)->ExceptionOccurred(jenv)) { $action check_result(jenv, result); } } /* Don't use our int return value except for exception checking */ %typemap(out) int %{ %} /* Output parameters indicating how many bytes were written/sizes are * converted into return values. */ %typemap(in,noblock=1,numinputs=0) size_t *written(size_t sz) { sz = 0; $1 = ($1_ltype)&sz; } %typemap(in,noblock=1,numinputs=0) size_t *output(size_t sz) { sz = 0; $1 = ($1_ltype)&sz; } %typemap(argout,noblock=1) size_t* { $result = int_cast(jenv, *$1); } /* Output strings are converted to native Java strings and returned */ %typemap(in,noblock=1,numinputs=0) char **output(char *temp = 0) { $1 = &temp; } %typemap(argout,noblock=1) (char **output) { $result = NULL; if ($1 && *$1) { if (!(*jenv)->ExceptionOccurred(jenv)) $result = (*jenv)->NewStringUTF(jenv, *$1); wally_free_string(*$1); } } /* uint32_t input arguments are taken as longs and cast with range checking */ %typemap(in) uint32_t { $1 = uint32_cast(jenv, $input); } /* uint64_t input arguments are taken as longs and cast unchecked. This means * callers need to take care with treating negative values correctly */ %typemap(in) uint64_t { $1 = (uint64_t)($input); } /* Treat uint32_t/uint64_t arrays like strings of ints */ %define %java_int_array(INTTYPE, JNITYPE, JTYPE, GETFN, RELEASEFN) %typemap(jni) (INTTYPE *STRING, size_t LENGTH) "JNITYPE" %typemap(jtype) (INTTYPE *STRING, size_t LENGTH) "JTYPE[]" %typemap(jstype) (INTTYPE *STRING, size_t LENGTH) "JTYPE[]" %typemap(javain) (INTTYPE *STRING, size_t LENGTH) "$javainput" %typemap(freearg) (INTTYPE *STRING, size_t LENGTH) "" %typemap(in) (INTTYPE *STRING, size_t LENGTH) { if (!(*jenv)->ExceptionOccurred(jenv)) { $1 = $input ? (INTTYPE *) JCALL2(GETFN, jenv, $input, 0) : 0; $2 = $input ? (size_t) JCALL1(GetArrayLength, jenv, $input) : 0; } else { $1 = 0; $2 = 0; } } %typemap(argout) (INTTYPE *STRING, size_t LENGTH) { if ($input) JCALL3(RELEASEFN, jenv, $input, (j##JTYPE *)$1, 0); } %enddef %java_int_array(uint32_t, jintArray, int, GetIntArrayElements, ReleaseIntArrayElements) %java_int_array(uint64_t, jlongArray, long, GetLongArrayElements, ReleaseLongArrayElements) /* Input buffers with lengths are passed as arrays */ %apply(char *STRING, size_t LENGTH) { (const unsigned char *abf, size_t abf_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *asset, size_t asset_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *bytes, size_t bytes_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *chain_code, size_t chain_code_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *commitment, size_t commitment_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *extra, size_t extra_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *generator, size_t generator_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *hash160, size_t hash160_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *iv, size_t iv_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *key, size_t key_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *output_abf, size_t output_abf_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *output_asset, size_t output_asset_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *output_generator, size_t output_generator_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *pass, size_t pass_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *parent160, size_t parent160_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *priv_key, size_t priv_key_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *proof, size_t proof_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *pub_key, size_t pub_key_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *salt, size_t salt_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *script, size_t script_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *sig, size_t sig_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *sighash, size_t sighash_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *txhash, size_t txhash) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *vbf, size_t vbf_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *witness, size_t witness_len) }; /* Output buffers */ %apply(char *STRING, size_t LENGTH) { (unsigned char *asset_out, size_t asset_out_len) }; %apply(char *STRING, size_t LENGTH) { (unsigned char *abf_out, size_t abf_out_len) }; %apply(char *STRING, size_t LENGTH) { (unsigned char *bytes_out, size_t len) }; %apply(char *STRING, size_t LENGTH) { (unsigned char *vbf_out, size_t vbf_out_len) }; %apply(uint32_t *STRING, size_t LENGTH) { (const uint32_t *child_path, size_t child_path_len) } %apply(uint32_t *STRING, size_t LENGTH) { (const uint32_t *sighash, size_t sighash_len) } %apply(uint64_t *STRING, size_t LENGTH) { (const uint64_t *values, size_t values_len) } %typemap(in, numinputs=0) uint64_t *value_out (uint64_t val) { val = 0; $1 = ($1_ltype)&val; } %typemap(argout) uint64_t* value_out{ $result = (jlong)*$1; } %typemap(in, numinputs=0) uint64_t *value_out (uint64_t val) { val = 0; $1 = ($1_ltype)&val; } %typemap(argout) uint64_t* value_out{ $result = (jlong)*$1; } /* Opaque types are converted to/from an internal object holder class */ %define %java_opaque_struct(NAME, ID) %typemap(in, numinputs=0) struct NAME **output (struct NAME * w) { w = 0; $1 = ($1_ltype)&w; } %typemap(argout) struct NAME ** { if (*$1) $result = create_obj(jenv, *$1, ID); } %typemap (in) const struct NAME * { $1 = (struct NAME *)get_obj_or_throw(jenv, $input, ID, "NAME"); if (!$1) return $null; } %typemap(jtype) const struct NAME * "Object" %typemap(jni) const struct NAME * "jobject" %enddef /* Change a functions return type to match its output type mapping */ %define %return_decls(FUNC, JTYPE, JNITYPE) %typemap(jstype) int FUNC "JTYPE" %typemap(jtype) int FUNC "JTYPE" %typemap(jni) int FUNC "JNITYPE" %rename("%(strip:[wally_])s") FUNC; %enddef %define %returns_void__(FUNC) %return_decls(FUNC, void, void) %enddef %define %returns_size_t(FUNC) %return_decls(FUNC, int, jint) %enddef %define %returns_uint64(FUNC) %return_decls(FUNC, long, jlong) %enddef %define %returns_string(FUNC) %return_decls(FUNC, String, jstring) %enddef %define %returns_struct(FUNC, STRUCT) %return_decls(FUNC, Object, jobject) %enddef %define %returns_array_(FUNC, ARRAYARG, LENARG, LEN) %return_decls(FUNC, byte[], jbyteArray) %exception FUNC { int skip = 0; jresult = NULL; if (!jarg ## ARRAYARG) { arg ## LENARG = LEN; arg ## ARRAYARG = malloc_or_throw(jenv, LEN); if (!arg ## ARRAYARG) skip = 1; /* Exception set by malloc_or_throw */ } if (!skip && !(*jenv)->ExceptionOccurred(jenv)) { $action if (check_result(jenv, result) == WALLY_OK && !jarg ## ARRAYARG) jresult = create_array(jenv, arg ## ARRAYARG, LEN); } if (!jarg ## ARRAYARG) clear_and_free(arg ## ARRAYARG, LEN); } %enddef /* Our wrapped opaque types */ %java_opaque_struct(words, 1) %java_opaque_struct(ext_key, 2) %java_opaque_struct(wally_tx_witness_stack, 3); %java_opaque_struct(wally_tx_input, 4); %java_opaque_struct(wally_tx_output, 5); %java_opaque_struct(wally_tx, 6); /* Our wrapped functions return types */ %returns_void__(bip32_key_free); %returns_struct(bip32_key_from_base58_alloc, ext_key); %rename("bip32_key_from_base58") bip32_key_from_base58_alloc; %returns_struct(bip32_key_from_parent_alloc, ext_key); %rename("bip32_key_from_parent") bip32_key_from_parent_alloc; %returns_struct(bip32_key_from_parent_path_alloc, ext_key); %rename("bip32_key_from_parent_path") bip32_key_from_parent_path_alloc; %returns_struct(bip32_key_from_seed_alloc, ext_key); %rename("bip32_key_from_seed") bip32_key_from_seed_alloc; %returns_array_(bip32_key_get_chain_code, 2, 3, member_size(ext_key, chain_code)); %returns_size_t(bip32_key_get_child_num); %returns_size_t(bip32_key_get_depth); %returns_array_(bip32_key_get_hash160, 2, 3, member_size(ext_key, hash160)); %returns_array_(bip32_key_get_parent160, 2, 3, member_size(ext_key, parent160)); %returns_array_(bip32_key_get_priv_key, 2, 3, member_size(ext_key, priv_key) - 1); %returns_array_(bip32_key_get_pub_key, 2, 3, member_size(ext_key, pub_key)); %returns_size_t(bip32_key_get_version); %returns_struct(bip32_key_init_alloc, ext_key); %rename("bip32_key_init") bip32_key_init_alloc; %returns_array_(bip32_key_serialize, 3, 4, BIP32_SERIALIZED_LEN); %returns_string(bip32_key_to_base58); %returns_struct(bip32_key_unserialize_alloc, ext_key); %rename("bip32_key_unserialize") bip32_key_unserialize_alloc; %returns_array_(bip38_raw_from_private_key, 6, 7, BIP38_SERIALIZED_LEN); %returns_string(bip38_from_private_key); %returns_array_(bip38_raw_to_private_key, 6, 7, 32); %returns_array_(bip38_to_private_key, 5, 6, 32); %returns_size_t(bip38_raw_get_flags); %returns_size_t(bip38_get_flags); %returns_string(bip39_get_languages); %returns_struct(bip39_get_wordlist, words); %returns_string(bip39_get_word); %returns_string(bip39_mnemonic_from_bytes); %returns_size_t(bip39_mnemonic_to_bytes); %returns_void__(bip39_mnemonic_validate); %returns_size_t(bip39_mnemonic_to_seed); %returns_string(wally_addr_segwit_from_bytes); %returns_size_t(wally_addr_segwit_to_bytes); %returns_array_(wally_aes, 6, 7, AES_BLOCK_LEN); %returns_size_t(wally_aes_cbc); %returns_array_(wally_asset_final_vbf, 8, 9, ASSET_TAG_LEN); %returns_array_(wally_asset_generator_from_bytes, 5, 6, ASSET_GENERATOR_LEN); %returns_size_t(wally_asset_rangeproof); %returns_size_t(wally_asset_surjectionproof_size); %returns_size_t(wally_asset_surjectionproof); %returns_uint64(wally_asset_unblind); %returns_array_(wally_asset_value_commitment, 6, 7, ASSET_COMMITMENT_LEN); %returns_string(wally_base58_from_bytes); %returns_size_t(wally_base58_to_bytes); %returns_size_t(wally_base58_get_length); %returns_void__(wally_ec_private_key_verify); %returns_array_(wally_ec_public_key_decompress, 3, 4, EC_PUBLIC_KEY_UNCOMPRESSED_LEN); %returns_array_(wally_ec_public_key_from_private_key, 3, 4, EC_PUBLIC_KEY_LEN); %returns_array_(wally_ec_sig_from_bytes, 6, 7, EC_SIGNATURE_LEN); %returns_array_(wally_ec_sig_normalize, 3, 4, EC_SIGNATURE_LEN); %returns_array_(wally_ec_sig_from_der, 3, 4, EC_SIGNATURE_LEN); %returns_size_t(wally_ec_sig_to_der); %returns_void__(wally_ec_sig_verify); %returns_size_t(wally_format_bitcoin_message); %returns_array_(wally_hash160, 3, 4, HASH160_LEN); %returns_string(wally_hex_from_bytes); %returns_size_t(wally_hex_to_bytes); %returns_array_(wally_hmac_sha256, 5, 6, HMAC_SHA256_LEN); %returns_array_(wally_hmac_sha512, 5, 6, HMAC_SHA512_LEN); %returns_void__(wally_init); %returns_array_(wally_pbkdf2_hmac_sha256, 7, 8, PBKDF2_HMAC_SHA256_LEN); %returns_array_(wally_pbkdf2_hmac_sha512, 7, 8, PBKDF2_HMAC_SHA512_LEN); %returns_size_t(wally_script_push_from_bytes); %returns_size_t(wally_scriptpubkey_csv_2of2_then_1_from_bytes); %returns_size_t(wally_scriptpubkey_csv_2of3_then_2_from_bytes); %returns_size_t(wally_scriptpubkey_get_type); %returns_size_t(wally_scriptpubkey_op_return_from_bytes); %returns_size_t(wally_scriptpubkey_p2pkh_from_bytes); %returns_size_t(wally_scriptpubkey_p2sh_from_bytes); %returns_size_t(wally_scriptpubkey_multisig_from_bytes); %returns_size_t(wally_scriptsig_p2pkh_from_sig); %returns_size_t(wally_scriptsig_p2pkh_from_der); %returns_size_t(wally_scriptsig_multisig_from_bytes); %returns_void__(wally_scrypt); %returns_void__(wally_secp_randomize); %returns_array_(wally_sha256, 3, 4, SHA256_LEN); %returns_array_(wally_sha256d, 3, 4, SHA256_LEN); %returns_array_(wally_sha512, 3, 4, SHA512_LEN); %returns_void__(wally_tx_add_input); %returns_void__(wally_tx_add_raw_input); %returns_void__(wally_tx_add_output); %returns_void__(wally_tx_add_raw_output); %returns_void__(wally_tx_free); %returns_struct(wally_tx_from_bytes, wally_tx); %returns_struct(wally_tx_from_hex, wally_tx); %returns_array_(wally_tx_get_btc_signature_hash, 8, 9, SHA256_LEN); %returns_size_t(wally_tx_get_length); %returns_array_(wally_tx_get_signature_hash, 12, 13, SHA256_LEN); %returns_size_t(wally_tx_get_vsize); %returns_size_t(wally_tx_get_weight); %returns_size_t(wally_tx_get_witness_count); %returns_struct(wally_tx_init_alloc, wally_tx); %returns_void__(wally_tx_input_free); %returns_struct(wally_tx_input_init_alloc, wally_tx_input); %returns_void__(wally_tx_output_free); %returns_struct(wally_tx_output_init_alloc, wally_tx_output); %returns_void__(wally_tx_remove_input); %returns_void__(wally_tx_remove_output); %returns_void__(wally_tx_set_input_script); %returns_void__(wally_tx_set_input_witness); %returns_size_t(wally_tx_to_bytes); %returns_string(wally_tx_to_hex); %returns_size_t(wally_tx_vsize_from_weight); %returns_void__(wally_tx_witness_stack_add); %returns_void__(wally_tx_witness_stack_add_dummy); %returns_void__(wally_tx_witness_stack_free); %returns_struct(wally_tx_witness_stack_init_alloc, wally_tx_witness_stack); %returns_void__(wally_tx_witness_stack_set); %returns_void__(wally_tx_witness_stack_set_dummy); %returns_string(wally_wif_from_bytes); %returns_size_t(wally_wif_to_bytes); %returns_size_t(wally_wif_is_uncompressed); %returns_size_t(wally_wif_to_public_key); %returns_string(wally_wif_to_address); %returns_size_t(wally_witness_program_from_bytes); %returns_size_t(wally_tx_is_elements); %returns_size_t(wally_tx_is_coinbase); %include "../include/wally_core.h" %include "../include/wally_address.h" %include "../include/wally_bip32.h" %include "bip32_int.h" %include "../include/wally_bip38.h" %include "../include/wally_bip39.h" %include "../include/wally_crypto.h" %include "../include/wally_script.h" %include "../include/wally_transaction.h" %include "transaction_int.h" %include "../include/wally_elements.h"