*/

static int
kex_method_curve25519_key_exchange
(LIBSSH2_SESSION * session, key_exchange_state_low_t * key_state)
{
    int ret = 0;
    int rc = 0;

    if(key_state->state == libssh2_NB_state_idle) {

        key_state->public_key_oct = NULL;
        key_state->state = libssh2_NB_state_created;
    }

    if( key_state->state == libssh2_NB_state_created ) {
        unsigned char *s = NULL;

        rc = strcmp(session->kex->name, "curve25519-sha256@libssh.org");
        if( rc != 0 )
            rc = strcmp(session->kex->name, "curve25519-sha256");

        if( rc != 0) {
            ret = _libssh2_error(session, -1,
                                 "Unknown KEX curve25519 curve type");
            goto clean_exit;
        }

        rc = _libssh2_curve25519_new(session, NULL, &key_state->curve25519_public_key,
                                     &key_state->curve25519_private_key);

        if( rc != 0 )
        {
            ret = _libssh2_error(session, rc,
                                 "Unable to create private key");
            goto clean_exit;
        }

        key_state->request[0] = SSH2_MSG_KEX_ECDH_INIT;
        s = key_state->request + 1;
        _libssh2_store_str(&s, (const char*)key_state->curve25519_public_key, LIBSSH2_ED25519_KEY_LEN);
        key_state->request_len = LIBSSH2_ED25519_KEY_LEN + 5;

        _libssh2_debug(session, LIBSSH2_TRACE_KEX,
                        "Initiating curve25519 SHA2");

        key_state->state = libssh2_NB_state_sent;
    }

    if( key_state->state == libssh2_NB_state_sent) {
        rc = _libssh2_transport_send(session, key_state->request,
                                     key_state->request_len, NULL, 0);
        if(rc == LIBSSH2_ERROR_EAGAIN) {
            return rc;
        } else if(rc) {
            ret = _libssh2_error(session, rc,
                                 "Unable to send ECDH_INIT");
            goto clean_exit;
        }

        key_state->state = libssh2_NB_state_sent1;
    }

    if( key_state->state == libssh2_NB_state_sent1) {
        rc = _libssh2_packet_require(session, SSH2_MSG_KEX_ECDH_REPLY,
                                     &key_state->data, &key_state->data_len,
                                     0, NULL, 0, &key_state->req_state);
        if(rc == LIBSSH2_ERROR_EAGAIN) {
            return rc;
        } else if(rc) {
            ret = _libssh2_error(session, rc,
                                 "Timeout waiting for ECDH_REPLY reply");
            goto clean_exit;
        }

        key_state->state = libssh2_NB_state_sent2;
    }

    if( key_state->state == libssh2_NB_state_sent2) {

        ret = curve25519_sha256(session, key_state->data, key_state->data_len,
                key_state->curve25519_public_key, key_state->curve25519_private_key,
                &key_state->exchange_state);

        if(ret == LIBSSH2_ERROR_EAGAIN) {
            return ret;
        }

        LIBSSH2_FREE(session, key_state->data);
    }

clean_exit:

    if (key_state->curve25519_public_key) {
        _libssh2_explicit_zero(key_state->curve25519_public_key, LIBSSH2_ED25519_KEY_LEN);
        LIBSSH2_FREE(session, key_state->curve25519_public_key);
        key_state->curve25519_public_key = NULL;
    }

    if ( key_state->curve25519_private_key ) {
        _libssh2_explicit_zero(key_state->curve25519_private_key, LIBSSH2_ED25519_KEY_LEN);
        LIBSSH2_FREE(session, key_state->curve25519_private_key);
        key_state->curve25519_private_key = NULL;
    }

    key_state->state = libssh2_NB_state_idle;