void galera::WriteSet::append_key(const KeyData& kd)
{
    KeyOS key (kd.proto_ver,
               kd.parts,
               kd.parts_num,
               (kd.shared() ? galera::KeyOS::F_SHARED : 0)
               );

    const size_t hash(key.hash());

    std::pair<KeyRefMap::const_iterator, KeyRefMap::const_iterator>
        range(key_refs_.equal_range(hash));

    for (KeyRefMap::const_iterator i(range.first); i != range.second; ++i)
    {
        KeyOS cmp(version_);

        (void)cmp.unserialize(&keys_[0], keys_.size(), i->second);

        if (key == cmp && key.flags() == cmp.flags()) return;
    }

    size_t key_size(key.serial_size());
    size_t offset(keys_.size());
    keys_.resize(offset + key_size);
    (void)key.serialize(&keys_[0], keys_.size(), offset);
    (void)key_refs_.insert(std::make_pair(hash, offset));
}
Beispiel #2
0
/**
 * nurs_output_size - obtain output key size
 * \param output output passed by callback param or get by nurs_get_output()
 * \param idx index in nurs_output_def
 *
 * This function returns the output key size specified by idx.
 * On error, it returns 0 and errno is appropriately set.
 */
uint32_t nurs_output_size(const struct nurs_output *output, uint16_t idx)
{
	if (idx >= output->len) {
		errno = ERANGE;
		return 0;
	}
	return key_size(&output->keys[idx]);
}
Beispiel #3
0
void
describe_key(const char *msg, Key *key, const char *comment)
{
	char *fp;

	fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
	if (!quiet)
		printf("%s: %u %s %s\n", msg, key_size(key), fp, comment);
	xfree(fp);
}
Beispiel #4
0
/**
 * nurs_input_size - obtain input key size
 * \param input input passed by callback param
 * \param idx index in nurs_input_def
 *
 * This function returns the input key size specified by idx.
 * On error, it returns 0 and errno is appropriately set.
 */
uint32_t nurs_input_size(const struct nurs_input *input, uint16_t idx)
{
	if (idx >= input->len) {
		errno = ERANGE;
		return 0;
	}
	if (!input->keys[idx]) {
		errno = ENOENT;
		return 0;
	}
	return key_size(input->keys[idx]);
}
Beispiel #5
0
int
hostfile_read_key(char **cpp, u_int *bitsp, Key *ret)
{
	char *cp;

	/* Skip leading whitespace. */
	for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++)
		;

	if (key_read(ret, &cp) != 1)
		return 0;

	/* Skip trailing whitespace. */
	for (; *cp == ' ' || *cp == '\t'; cp++)
		;

	/* Return results. */
	*cpp = cp;
	*bitsp = key_size(ret);
	return 1;
}
Beispiel #6
0
static void output(ErlDrvData handle, char *buf, int len) {
  bloom_drv_t *driver = (bloom_drv_t *)handle;
  char command = buf[0];
  
  switch (command) {
    case SETUP:
    setup(driver, &buf[1], len-1);
    break;
    case PUT:
    put(driver, &buf[1], len-1);
    break;
    case HAS:
    has(driver, &buf[1], len-1);
    break;
    case MEM_SIZE:
    mem_size(driver);
    break;
    case KEY_SIZE:
    key_size(driver);
    break;
  }
}
Beispiel #7
0
static char *
key_fingerprint_randomart(u_char *dgst_raw, u_int dgst_raw_len, const Key *k)
{
	/*
	 * Chars to be used after each other every time the worm
	 * intersects with itself.  Matter of taste.
	 */
	char	*augmentation_string = " .o+=*BOX@%&#/^SE";
	char	*retval, *p;
	unsigned char	 field[FLDSIZE_X][FLDSIZE_Y];
	unsigned int	 i, b;
	int	 x, y;
	size_t	 len = strlen(augmentation_string) - 1;

	retval = calloc(1, (FLDSIZE_X + 3 + 1) * (FLDSIZE_Y + 2));

	/* initialize field */
	memset(field, 0, FLDSIZE_X * FLDSIZE_Y * sizeof(char));
	x = FLDSIZE_X / 2;
	y = FLDSIZE_Y / 2;

	/* process raw key */
	for (i = 0; i < dgst_raw_len; i++) {
		int input;
		/* each byte conveys four 2-bit move commands */
		input = dgst_raw[i];
		for (b = 0; b < 4; b++) {
			/* evaluate 2 bit, rest is shifted later */
			x += (input & 0x1) ? 1 : -1;
			y += (input & 0x2) ? 1 : -1;

			/* assure we are still in bounds */
			x = max(x, 0);
			y = max(y, 0);
			x = min(x, FLDSIZE_X - 1);
			y = min(y, FLDSIZE_Y - 1);

			/* augment the field */
			field[x][y]++;
			input = input >> 2;
		}
	}

	/* mark starting point and end point*/
	field[FLDSIZE_X / 2][FLDSIZE_Y / 2] = len - 1;
	field[x][y] = len;

	/* fill in retval */
	_snprintf_s(retval, FLDSIZE_X, _TRUNCATE, "+--[%4s %4u]", ssh_key_type(k->type), key_size(k));
	p = strchr(retval, '\0');

	/* output upper border */
	for (i = p - retval - 1; i < FLDSIZE_X; i++)
		*p++ = '-';
	*p++ = '+';
	*p++ = '\r';
	*p++ = '\n';

	/* output content */
	for (y = 0; y < FLDSIZE_Y; y++) {
		*p++ = '|';
		for (x = 0; x < FLDSIZE_X; x++)
			*p++ = augmentation_string[min(field[x][y], len)];
		*p++ = '|';
		*p++ = '\r';
		*p++ = '\n';
	}

	/* output lower border */
	*p++ = '+';
	for (i = 0; i < FLDSIZE_X; i++)
		*p++ = '-';
	*p++ = '+';

	return retval;
}
Beispiel #8
0
static int
sc_read_pubkey(Key * k)
{
	u_char buf[2], *n;
	char *p;
	int len, sw, status = -1;

	len = sw = 0;
	n = NULL;

	if (sc_fd < 0) {
		if (sc_init() < 0)
			goto err;
	}

	/* get key size */
	sectok_apdu(sc_fd, CLA_SSH, INS_GET_KEYLENGTH, 0, 0, 0, NULL,
	    sizeof(buf), buf, &sw);
	if (!sectok_swOK(sw)) {
		error("could not obtain key length: %s", sectok_get_sw(sw));
		goto err;
	}
	len = (buf[0] << 8) | buf[1];
	len /= 8;
	debug("INS_GET_KEYLENGTH: len %d sw %s", len, sectok_get_sw(sw));

	n = xmalloc(len);
	/* get n */
	sectok_apdu(sc_fd, CLA_SSH, INS_GET_PUBKEY, 0, 0, 0, NULL, len, n, &sw);

	if (sw == 0x6982) {
		if (try_AUT0() < 0)
			goto err;
		sectok_apdu(sc_fd, CLA_SSH, INS_GET_PUBKEY, 0, 0, 0, NULL, len, n, &sw);
	}
	if (!sectok_swOK(sw)) {
		error("could not obtain public key: %s", sectok_get_sw(sw));
		goto err;
	}

	debug("INS_GET_KEYLENGTH: sw %s", sectok_get_sw(sw));

	if (BN_bin2bn(n, len, k->rsa->n) == NULL) {
		error("c_read_pubkey: BN_bin2bn failed");
		goto err;
	}

	/* currently the java applet just stores 'n' */
	if (!BN_set_word(k->rsa->e, 35)) {
		error("c_read_pubkey: BN_set_word(e, 35) failed");
		goto err;
	}

	status = 0;
	p = key_fingerprint(k, SSH_FP_MD5, SSH_FP_HEX);
	debug("fingerprint %u %s", key_size(k), p);
	xfree(p);

err:
	if (n != NULL)
		xfree(n);
	sc_close();
	return status;
}
Beispiel #9
0
//static char * key_fingerprint_randomart(ut8 *dgst_raw, ut32 dgst_raw_len) {
R_API char * r_print_randomart(const ut8 *dgst_raw, ut32 dgst_raw_len, ut64 addr) {
	/*
	 * Chars to be used after each other every time the worm
	 * intersects with itself.  Matter of taste.
	 */
	char	*augmentation_string = " .o+=*BOX@%&#/^SE";
	char	*retval, *p;
	ut8	 field[FLDSIZE_X][FLDSIZE_Y];
	ut32	 i, b;
	int	 x, y;
	size_t	 len = strlen(augmentation_string) - 1;

	retval = malloc((FLDSIZE_X + 3) * (FLDSIZE_Y + 2));

	/* initialize field */
	memset(field, 0, FLDSIZE_X * FLDSIZE_Y * sizeof(char));
	x = FLDSIZE_X / 2;
	y = FLDSIZE_Y / 2;

	/* process raw key */
	for (i = 0; i < dgst_raw_len; i++) {
		int input;
		/* each byte conveys four 2-bit move commands */
		input = dgst_raw[i];
		for (b = 0; b < 4; b++) {
			/* evaluate 2 bit, rest is shifted later */
			x += (input & 0x1) ? 1 : -1;
			y += (input & 0x2) ? 1 : -1;

			/* assure we are still in bounds */
			x = R_MAX(x, 0);
			y = R_MAX(y, 0);
			x = R_MIN(x, FLDSIZE_X - 1);
			y = R_MIN(y, FLDSIZE_Y - 1);

			/* augment the field */
			if (field[x][y] < len - 2)
				field[x][y]++;
			input = input >> 2;
		}
	}

	/* mark starting point and end point*/
	field[FLDSIZE_X / 2][FLDSIZE_Y / 2] = len - 1;
	field[x][y] = len;

	/* fill in retval */
#if 0
	snprintf(retval, FLDSIZE_X, "+--[%4s %4u]", key_type(k), key_size(k));
#else
	//strcpy (retval, "+-------------");
	sprintf (retval, "+--[0x%08"PFMT64x"]-", addr);
#endif
	p = strchr(retval, '\0');

	/* output upper border */
	for (i = p - retval - 1; i < FLDSIZE_X; i++)
		*p++ = '-';
	*p++ = '+';
	*p++ = '\n';

	/* output content */
	for (y = 0; y < FLDSIZE_Y; y++) {
		*p++ = '|';
		for (x = 0; x < FLDSIZE_X; x++)
			*p++ = augmentation_string[R_MIN(field[x][y], len)];
		*p++ = '|';
		*p++ = '\n';
	}

	/* output lower border */
	*p++ = '+';
	for (i = 0; i < FLDSIZE_X; i++)
		*p++ = '-';
	*p++ = '+';
	*p++ = 0;

	return retval;
}
Beispiel #10
0
// kssl_operate: create a serialized response from a KSSL request
// header and payload
kssl_error_code kssl_operate(kssl_header *header,
                             BYTE *payload,
                             pk_list privates,
                             BYTE **out_response,
                             int *out_response_len) {
  kssl_error_code err = KSSL_ERROR_NONE;
  BYTE *local_resp = NULL;
  int local_resp_len = 0;

  // Parse the indices of the items out of the payload
  kssl_header out_header;
  kssl_operation request;
  kssl_operation response;
  BYTE *out_payload = NULL;
  zero_operation(&request);
  zero_operation(&response);

  *out_response = 0;
  *out_response_len = 0;

  // Extract the items from the payload
  err = parse_message_payload(payload, header->length, &request);
  if (err != KSSL_ERROR_NONE) {
    goto exit;
  }

  if (silent == 0) {
    log_operation(header, &request);
  }

  switch (request.opcode) {
    // Other side sent response, error or pong: unexpected
    case KSSL_OP_RESPONSE:
    case KSSL_OP_ERROR:
    case KSSL_OP_PONG:
    {
      err = KSSL_ERROR_UNEXPECTED_OPCODE;
      break;
    }

    // Echo is trivial, it just echos the complete state->header back
    // including the payload item
    case KSSL_OP_PING:
    {
      response.is_payload_set = 1;
      response.payload = request.payload;
      response.payload_len = request.payload_len;
      response.is_opcode_set = 1;
      response.opcode = KSSL_OP_PONG;

      break;
    }

    // Decrypt or sign the payload using the private key
    case KSSL_OP_RSA_DECRYPT:
    case KSSL_OP_RSA_SIGN_MD5SHA1:
    case KSSL_OP_RSA_SIGN_SHA1:
    case KSSL_OP_RSA_SIGN_SHA224:
    case KSSL_OP_RSA_SIGN_SHA256:
    case KSSL_OP_RSA_SIGN_SHA384:
    case KSSL_OP_RSA_SIGN_SHA512:
    {
      unsigned int payload_size;
      int max_payload_size;
      int key_id;

      if (request.is_digest_set == 0) {
        err = KSSL_ERROR_FORMAT;
        break;
      }

      // Identify private key from request digest
      key_id = find_private_key(privates, request.digest);
      if (key_id < 0) {
        err = KSSL_ERROR_KEY_NOT_FOUND;
        break;
      }

      // Allocate buffer to hold output of private key operation
      max_payload_size = key_size(privates, key_id);
      out_payload = malloc(max_payload_size);
      if (out_payload == NULL) {
        err = KSSL_ERROR_INTERNAL;
        break;
      }

      // Operate on payload
      err = private_key_operation(privates, key_id, request.opcode,
          request.payload_len, request.payload, out_payload,
          &payload_size);
      if (err != KSSL_ERROR_NONE) {
        err = KSSL_ERROR_CRYPTO_FAILED;
        break;
      }

      response.is_payload_set = 1;
      response.payload        = out_payload;
      response.payload_len    = payload_size;
      response.is_opcode_set  = 1;
      response.opcode         = KSSL_OP_RESPONSE;

      break;
    }

    // This should not occur
  default:
    {
      err = KSSL_ERROR_BAD_OPCODE;
      break;
    }
  }

exit:
  if (err != KSSL_ERROR_NONE) {
    err = kssl_error(header->id, err, &local_resp, &local_resp_len);
  } else {

    // Create output header

    out_header.version_maj = KSSL_VERSION_MAJ;
    out_header.version_min = KSSL_VERSION_MIN;
    out_header.id          = header->id;

    // Note that the response in &local_resp is dynamically allocated
    // and needs to be freed

    err = flatten_operation(&out_header, &response, &local_resp,
        &local_resp_len);
  }

  if (out_payload != NULL) {
    free(out_payload);
  }

  if (err == KSSL_ERROR_NONE) {
    *out_response = local_resp;
    *out_response_len = local_resp_len;
  }

  return err;
}
static int
sc_read_pubkey(Key * k, const struct sc_pkcs15_object *cert_obj)
{
	int r;
	sc_pkcs15_cert_t *cert = NULL;
	struct sc_priv_data *priv = NULL;
	sc_pkcs15_cert_info_t *cinfo = cert_obj->data;

	X509 *x509 = NULL;
	EVP_PKEY *pubkey = NULL;
	u8 *p;
	char *tmp;

	debug("sc_read_pubkey() with cert id %02X", cinfo->id.value[0]);
	r = sc_pkcs15_read_certificate(p15card, cinfo, &cert);
	if (r) {
		logit("Certificate read failed: %s", sc_strerror(r));
		goto err;
	}
	x509 = X509_new();
	if (x509 == NULL) {
		r = -1;
		goto err;
	}
	p = cert->data;
	if (!d2i_X509(&x509, &p, cert->data_len)) {
		logit("Unable to parse X.509 certificate");
		r = -1;
		goto err;
	}
	sc_pkcs15_free_certificate(cert);
	cert = NULL;
	pubkey = X509_get_pubkey(x509);
	X509_free(x509);
	x509 = NULL;
	if (pubkey->type != EVP_PKEY_RSA) {
		logit("Public key is of unknown type");
		r = -1;
		goto err;
	}
	k->rsa = EVP_PKEY_get1_RSA(pubkey);
	EVP_PKEY_free(pubkey);

	k->rsa->flags |= RSA_FLAG_SIGN_VER;
	RSA_set_method(k->rsa, sc_get_rsa_method());
	priv = xmalloc(sizeof(struct sc_priv_data));
	priv->cert_id = cinfo->id;
	priv->ref_count = 1;
	RSA_set_app_data(k->rsa, priv);

	k->flags = KEY_FLAG_EXT;
	tmp = key_fingerprint(k, SSH_FP_MD5, SSH_FP_HEX);
	debug("fingerprint %d %s", key_size(k), tmp);
	xfree(tmp);

	return 0;
err:
	if (cert)
		sc_pkcs15_free_certificate(cert);
	if (pubkey)
		EVP_PKEY_free(pubkey);
	if (x509)
		X509_free(x509);
	return r;
}
Beispiel #12
0
int main(int argc, char *argv[]) {
    #ifdef TEST
        test();
        return 0;
    #endif
    #ifdef REPAIR
        repair(argc, argv);
        return 0;
    #endif
    #ifdef UPGRADE
        upgrade(argc, argv);
        return 0;
    #endif

    int load_sol = 0;
    int resume_sol = 0;
    if (strcmp(argv[argc - 1], "load") == 0) {
        load_sol = 1;
        argc--;
    }
    if (strcmp(argv[argc - 1], "resume") == 0) {
        resume_sol = 1;
        argc--;
    }
    parse_args(argc - 1, argv + 1);

    int width = board_width;
    int height = board_height;
    if (board_width >= 10) {
        fprintf(stderr, "Width must be less than 10.\n");
        exit(EXIT_FAILURE);
    }
    if (board_height >= 8) {
        fprintf(stderr, "Height must be less than 8.\n");
        exit(EXIT_FAILURE);
    }

    #include "tsumego.c"

    state base_state_;
    state *base_state = &base_state_;

    char sol_name[64] = "unknown";
    char temp_filename[128];
    char filename[128];
    if (board_width > 0) {
        *base_state = (state) {rectangle(width, height), 0, 0, 0, 0};
        sprintf(sol_name, "%dx%d", width, height);
    }
    else {
        int i;
        int found = 0;

        for (i = 0; tsumego_infos[i].name; ++i) {
            if (!strcmp(tsumego_name, tsumego_infos[i].name)) {
                *base_state = *(tsumego_infos[i].state);
                strcpy(sol_name, tsumego_name);
                found = 1;
                break;
            }
        }
        if (!found) {
            fprintf(stderr, "unknown tsumego: `%s'\n", tsumego_name);
            exit(EXIT_FAILURE);
        }
    }
    base_state->ko_threats = ko_threats;

    sprintf(temp_filename, "%s_temp.dat", sol_name);


    state_info si_;
    state_info *si = &si_;
    init_state(base_state, si);

    if (si->color_symmetry) {
        num_layers = 2 * abs(base_state->ko_threats) + 1;
    }
    else if (num_layers <= 0) {
        num_layers = abs(base_state->ko_threats) + 1;
    }
    else {
        assert(num_layers >= abs(base_state->ko_threats) + 1);
    }

    print_state(base_state);
    for (int i = 0; i < si->num_external; i++) {
        print_stones(si->externals[i]);
    }
    printf(
        "width=%d height=%d c=%d v=%d h=%d d=%d\n",
        si->width,
        si->height,
        si->color_symmetry,
        si->mirror_v_symmetry,
        si->mirror_h_symmetry,
        si->mirror_d_symmetry
    );

    state s_;
    state *s = &s_;

    dict d_;
    dict *d = &d_;

    solution sol_;
    solution *sol = &sol_;
    sol->base_state = base_state;
    sol->si = si;
    sol->d = d;
    sol->num_layers = num_layers;
    size_t num_states;

    // Re-used at frontend. TODO: Allocate a different pointer.
    state child_;
    state *child = &child_;

    if (load_sol) {
        goto frontend;
    }

    if (resume_sol) {
        char *buffer = file_to_buffer(temp_filename);
        buffer = load_solution(sol, buffer, 1);
        num_states = num_keys(sol->d);
        if (sol->leaf_rule == japanese_double_liberty) {
            goto iterate_capture;
        }
        else {
            goto iterate_japanese;
        }
    }

    size_t k_size = key_size(sol->si);
    if (!sol->si->color_symmetry) {
        k_size *= 2;
    }
    init_dict(sol->d, k_size);

    size_t total_legal = 0;
    for (size_t k = 0; k < k_size; k++) {
        if (!from_key_s(sol, s, k, 0)){
            continue;
        }
        total_legal++;
        size_t layer;
        size_t key = to_key_s(sol, s, &layer);
        assert(layer == 0);
        add_key(sol->d, key);
    }
    finalize_dict(sol->d);
    num_states = num_keys(sol->d);

    printf("Total positions %zu\n", total_legal);
    printf("Total unique positions %zu\n", num_states);

    node_value **base_nodes = (node_value**) malloc(sol->num_layers * sizeof(node_value*));
    for (size_t i = 0; i < sol->num_layers; i++) {
        base_nodes[i] = (node_value*) malloc(num_states * sizeof(node_value));
    }
    value_t *leaf_nodes = (value_t*) malloc(num_states * sizeof(value_t));

    lin_dict ko_ld_ = (lin_dict) {0, 0, 0, NULL};
    lin_dict *ko_ld = &ko_ld_;

    sol->base_nodes = base_nodes;
    sol->leaf_nodes = leaf_nodes;
    sol->ko_ld = ko_ld;

    size_t child_key;
    size_t key = sol->d->min_key;
    for (size_t i = 0; i < num_states; i++) {
        assert(from_key_s(sol, s, key, 0));
        // size_t layer;
        // assert(to_key_s(sol, s, &layer) == key);
        sol->leaf_nodes[i] = 0;
        for (size_t k = 0; k < sol->num_layers; k++) {
            (sol->base_nodes[k])[i] = (node_value) {VALUE_MIN, VALUE_MAX, DISTANCE_MAX, DISTANCE_MAX};
        }
        for (int j = 0; j < STATE_SIZE; j++) {
            *child = *s;
            int prisoners;
            if (make_move(child, 1ULL << j, &prisoners)) {
                if (target_dead(child)) {
                    continue;
                }
                if (child->ko) {
                    size_t child_layer;
                    child_key = to_key_s(sol, child, &child_layer);
                    add_lin_key(sol->ko_ld, child_key);
                }
            }
        }
        key = next_key(sol->d, key);
    }

    finalize_lin_dict(sol->ko_ld);

    node_value **ko_nodes = (node_value**) malloc(sol->num_layers * sizeof(node_value*));
    sol->ko_nodes = ko_nodes;
    for (size_t i = 0; i < sol->num_layers; i++) {
        sol->ko_nodes[i] = (node_value*) malloc(sol->ko_ld->num_keys * sizeof(node_value));
    }
    printf("Unique positions with ko %zu\n", sol->ko_ld->num_keys);

    for (size_t i = 0; i < sol->ko_ld->num_keys; i++) {
        for (size_t k = 0; k < sol->num_layers; k++) {
            sol->ko_nodes[k][i] = (node_value) {VALUE_MIN, VALUE_MAX, DISTANCE_MAX, DISTANCE_MAX};
        }
    }

    #ifdef CHINESE
    printf("Negamax with Chinese rules.\n");
    sol->count_prisoners = 0;
    sol->leaf_rule = chinese_liberty;
    iterate(sol, temp_filename);
    #endif

    // NOTE: Capture rules may refuse to kill stones when the needed nakade sacrifices exceed triple the number of stones killed.
    printf("Negamax with capture rules.\n");
    sol->count_prisoners = 1;
    sol->leaf_rule = japanese_double_liberty;
    iterate_capture:
    iterate(sol, temp_filename);

    sprintf(filename, "%s_capture.dat", sol_name);
    FILE *f = fopen(filename, "wb");
    save_solution(sol, f);
    fclose(f);


    calculate_leaves(sol);

    // Clear the rest of the tree.
    for (size_t j = 0; j < sol->num_layers; j++) {
        for (size_t i = 0; i < num_states; i++) {
            sol->base_nodes[j][i] = (node_value) {VALUE_MIN, VALUE_MAX, DISTANCE_MAX, DISTANCE_MAX};
        }
        for (size_t i = 0; i < sol->ko_ld->num_keys; i++) {
            sol->ko_nodes[j][i] = (node_value) {VALUE_MIN, VALUE_MAX, DISTANCE_MAX, DISTANCE_MAX};
        }
    }

    printf("Negamax with Japanese rules.\n");
    sol->count_prisoners = 1;
    sol->leaf_rule = precalculated;
    iterate_japanese:
    iterate(sol, temp_filename);

    sprintf(filename, "%s_japanese.dat", sol_name);
    f = fopen(filename, "wb");
    save_solution(sol, f);
    fclose(f);

    frontend:
    if (load_sol) {
        sprintf(filename, "%s_japanese.dat", sol_name);
        char *buffer = file_to_buffer(filename);
        buffer = load_solution(sol, buffer, 1);
    }

    *s = *sol->base_state;

    char coord1;
    int coord2;

    int total_prisoners = 0;
    int turn = 0;

    while (1) {
        size_t layer;
        size_t key = to_key_s(sol, s, &layer);
        node_value v = negamax_node(sol, s, key, layer, 0);
        print_state(s);
        if (turn) {
            print_node((node_value) {total_prisoners - v.high, total_prisoners - v.low, v.high_distance, v.low_distance});
        }
        else {
            print_node((node_value) {total_prisoners + v.low, total_prisoners + v.high, v.low_distance, v.high_distance});
        }
        if (target_dead(s) || s->passes >= 2) {
            break;
        }
        for (int j = -1; j < STATE_SIZE; j++) {
            *child = *s;
            stones_t move;
            if (j == -1){
                move = 0;
            }
            else {
                move = 1ULL << j;
            }
            char c1 = 'A' + (j % WIDTH);
            char c2 = '0' + (j / WIDTH);
            int prisoners;
            if (make_move(child, move, &prisoners)) {
                size_t child_layer;
                size_t child_key = to_key_s(sol, child, &child_layer);
                node_value child_v = negamax_node(sol, child, child_key, child_layer, 0);
                if (sol->count_prisoners) {
                    if (child_v.low > VALUE_MIN && child_v.low < VALUE_MAX) {
                        child_v.low = child_v.low - prisoners;
                    }
                    if (child_v.high > VALUE_MIN && child_v.high < VALUE_MAX) {
                        child_v.high = child_v.high - prisoners;
                    }
                }
                if (move) {
                    printf("%c%c", c1, c2);
                }
                else {
                    printf("pass");
                }
                if (-child_v.high == v.low) {
                    printf("-");
                    if (child_v.high_distance + 1 == v.low_distance) {
                        printf("L");
                    }
                    else {
                        printf("l");
                    }
                }
                if (-child_v.high == v.low) {
                    printf("-");
                    if (child_v.low_distance + 1 == v.high_distance) {
                        printf("H");
                    }
                    else {
                        printf("h");
                    }
                }
                printf(" ");
            }
        }
        printf("\n");
        printf("Enter coordinates:\n");
        assert(scanf("%c %d", &coord1, &coord2));
        int c;
        while ((c = getchar()) != '\n' && c != EOF);
        coord1 = tolower(coord1) - 'a';
        stones_t move;
        if (coord1 < 0 || coord1 >= WIDTH) {
            // printf("%d, %d\n", coord1, coord2);
            move = 0;
        }
        else {
            move = 1ULL << (coord1 + V_SHIFT * coord2);
        }
        int prisoners;
        if (make_move(s, move, &prisoners)) {
            if (turn) {
                total_prisoners -= prisoners;
            }
            else {
                total_prisoners += prisoners;
            }
            turn = !turn;
        }
    }

    return 0;
}