/*
 * Copyright (C) 2018-2021 Western Digital Corporation or its affiliates
 * Copyright (C) 2017-2018 Wearable, Inc.
 * Copyright (C) 2000-2012 leJOS Contributors
 * Copyright (C) 2000 Jose H. Solorzano and TinyVM Contributors
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 * 
 * This Source Code Form is “Incompatible With Secondary Licenses”,
 * as defined by the Mozilla Public License, v. 2.0.
 */

#include "platform_hooks.h"
#include "state.h"
#include "types.h"
#include "exceptions.h"
#include "classes.h"
#include "specialsignatures.h"
#include "stack.h"

#include <sb_sw_lib.h>
#include <sb_hkdf.h>
#include <ctc.h>
#include <aes_ccm_128.h>

/**
 * Helper macro to convert an argument into a byte array
 * 
 * Defines a uint8_t* data_x for the raw data and a size_t size_x for the length
 */
#define BYTE_ARRAY_EXTRACT(x) Object* data_obj_ ## x = word2obj(argv[x]); \
            uint8_t* data_ ## x = (uint8_t*) jbyte_array(data_obj_ ## x); \
            size_t size_ ## x = nvm_array_size(data_obj_ ## x);


int dispatch_platform_crypt(nvm_state_t* pState, uint16_t signature, STACKWORD argv[], _Bool* taken)
{
#define signature_argv(count) \
    nvm_array_size_t size[count]; \
    uint8_t* array[count]; \
    for (size_t argc = 0; argc < (count); argc++) { \
        Object* object = (Object*)word2obj(argv[argc]); \
        if (object == NULL) { \
            return nvm_throw_new_exception(pState, JAVA_LANG_NULLPOINTEREXCEPTION); \
        } \
        size [argc] = nvm_array_size(object); \
        array[argc] = (uint8_t*)jbyte_array(object); \
    } \
    do {} while (0)

    *taken = 1;
    switch (signature) {
        case xor_4_1B_1B_1B_5V: {
            // IN a1, IN a2, OUT a1 ^ a2
            signature_argv(3);
            if(size[0] == size[1] && size[1] == size[2]) {
                for(int i =0;i<size[0];i++) {
                    array[2][i] = array[0][i] ^ array[1][i];
                }
                break;
            }
            return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
        }
        case ctc_4_1B_1B_5Z: {
            // IN a1, IN a2
            signature_argv(2);
            if(size[0] == size[1]) {
                push_word_cur(pState, nanite_crypto_ctc(array[0], array[1], size[0]));
                break;
            }
            return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
        }
        case hmac_0sha256_0context_0size_4_5I: {
            push_word_cur(pState, (STACKWORD)sizeof(sb_hmac_sha256_state_t));
            break;
        }
        case hmac_0sha256_0init_4_1B_1B_5V: {
            signature_argv(2);
            if (size[0] == sizeof(sb_hmac_sha256_state_t)) {
                sb_hmac_sha256_init((sb_hmac_sha256_state_t*)array[0], (void*)array[1], size[1]);
                break;
            }
            return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
        }
        case hmac_0sha256_0reinit_4_1B_5V: {
            signature_argv(1);
            if (size[0] == sizeof(sb_hmac_sha256_state_t)) {
                sb_hmac_sha256_reinit((sb_hmac_sha256_state_t*)array[0]);
                break;
            }
            return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
        }
        case hmac_0sha256_0update_4_1B_1B_5V: {
            signature_argv(2);
            if (size[0] == sizeof(sb_hmac_sha256_state_t)) {
                sb_hmac_sha256_update((sb_hmac_sha256_state_t*)array[0], (void*)array[1], size[1]);
                break;
            }
            return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
        }
        case hmac_0sha256_0finish_4_1B_1B_5V: {
            signature_argv(2);
            if (size[0] == sizeof(sb_hmac_sha256_state_t) && size[1] == SB_SHA256_SIZE) {
                sb_hmac_sha256_finish((sb_hmac_sha256_state_t*)array[0], array[1]);
                break;
            }
            return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
        }
        case hmac_0drbg_0context_0size_4_5I: {
            push_word_cur(pState, (STACKWORD)sizeof(sb_hmac_drbg_state_t));
            break;
        }
        case hmac_0drbg_0init_4_1B_1B_1B_1B_5I: {
            signature_argv(4);
            if (size[0] == sizeof(sb_hmac_drbg_state_t)) {
                sb_error_t result = sb_hmac_drbg_init((sb_hmac_drbg_state_t*)array[0], array[1], size[1], array[2], size[2], array[3], size[3]);
                push_word_cur(pState, (STACKWORD)result);
                break;
            }
            return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
            
        }
        case hmac_0drbg_0reseed_4_1B_1B_1B_5I: {
            signature_argv(3);
            if (size[0] == sizeof(sb_hmac_drbg_state_t)) {
                sb_error_t result = sb_hmac_drbg_reseed((sb_hmac_drbg_state_t*)array[0], array[1], size[1], array[2], size[2]);
                push_word_cur(pState, (STACKWORD)result);
                break;
            }
            return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
        }
        case hmac_0drbg_0reseed_0required_4_1BI_5I: {
            signature_argv(1);
            if (size[0] == sizeof(sb_hmac_drbg_state_t)) {
                sb_error_t result = sb_hmac_drbg_reseed_required((sb_hmac_drbg_state_t*)array[0], (int)argv[1]);
                push_word_cur(pState, (STACKWORD)result);
                break;
            }
            return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
        }
        case hmac_0drbg_0generate_4_1B_1B_5I: {
            signature_argv(2);
            if (size[0] == sizeof(sb_hmac_drbg_state_t)) {
                sb_error_t result = sb_hmac_drbg_generate_additional_dummy((sb_hmac_drbg_state_t*)array[0], array[1], size[1]);
                push_word_cur(pState, (STACKWORD)result);
                break;
            }
            return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
        }
        case hmac_0drbg_0generate_4_1B_1B_1B_5I: {
            signature_argv(3);
            if (size[0] == sizeof(sb_hmac_drbg_state_t)) {
                const sb_byte_t* const additional[SB_HMAC_DRBG_ADD_VECTOR_LEN] = { array[2], NULL, NULL };
                const size_t additional_len[SB_HMAC_DRBG_ADD_VECTOR_LEN] = { size[2], 0, 0};
                sb_error_t result = sb_hmac_drbg_generate_additional_vec((sb_hmac_drbg_state_t*)array[0], array[1], size[1], additional, additional_len);
                push_word_cur(pState, (STACKWORD)result);
                break;
            }
            return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
        }
        case hmac_0drbg_0generate_4_1B_1B_1B_1B_5I: {
            signature_argv(4);
            if (size[0] == sizeof(sb_hmac_drbg_state_t)) {
                const sb_byte_t* const additional[SB_HMAC_DRBG_ADD_VECTOR_LEN] = { array[2], array[3], NULL };
                const size_t additional_len[SB_HMAC_DRBG_ADD_VECTOR_LEN] = { size[2], size[3], 0};
                sb_error_t result = sb_hmac_drbg_generate_additional_vec((sb_hmac_drbg_state_t*)array[0], array[1], size[1], additional, additional_len);
                push_word_cur(pState, (STACKWORD)result);
                break;
            }
            return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
        }
        case hmac_0drbg_0generate_4_1B_1B_1B_1B_1B_5I: {
            signature_argv(5);
            if (size[0] == sizeof(sb_hmac_drbg_state_t)) {
                const sb_byte_t* const additional[SB_HMAC_DRBG_ADD_VECTOR_LEN] = { array[2], array[3], array[4] };
                const size_t additional_len[SB_HMAC_DRBG_ADD_VECTOR_LEN] = { size[2], size[3], size[4]};
                sb_error_t result = sb_hmac_drbg_generate_additional_vec((sb_hmac_drbg_state_t*)array[0], array[1], size[1], additional, additional_len);
                push_word_cur(pState, (STACKWORD)result);
                break;
            }
            return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
        }
        case sha256_0context_0size_4_5I: {
            push_word_cur(pState, (STACKWORD)sizeof(sb_sha256_state_t));
            break;
        }
        case sha256_0init_4_1B_5V: {
            signature_argv(1);
            if (size[0] == sizeof(sb_sha256_state_t)) {
                sb_sha256_init((sb_sha256_state_t*)array[0]);
                break;
            }
            return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
        }
        case sha256_0update_4_1B_1B_5V: {
            signature_argv(2);
            if (size[0] == sizeof(sb_sha256_state_t)) {
                sb_sha256_update((sb_sha256_state_t*) array[0], array[1], size[1]);
                break;
            }
            return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
        }
        case sha256_0finish_4_1B_1B_5V: {
            signature_argv(2);
            if (size[0] == sizeof(sb_sha256_state_t) && size[1] == SB_SHA256_SIZE) {
                sb_sha256_finish((sb_sha256_state_t*)array[0], array[1]);
                break;
            }
            return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
        }
        case p256_0context_0size_4_5I: {
            push_word_cur(pState, (STACKWORD)sizeof(sb_sw_context_t));
            break;
        }
        case p256_0generate_0private_0key_4_1B_1B_1BZ_5I: {
            // IN context, IN drbg, OUT private key, IN endianness
            signature_argv(3);
            sb_data_endian_t e = SB_DATA_ENDIAN_BIG;
            if (!argv[3]) {
                e = SB_DATA_ENDIAN_LITTLE;
            }
            if (size[0] == sizeof(sb_sw_context_t) && size[1] == sizeof(sb_hmac_drbg_state_t) && size[2] == SB_ELEM_BYTES) {
                push_word_cur(pState, sb_sw_generate_private_key((sb_sw_context_t*) array[0],
                                                       (sb_sw_private_t*) array[2],
                                                       (sb_hmac_drbg_state_t*) array[1],
                                                       SB_SW_CURVE_P256, e));                                    
            } else {
                return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
            }
            break;
        }

        case p256_0validate_0private_0key_4_1B_1BZ_5I: {
            // IN context, IN private key, IN endianness
            signature_argv(2);
            sb_data_endian_t e = SB_DATA_ENDIAN_BIG;
            if (!argv[2]) {
                e = SB_DATA_ENDIAN_LITTLE;
            }
            if (size[0] == sizeof(sb_sw_context_t) && size[1] == SB_ELEM_BYTES) {
                push_word_cur(pState, sb_sw_valid_private_key((sb_sw_context_t*) array[0],
                                                       (sb_sw_private_t*) array[1],
                                                       SB_SW_CURVE_P256, e));                                    
            } else {
                return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
            }
            break;
        }

        case p256_0compute_0public_0key_0start_4_1B_1B_1BZ_5I: {
            // IN context, IN drbg, IN private key, IN endianness
            signature_argv(3);
            sb_data_endian_t e = SB_DATA_ENDIAN_BIG;
            if (!argv[3]) {
                e = SB_DATA_ENDIAN_LITTLE;
            }
            if (size[0] == sizeof(sb_sw_context_t) && size[1] == sizeof(sb_hmac_drbg_state_t) && size[2] == SB_ELEM_BYTES) {
                push_word_cur(pState, sb_sw_compute_public_key_start((sb_sw_context_t*) array[0],
                                                       (sb_sw_private_t*) array[2],
                                                       (sb_hmac_drbg_state_t*)array[1],
                                                       SB_SW_CURVE_P256, e));                                    
            } else {
                return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
            }
            break;
        }

        case p256_0compute_0public_0key_0continue_4_1B_1B_5I: {
            // IN context, OUT done
            signature_argv(2);
            if (size[0] == sizeof(sb_sw_context_t) && size[1] == 1) {
                array[1][0] = 0x00;
                _Bool done;
                sb_error_t err = sb_sw_compute_public_key_continue((sb_sw_context_t*) array[0], &done);  
                if(err == SB_SUCCESS && done) {
                    array[1][0] = 0x01;
                } 
                push_word_cur(pState, err);                                  
            } else {
                return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
            }
            break;
        }
        case p256_0compute_0public_0key_0finish_4_1B_1BZ_5I: {
            // IN context, OUT public key, IN endianness
            signature_argv(2);
            sb_data_endian_t e = SB_DATA_ENDIAN_BIG;
            if (!argv[2]) {
                e = SB_DATA_ENDIAN_LITTLE;
            }
            if (size[0] == sizeof(sb_sw_context_t) && size[1] == SB_ELEM_BYTES * 2) {
                push_word_cur(pState, sb_sw_compute_public_key_finish((sb_sw_context_t*) array[0],
                                                       (sb_sw_public_t*) array[1], e));                                    
            } else {
                return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
            }
            break;
        }

        case p256_0point_0multiply_4_1B_1B_1B_1B_1BZ_5I: {
            // IN context, IN drbg, OUT output, IN private key, IN public key, IN endianness
            signature_argv(5);
            sb_data_endian_t e = SB_DATA_ENDIAN_BIG;
            if (!argv[5]) {
                e = SB_DATA_ENDIAN_LITTLE;
            }
            if (size[0] == sizeof(sb_sw_context_t) && size[1] == sizeof(sb_hmac_drbg_state_t) && size[2] == SB_ELEM_BYTES * 2 
            && size[3] == SB_ELEM_BYTES && size[4] == SB_ELEM_BYTES*2) {
                push_word_cur(pState, sb_sw_point_multiply((sb_sw_context_t*) array[0],
                                                        (sb_sw_public_t*) array[2],
                                                       (sb_sw_private_t*) array[3],
                                                       (sb_sw_public_t*) array[4],
                                                       (sb_hmac_drbg_state_t*)array[1],
                                                       SB_SW_CURVE_P256, e));                                    
            } else {
                return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
            }
            break;
        }

        case p256_0point_0multiply_0start_4_1B_1B_1B_1BZ_5I: {
            // IN context, IN drbg, IN private key, IN public key, IN endianness
            signature_argv(4);
            sb_data_endian_t e = SB_DATA_ENDIAN_BIG;
            if (!argv[4]) {
                e = SB_DATA_ENDIAN_LITTLE;
            }
            if (size[0] == sizeof(sb_sw_context_t) && size[1] == sizeof(sb_hmac_drbg_state_t) 
                    && size[2] == SB_ELEM_BYTES && size[3] == SB_ELEM_BYTES*2) {
                push_word_cur(pState, sb_sw_point_multiply_start((sb_sw_context_t*) array[0],
                                                       (sb_sw_private_t*) array[2],
                                                       (sb_sw_public_t*) array[3],
                                                       (sb_hmac_drbg_state_t*)array[1],
                                                       SB_SW_CURVE_P256, e));                                    
            } else {
                return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
            }
            break;
        }
        case p256_0point_0multiply_0continue_4_1B_1B_5I: {
            // IN context, OUT done
            signature_argv(2);
            if (size[0] == sizeof(sb_sw_context_t) && size[1] == 1) {
                array[1][0] = 0x00;
                _Bool done;
                sb_error_t err = sb_sw_point_multiply_continue((sb_sw_context_t*) array[0], &done);  
                if(err == SB_SUCCESS && done) {
                    array[1][0] = 0x01;
                } 
                push_word_cur(pState, err);                                  
            } else {
                return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
            }
            break;
        }
        case p256_0point_0multiply_0finish_4_1B_1BZ_5I: {
            // IN context, OUT output, IN endianness
            signature_argv(2);
            sb_data_endian_t e = SB_DATA_ENDIAN_BIG;
            if (!argv[2]) {
                e = SB_DATA_ENDIAN_LITTLE;
            }
            if (size[0] == sizeof(sb_sw_context_t) && size[1] == SB_ELEM_BYTES*2) {
                push_word_cur(pState, sb_sw_point_multiply_finish((sb_sw_context_t*) array[0],
                                                       (sb_sw_public_t*) array[1], e));                                    
            } else {
                return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
            }
            break;
        }

        case p256_0shared_0secret_0start_4_1B_1B_1B_1BZ_5I: {
            // IN context, IN drbg, IN public key, IN private key, IN endianness
            signature_argv(4);
            sb_data_endian_t e = SB_DATA_ENDIAN_BIG;
            if (!argv[4]) {
                e = SB_DATA_ENDIAN_LITTLE;
            }
            if (size[0] == sizeof(sb_sw_context_t) && size[1] == sizeof(sb_hmac_drbg_state_t) 
                    && size[2] == SB_ELEM_BYTES * 2 && size[3] == SB_ELEM_BYTES) {
                push_word_cur(pState, sb_sw_shared_secret_start((sb_sw_context_t*) array[0],
                                                       (sb_sw_private_t*) array[3],
                                                       (sb_sw_public_t*) array[2],
                                                       (sb_hmac_drbg_state_t*)array[1],
                                                       SB_SW_CURVE_P256, e));                                    
            } else {
                return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
            }
            break;
        }

        case p256_0shared_0secret_0continue_4_1B_1B_5I: {
            // IN context, OUT done
            signature_argv(2);
            if (size[0] == sizeof(sb_sw_context_t) && size[1] == 1) {
                array[1][0] = 0x00;
                _Bool done;
                sb_error_t err = sb_sw_shared_secret_continue((sb_sw_context_t*) array[0], &done);  
                if(err == SB_SUCCESS && done) {
                    array[1][0] = 0x01;
                } 
                push_word_cur(pState, err);                                  
            } else {
                return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
            }
            break;
        }

        case p256_0shared_0secret_0finish_4_1B_1BZ_5I: {
            // IN context, OUT shared secret, IN endianness
            signature_argv(2);
            sb_data_endian_t e = SB_DATA_ENDIAN_BIG;
            if (!argv[2]) {
                e = SB_DATA_ENDIAN_LITTLE;
            }
            if (size[0] == sizeof(sb_sw_context_t) && size[1] == SB_ELEM_BYTES) {
                push_word_cur(pState, sb_sw_shared_secret_finish((sb_sw_context_t*) array[0],
                                                       (sb_sw_shared_secret_t*) array[1], e));                                    
            } else {
                return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
            }
            break;
        }

        case p256_0sign_0start_4_1B_1B_1B_1BZ_5I: {
            // IN context, IN drbg, IN private key, IN hash, IN endianness
            signature_argv(4);
            sb_data_endian_t e = SB_DATA_ENDIAN_BIG;
            if (!argv[4]) {
                e = SB_DATA_ENDIAN_LITTLE;
            }
            if (size[0] == sizeof(sb_sw_context_t) && size[1] == sizeof(sb_hmac_drbg_state_t) 
                && size[2] == SB_ELEM_BYTES && size[3] == SB_ELEM_BYTES) {
                push_word_cur(pState, sb_sw_sign_message_digest_start((sb_sw_context_t*) array[0],
                                                               (sb_sw_private_t*) array[2],
                                                               (sb_sw_message_digest_t*) array[3],
                                                               (sb_hmac_drbg_state_t*)array[1], 
                                                               SB_SW_CURVE_P256, e));
            } else {
                return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
            }
            break;
        }
        case p256_0sign_0continue_4_1B_1B_5I: {
            // IN context, OUT done
            signature_argv(2);
            if (size[0] == sizeof(sb_sw_context_t) && size[1] == 1) {
                array[1][0] = 0x00;
                _Bool done;
                sb_error_t err = sb_sw_sign_message_digest_continue((sb_sw_context_t*) array[0], &done);  
                if(err == SB_SUCCESS && done) {
                    array[1][0] = 0x01;
                } 
                push_word_cur(pState, err);                                  
            } else {
                return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
            }
            break;
        }
        case p256_0sign_0finish_4_1B_1BZ_5I: {
            // IN context, OUT signature, IN endianness
            signature_argv(2);
            sb_data_endian_t e = SB_DATA_ENDIAN_BIG;
            if (!argv[2]) {
                e = SB_DATA_ENDIAN_LITTLE;
            }
            if (size[0] == sizeof(sb_sw_context_t) && size[1] == SB_ELEM_BYTES * 2) {
                push_word_cur(pState, sb_sw_sign_message_digest_finish((sb_sw_context_t*) array[0],
                                                               (sb_sw_signature_t*) array[1], e));
            } else {
                return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
            }
            break;
        }

        case p256_0verify_0start_4_1B_1B_1B_1B_1BZ_5I: {
            // IN context, IN drbg, IN signature, IN public key, IN hash, IN endianness
            signature_argv(5);
            sb_data_endian_t e = SB_DATA_ENDIAN_BIG;
            if (!argv[5]) {
                e = SB_DATA_ENDIAN_LITTLE;
            }
            if (size[0] == sizeof(sb_sw_context_t) &&
                    size[1] == sizeof(sb_hmac_drbg_state_t) &&
                    size[2] == SB_ELEM_BYTES*2 && size[3] == SB_ELEM_BYTES*2 && size[4] == SB_ELEM_BYTES) {
                push_word_cur(pState, sb_sw_verify_signature_start((sb_sw_context_t*)array[0],
                                         (sb_sw_signature_t*) array[2],
                                         (sb_sw_public_t*) array[3],
                                         (sb_sw_message_digest_t*) array[4],
                                         (sb_hmac_drbg_state_t*)array[1], 
                                        SB_SW_CURVE_P256, e));
            } else {
                return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
            }
            break;
        }
        case p256_0verify_0continue_4_1B_1B_5I: {
            // IN context, OUT done
            signature_argv(2);
            if (size[0] == sizeof(sb_sw_context_t) && size[1] == 1) {
                array[1][0] = 0x00;
                _Bool done;
                sb_error_t err = sb_sw_verify_signature_continue((sb_sw_context_t*) array[0], &done);  
                if(err == SB_SUCCESS && done) {
                    array[1][0] = 0x01;
                } 
                push_word_cur(pState, err);                                  
            } else {
                return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
            }
            break;
        }
        case p256_0verify_0finish_4_1B_5I: {
            // IN context
            signature_argv(1);
            if (size[0] == sizeof(sb_sw_context_t)) {
                push_word_cur(pState, sb_sw_verify_signature_finish((sb_sw_context_t*) array[0]));
            } else {
                return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
            }
            break;
        }

        case p256_0invert_0private_0key_4_1B_1B_1B_1BZ_5I: {
            // IN context, IN drbg, IN private key, OUT private key inverted, IN endianness
            signature_argv(4);
            sb_data_endian_t e = SB_DATA_ENDIAN_BIG;
            if(!argv[4]) {
                e = SB_DATA_ENDIAN_LITTLE;
            }
            if(size[0] == sizeof(sb_sw_context_t) && size[1] == sizeof(sb_hmac_drbg_state_t) && 
                size[2] == SB_ELEM_BYTES && size[3] == SB_ELEM_BYTES) {
                push_word_cur(pState, sb_sw_invert_private_key(  (sb_sw_context_t*)array[0],
                                                                (sb_sw_private_t*) array[3],
                                                                (sb_sw_private_t*) array[2],
                                                                (sb_hmac_drbg_state_t*)array[1], 
                                                                SB_SW_CURVE_P256, e));
            } else {
                return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
            }
            break;
        }
        case p256_0compress_0public_0key_4_1B_1B_1B_1BZ_5I: {
            // IN context, IN public key, OUT sign, OUT compressed public key, IN endianness
            signature_argv(4);
            sb_data_endian_t e = SB_DATA_ENDIAN_BIG;
            if(!argv[4]) {
                e = SB_DATA_ENDIAN_LITTLE;
            }
            _Bool sign;
            
            if(size[0] == sizeof(sb_sw_context_t) && size[1] == SB_ELEM_BYTES*2 && size[2] == 1 && size[3] == SB_ELEM_BYTES) {
                push_word_cur(pState, sb_sw_compress_public_key( (sb_sw_context_t*)array[0],
                                                                (sb_sw_compressed_t*) array[3],
                                                                &sign,
                                                                (sb_sw_public_t*) array[1], SB_SW_CURVE_P256, e));
                array[2][0] = sign ? 0x01 : 0x00;
            } else {
                return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
            }
            break;
        }
        case p256_0decompress_0public_0key_4_1B_1BZ_1BZ_5I: {
             // IN context, IN compressed public key, IN sign, OUT public key, IN endianness
            signature_argv(4);
            sb_data_endian_t e = SB_DATA_ENDIAN_BIG;
            _Bool sign = true;
            if(!argv[4]) {
                e = SB_DATA_ENDIAN_LITTLE;
            }
            if(!argv[3]) {
                sign = false;
            }

            if(size[0] == sizeof(sb_sw_context_t) && size[1] == SB_ELEM_BYTES && size[3] == SB_ELEM_BYTES*2) {
                push_word_cur(pState, sb_sw_decompress_public_key(   (sb_sw_context_t*)array[0],
                                                                    (sb_sw_public_t*) array[3],
                                                                    (sb_sw_compressed_t*) array[1], 
                                                                    sign,
                                                                    SB_SW_CURVE_P256, e));
            } else {
                return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
            }
            break;
        }
        case p256_0wrap_0digest_4_1B_1B_1B_1B_1BZ_5I: {
            // IN context, IN drbg, IN digest, IN private key, OUT wrappedDigest, IN endianness
            signature_argv(5);
            sb_data_endian_t e = SB_DATA_ENDIAN_BIG;
            if (!argv[5]) {
                e = SB_DATA_ENDIAN_LITTLE;
            }
            if (size[0] == sizeof(sb_sw_context_t) && size[1] == sizeof(sb_hmac_drbg_state_t) 
                    && size[2] == SB_ELEM_BYTES && size[3] == SB_ELEM_BYTES && size[4] == SB_ELEM_BYTES) {
                push_word_cur(pState, sb_sw_composite_sign_wrap_message_digest((sb_sw_context_t*) array[0],
                                                       (sb_sw_message_digest_t*)array[4],
                                                       (sb_sw_message_digest_t*)array[2],
                                                       (sb_sw_private_t*) array[3],
                                                       (sb_hmac_drbg_state_t*)array[1],
                                                       SB_SW_CURVE_P256, e));                                    
            } else {
                return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
            }
            break;
        }
        case p256_0unwrap_0signature_4_1B_1B_1B_1BZ_5I: {
            // IN context, IN signature, IN private key, OUT unwrappedSignature, IN endianness
            signature_argv(4);
            sb_data_endian_t e = SB_DATA_ENDIAN_BIG;
            if (!argv[4]) {
                e = SB_DATA_ENDIAN_LITTLE;
            }
            if (size[0] == sizeof(sb_sw_context_t) && size[1] == SB_ELEM_BYTES*2 
                    && size[2] == SB_ELEM_BYTES && size[3] == SB_ELEM_BYTES*2) {
                push_word_cur(pState, sb_sw_composite_sign_unwrap_signature((sb_sw_context_t*) array[0],
                                                       (sb_sw_signature_t*)array[3],
                                                       (sb_sw_signature_t*)array[1],
                                                       (sb_sw_private_t*) array[2],
                                                       SB_SW_CURVE_P256, e));                                    
            } else {
                return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
            }
            break;
        }
        case hkdf_0context_0size_4_5I: {
            push_word_cur(pState, (STACKWORD)sizeof(sb_hkdf_state_t));
            break;
        }
        case hkdf_0extract_4_1B_1B_1B_5V: {
            // IN context, IN salt, IN input
            signature_argv(3);
            if (size[0] == sizeof(sb_hkdf_state_t)) {
                sb_hkdf_extract((sb_hkdf_state_t*)array[0],
                                (const sb_byte_t*)array[1], size[1],
                                (const sb_byte_t*)array[2], size[2]);
                break;
            } else {
                return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
            }
            break;
        }
        case hkdf_0extract_0init_4_1B_1B_5V: {
            // IN context, IN salt
            signature_argv(2);
            if (size[0] == sizeof(sb_hkdf_state_t)) {
                sb_hkdf_extract_init((sb_hkdf_state_t*)array[0],
                                (const sb_byte_t*)array[1], size[1]);
                break;
            } else {
                return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
            }
            break;
        }
        case hkdf_0extract_0update_4_1B_1B_5V: {
            // IN context, IN input
            signature_argv(2);
            if (size[0] == sizeof(sb_hkdf_state_t)) {
                sb_hkdf_extract_update((sb_hkdf_state_t*)array[0],
                                (const sb_byte_t*)array[1], size[1]);
                break;
            } else {
                return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
            }
            break;
        }
        case hkdf_0extract_0finish_4_1B_5V: {
            // IN context
            signature_argv(1);
            if (size[0] == sizeof(sb_hkdf_state_t)) {
                sb_hkdf_extract_finish((sb_hkdf_state_t*)array[0]);
                break;
            } else {
                return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
            }
            break;
        }
        case hkdf_0expand_4_1B_1B_1B_5V: {
            // IN context, IN info, IN output
            signature_argv(3);
            if (size[0] == sizeof(sb_hkdf_state_t)) {
                sb_hkdf_expand((sb_hkdf_state_t*)array[0],
                                (const sb_byte_t*)array[1], size[1],
                                (sb_byte_t*)array[2], size[2]);
                break;
            } else {
                return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
            }
            break;
        }
        case hkdf_0expand_0p256_0private_0key_4_1B_1B_1B_1BZ_5I: {
            // IN context, IN hkdf context, IN info, OUT private key, IN endianness
            signature_argv(4);
            sb_data_endian_t e = SB_DATA_ENDIAN_BIG;
            if(!argv[4]) {
                e = SB_DATA_ENDIAN_LITTLE;
            }

            if(size[0] == sizeof(sb_sw_context_t) && size[1] == sizeof(sb_hkdf_state_t) && size[3] == SB_ELEM_BYTES) {
                push_word_cur(pState, sb_sw_hkdf_expand_private_key( (sb_sw_context_t*)array[0],
                                                                    (sb_sw_private_t*)array[3],
                                                                    (sb_hkdf_state_t*)array[1],
                                                                    (const sb_byte_t*)array[2], size[2], SB_SW_CURVE_P256, e));
            } else {
                return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
            }

            break;
        }
        case aes_0ccm_0128_0context_0size_4_5I: {
            push_word_cur(pState, (STACKWORD)sizeof(aes_ccm_128_state_t));
            break;
        }
        case aes_0ccm_0128_0init_4_1B_1BI_1B_5Z: {
            // INOUT context, IN key, IN micLength, IN nonce
            signature_argv(2);
            BYTE_ARRAY_EXTRACT(3)
            if (size[0] == sizeof(aes_ccm_128_state_t) && size[1] == AES_128_KEY_SIZE && size_3 == AES_CCM_128_NONCE_SIZE) {
                push_word_cur(pState, nanite_crypto_aes_ccm_128_init((aes_ccm_128_state_t*)array[0], array[1], (aes_ccm_128_mic_length_t)argv[2], data_3));
            } else {
                return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
            }
            break;
        }
        case aes_0ccm_0128_0update_0nonce_4_1B_1B_5V: {
            // INOUT context, IN nonce
            signature_argv(2);
            if (size[0] == sizeof(aes_ccm_128_state_t) && size[1] == AES_CCM_128_NONCE_SIZE) {
                nanite_crypto_aes_ccm_128_update_nonce((aes_ccm_128_state_t*)array[0], array[1]);
            } else {
                return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
            }
            break;
        }
        case aes_0ccm_0128_0verify_4_1B_1BI_5Z: {
            // INOUT context, IN data, IN aDataCount
            signature_argv(2);
            if (size[0] == sizeof(aes_ccm_128_state_t)) {
                push_word_cur(pState, nanite_crypto_aes_ccm_128_verify((aes_ccm_128_state_t*)array[0], array[1], size[1], argv[2]));
            } else {
                return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
            }
            break;
        }
        case aes_0ccm_0128_0decrypt_4_1B_1BIII_5Z: {
            // INOUT context, IN data, IN offset, IN length, IN aDataCount
            signature_argv(2);
            if (size[0] == sizeof(aes_ccm_128_state_t)) {
                push_word_cur(pState, nanite_crypto_aes_ccm_128_decrypt((aes_ccm_128_state_t*)array[0], array[1], size[1], argv[2], argv[3], argv[4]));
            } else {
                return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
            }
            break;
        }
        case aes_0ccm_0128_0encrypt_4_1B_1BIII_5Z: {
            // INOUT context, IN data, IN offset, IN length, IN aDataCount
            signature_argv(2);
            if (size[0] == sizeof(aes_ccm_128_state_t)) {
                push_word_cur(pState, nanite_crypto_aes_ccm_128_encrypt((aes_ccm_128_state_t*)array[0], array[1], size[1], argv[2], argv[3], argv[4]));
            } else {
                return nvm_throw_new_exception(pState, JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
            }
            break;
        }
    default:
        *taken = 0;
        break;
    }
    return EXEC_CONTINUE;
#undef sys_success
#undef signature_argv
}
