/** * prism_vif_hash_func- * @key: Prism Virtual I/F hash key * * Derive a hash val from vif key */ unsigned int prism_vif_hash_func(const void *key) { const prism_vif_elem_t *vif_elem = key; return hash_bytes(vif_elem, sizeof(prism_vif_hash_key_t), 1); }
/** * prism_route_hash_func- * @key: Prism route hash key * * Derive a hash val froma route key */ unsigned int prism_route_hash_func(const void *key) { const prism_rt_elem_t *rt_elem = key; return hash_bytes(rt_elem, sizeof(prism_rt_hash_key_t), 1); }
static uint64_t _kvdb_o_hash_value(void *v, void *ctx) { kvdb_o o = (kvdb_o) v; return hash_bytes(&o->oid, KVDB_OID_SIZE); }
/** * @name fab_host_hash_func * @brief Derive a hash val from a host key * @param [in] key: fabric host hash key * * @retval int hash-value */ unsigned int fab_host_hash_func(const void *key) { const fab_host_t *host = key; return hash_bytes(host, sizeof(fab_hkey_t), 1); }
/** * prism_next_hop_hash_func- * @key: Prism next hop hash key * * Derive a hash val froma next hop key */ unsigned int prism_next_hop_hash_func(const void *key) { const prism_nh_elem_t *nh_elem = key; return hash_bytes(nh_elem, sizeof(prism_nh_hash_key_t), 1); }
/* Returns a hash of the wildcards in 'wc'. */ uint32_t flow_wildcards_hash(const struct flow_wildcards *wc, uint32_t basis) { /* If you change struct flow_wildcards and thereby trigger this * assertion, please check that the new struct flow_wildcards has no holes * in it before you update the assertion. */ BUILD_ASSERT_DECL(sizeof *wc == 60 + FLOW_N_REGS * 4); return hash_bytes(wc, sizeof *wc, basis); }
/* Hashes the portions of 'flow' designated by 'fields'. */ uint32_t flow_hash_fields(const struct flow *flow, enum nx_hash_fields fields, uint16_t basis) { switch (fields) { case NX_HASH_FIELDS_ETH_SRC: return hash_bytes(flow->dl_src, sizeof flow->dl_src, basis); case NX_HASH_FIELDS_SYMMETRIC_L4: return flow_hash_symmetric_l4(flow, basis); } NOT_REACHED(); }
/* * Retrieve the list of matching offsets from the hash. * * Returns the offset to head of the linked list. * Returns 0 if value was not found. */ gint wg_idxhash_find(void* db, db_hash_area_header *ha, char* data, gint length) { wg_uint hash; gint head_offset, bucket; hash = hash_bytes(db, data, length, ha->arraylength); head_offset = (ha->arraystart)+(sizeof(gint) * hash); /* points to head */ /* Find the correct bucket. */ bucket = find_idxhash_bucket(db, data, length, &head_offset); if(!bucket) return 0; return dbfetch(db, bucket + HASHIDX_RECLIST_POS*sizeof(gint)); }
/* Hashes 'flow' based on its L2 through L4 protocol information. */ uint32_t flow_hash_symmetric_l4(const struct flow *flow, uint32_t basis) { struct { union { ovs_be32 ipv4_addr; struct in6_addr ipv6_addr; }; ovs_be16 eth_type; ovs_be16 vlan_tci; ovs_be16 tp_port; uint8_t eth_addr[ETH_ADDR_LEN]; uint8_t ip_proto; } fields; int i; memset(&fields, 0, sizeof fields); for (i = 0; i < ETH_ADDR_LEN; i++) { fields.eth_addr[i] = flow->dl_src[i] ^ flow->dl_dst[i]; } fields.vlan_tci = flow->vlan_tci & htons(VLAN_VID_MASK); fields.eth_type = flow->dl_type; /* UDP source and destination port are not taken into account because they * will not necessarily be symmetric in a bidirectional flow. */ if (fields.eth_type == htons(ETH_TYPE_IP)) { fields.ipv4_addr = flow->nw_src ^ flow->nw_dst; fields.ip_proto = flow->nw_proto; if (fields.ip_proto == IPPROTO_TCP) { fields.tp_port = flow->tp_src ^ flow->tp_dst; } } else if (fields.eth_type == htons(ETH_TYPE_IPV6)) { const uint8_t *a = &flow->ipv6_src.s6_addr[0]; const uint8_t *b = &flow->ipv6_dst.s6_addr[0]; uint8_t *ipv6_addr = &fields.ipv6_addr.s6_addr[0]; for (i=0; i<16; i++) { ipv6_addr[i] = a[i] ^ b[i]; } fields.ip_proto = flow->nw_proto; if (fields.ip_proto == IPPROTO_TCP) { fields.tp_port = flow->tp_src ^ flow->tp_dst; } } return hash_bytes(&fields, sizeof fields, basis); }
void random_init(void) { uint32_t *seedp = seed_get(); while (!*seedp) { struct timeval tv; uint32_t entropy; pthread_t self; xgettimeofday(&tv); get_entropy_or_die(&entropy, 4); self = pthread_self(); *seedp = (tv.tv_sec ^ tv.tv_usec ^ entropy ^ hash_bytes(&self, sizeof self, 0)); } }
/** * @name fab_mp_select * * @brief Select a path from multi-path set */ static size_t fab_mp_select(void *u_arg, size_t max_routes) { fab_route_t *froute = u_arg; unsigned int mp_key; assert(froute); #ifdef NOTDEMO mp_key = hash_bytes(&froute->rt_flow.nw_src, 8, 1); mp_key %= max_routes; #else mp_key = ntohl(froute->rt_flow.ip.nw_dst) & 0xff; mp_key %= max_routes; #endif return mp_key; }
/* Returns a hash value for double D, starting from BASIS. */ unsigned int hash_double (double d, unsigned int basis) { if (sizeof (double) == 8) { uint32_t tmp[2]; uint32_t a, b, c; a = b = c = 0xdeadbeef + 8 + basis; memcpy (tmp, &d, 8); a += tmp[0]; b += tmp[1]; HASH_FINAL (a, b, c); return c; } else return hash_bytes (&d, sizeof d, basis); }
/* * Remove an offset from the index hash. * * Returns 0 on success * Returns -1 on error. */ gint wg_idxhash_remove(void* db, db_hash_area_header *ha, char* data, gint length, gint offset) { wg_uint hash; gint bucket_offset, bucket; gint *next_offset, *reclist_offset; hash = hash_bytes(db, data, length, ha->arraylength); bucket_offset = (ha->arraystart)+(sizeof(gint) * hash); /* points to head */ /* Find the correct bucket. */ bucket = find_idxhash_bucket(db, data, length, &bucket_offset); if(!bucket) { return show_hash_error(db, "wg_idxhash_remove: Hash value not found."); } /* Remove the record offset from the list. */ reclist_offset = offsettoptr(db, bucket + HASHIDX_RECLIST_POS*sizeof(gint)); next_offset = reclist_offset; while(*next_offset) { gcell *rec_cell = (gcell *) offsettoptr(db, *next_offset); if(rec_cell->car == offset) { gint rec_offset = *next_offset; *next_offset = rec_cell->cdr; /* remove from list chain */ wg_free_listcell(db, rec_offset); /* free storage */ goto is_bucket_empty; } next_offset = &(rec_cell->cdr); } return show_hash_error(db, "wg_idxhash_remove: Offset not found"); is_bucket_empty: if(!(*reclist_offset)) { gint nextchain = dbfetch(db, bucket + HASHIDX_HASHCHAIN_POS*sizeof(gint)); dbstore(db, bucket_offset, nextchain); wg_free_object(db, &(dbmemsegh(db)->indexhash_area_header), bucket); } return 0; }
void rawLogMessage(LogLevel c, const char *message) { static std::size_t lastHash = 0; static int timesRepeated = 0; std::size_t curHash = hash_bytes(message, std::strlen(message)) + (std::size_t)c; // bool repeatLast = false; if (curHash == lastHash) { // repeat last output ++timesRepeated; setConsoleColor(std::cerr, 8); rawRepeatLast(timesRepeated, message); setConsoleColor(std::cerr, 7); } else { lastHash = curHash; if (timesRepeated) rawDebugOutput(0, "\n"); timesRepeated = 0; } if (c == LogLevel::Debug) { setConsoleColor(std::cerr, 8); rawDebugOutput(timesRepeated, "[DEBUG] "); } else if (c == LogLevel::Warning) { setConsoleColor(std::cerr, 14); rawDebugOutput(timesRepeated, "[WARN ] "); setConsoleColor(std::cerr, 7); } else if (c == LogLevel::Error) { setConsoleColor(std::cerr, 12); rawDebugOutput(timesRepeated, "[ERROR] "); setConsoleColor(std::cerr, 7); } else if (c == LogLevel::Fatal) { setConsoleColor(std::cerr, 12); rawDebugOutput(timesRepeated, "\n[FATAL] "); } rawDebugOutput(timesRepeated, message); rawDebugOutput(timesRepeated, "\n"); setConsoleColor(std::cerr, 7); }
/* * r = rand(), |r| = hashlen * k = HashToRange(r||Hash(m), q), k in [0, q-1] * U = [k]P in E/F_p * Q = HashToPoint(ID) in E/F_p * v = Hash(e(Ppub, Q)^k) xor r, |v| == hashlen * w = HashBytes(r) xor m */ BFCiphertextBlock *BFIBE_do_encrypt(BFPublicParameters *mpk, const unsigned char *in, size_t inlen, const char *id, size_t idlen) { int e = 1; BFCiphertextBlock *ret = NULL; BN_CTX *bn_ctx = NULL; EC_GROUP *group = NULL; EC_POINT *Ppub = NULL; EC_POINT *point = NULL; BN_GFP2 *theta = NULL; BIGNUM *k; const EVP_MD *md; KDF_FUNC hash_bytes; unsigned char rho[EVP_MAX_MD_SIZE * 2]; unsigned char buf[EVP_MAX_MD_SIZE]; unsigned int len; size_t size; int i; if (!mpk || !in || inlen <= 0 || !id || idlen <= 0) { BFIBEerr(BFIBE_F_BFIBE_DO_ENCRYPT, ERR_R_PASSED_NULL_PARAMETER); return NULL; } /* BN_CTX */ if (!(bn_ctx = BN_CTX_new())) { BFIBEerr(BFIBE_F_BFIBE_DO_ENCRYPT, ERR_R_MALLOC_FAILURE); goto end; } BN_CTX_start(bn_ctx); /* EC_GROUP */ if (!(group = EC_GROUP_new_type1curve(mpk->p, mpk->pointP->x, mpk->pointP->y, mpk->q, bn_ctx))) { BFIBEerr(BFIBE_F_BFIBE_DO_ENCRYPT, BFIBE_R_PARSE_MPK_FAILURE); goto end; } ret = BFCiphertextBlock_new(); Ppub = EC_POINT_new(group); point = EC_POINT_new(group); theta = BN_GFP2_new(); k = BN_CTX_get(bn_ctx); if (!ret || !point || !Ppub || !k || !theta) { BFIBEerr(BFIBE_F_BFIBE_DO_ENCRYPT, ERR_R_MALLOC_FAILURE); goto end; } /* get kdf from mpk->hashfcn */ if (!(md = EVP_get_digestbyobj(mpk->hashfcn))) { BFIBEerr(BFIBE_F_BFIBE_DO_ENCRYPT, BFIBE_R_INVALID_BFIBE_HASHFUNC); goto end; } if (!(hash_bytes = KDF_get_ibcs(md))) { BFIBEerr(BFIBE_F_BFIBE_DO_ENCRYPT, BFIBE_R_INVALID_BFIBE_HASHFUNC); goto end; } /* ret->version */ ret->version = BFIBE_VERSION; /* rho = Rand(hashlen) */ if (!RAND_bytes(rho, EVP_MD_size(md))) { BFIBEerr(BFIBE_F_BFIBE_DO_ENCRYPT, BFIBE_R_RAND_FAILURE); goto end; } /* k = HashToRange(rho||Hash(in), q) in [0, q - 1] */ len = EVP_MD_size(md); if (!EVP_Digest(in, inlen, rho + EVP_MD_size(md), &len, md, NULL)) { BFIBEerr(BFIBE_F_BFIBE_DO_ENCRYPT, ERR_R_EVP_LIB); goto end; } if (!BN_hash_to_range(md, &k, rho, EVP_MD_size(md) * 2, mpk->q, bn_ctx)) { BFIBEerr(BFIBE_F_BFIBE_DO_ENCRYPT, ERR_R_BN_LIB); goto end; } /* ret->u = mpk->pointP * k in E/F_p, mpk->pointP is the generator */ if (!EC_POINT_mul(group, point, k, NULL, NULL, bn_ctx)) { BFIBEerr(BFIBE_F_BFIBE_DO_ENCRYPT, ERR_R_EC_LIB); goto end; } if (!EC_POINT_get_affine_coordinates_GFp(group, point, ret->u->x, ret->u->y, bn_ctx)) { BFIBEerr(BFIBE_F_BFIBE_DO_ENCRYPT, ERR_R_EC_LIB); goto end; } /* theta = e(mpk->pointPpub, HashToPoint(ID)) */ if (!EC_POINT_set_affine_coordinates_GFp(group, Ppub, mpk->pointPpub->x, mpk->pointPpub->y, bn_ctx)) { BFIBEerr(BFIBE_F_BFIBE_DO_ENCRYPT, ERR_R_EC_LIB); goto end; } if (!EC_POINT_hash2point(group, md, id, idlen, point, bn_ctx)) { BFIBEerr(BFIBE_F_BFIBE_DO_ENCRYPT, ERR_R_EC_LIB); goto end; } if (!EC_type1curve_tate(group, theta, Ppub, point, bn_ctx)) { BFIBEerr(BFIBE_F_BFIBE_DO_ENCRYPT, ERR_R_EC_LIB); goto end; } /* theta = theta^k */ if (!BN_GFP2_exp(theta, theta, k, mpk->p, bn_ctx)) { BFIBEerr(BFIBE_F_BFIBE_DO_ENCRYPT, ERR_R_EC_LIB); goto end; } /* ret->v = Hash(theta) xor rho */ size = sizeof(buf); if (!BN_GFP2_canonical(theta, buf, &size, 0, mpk->p, bn_ctx)) { BFIBEerr(BFIBE_F_BFIBE_DO_ENCRYPT, ERR_R_BN_LIB); goto end; } len = sizeof(buf); if (!EVP_Digest(buf, size, buf, &len, md, NULL)) { BFIBEerr(BFIBE_F_BFIBE_DO_ENCRYPT, ERR_R_EVP_LIB); goto end; } for (i = 0; i < EVP_MD_size(md); i++) { buf[i] ^= rho[i]; } if (!ASN1_OCTET_STRING_set(ret->v, buf, EVP_MD_size(md))) { BFIBEerr(BFIBE_F_BFIBE_DO_ENCRYPT, ERR_R_ASN1_LIB); goto end; } /* ret->w = HashBytes(rho) xor m */ if (!ASN1_OCTET_STRING_set(ret->w, NULL, inlen)) { BFIBEerr(BFIBE_F_BFIBE_DO_ENCRYPT, ERR_R_MALLOC_FAILURE); goto end; } size = inlen; if (!hash_bytes(rho, EVP_MD_size(md), ret->w->data, &size)) { BFIBEerr(BFIBE_F_BFIBE_DO_ENCRYPT, BFIBE_R_HASH_BYTES_FAILURE); goto end; } for (i = 0; i < inlen; i++) { ret->w->data[i] ^= in[i]; } e = 0; end: if (e && ret) { BFCiphertextBlock_free(ret); ret = NULL; } if (bn_ctx) { BN_CTX_end(bn_ctx); } BN_CTX_free(bn_ctx); EC_GROUP_free(group); EC_POINT_free(Ppub); EC_POINT_free(point); BN_GFP2_free(theta); return ret; }
/** * @name fab_tenant_nw_hash_fn * @brief Hash function for a tenant network * @param [in] key Key pointer which is tenant network */ unsigned int fab_tenant_nw_uuid_hash_func(const void *key) { return hash_bytes(key, sizeof(uuid_t), 1); }
std::vector<byte> hash_bytes(const std::vector<byte, A>& v) { return hash_bytes(v.data(), v.size()); }
int BFIBE_do_decrypt(BFPublicParameters *mpk, const BFCiphertextBlock *in, unsigned char *out, size_t *outlen, BFPrivateKeyBlock *sk) { int ret = 0; BN_CTX *bn_ctx = NULL; EC_GROUP *group = NULL; EC_POINT *point = NULL; EC_POINT *point1 = NULL; BN_GFP2 *theta = NULL; BIGNUM *k; const EVP_MD *md; KDF_FUNC hash_bytes; unsigned char rho[EVP_MAX_MD_SIZE * 2]; size_t size; unsigned int len; int i; if (!mpk || !in || !outlen || !sk) { BFIBEerr(BFIBE_F_BFIBE_DO_DECRYPT, ERR_R_PASSED_NULL_PARAMETER); return 0; } if (!out) { *outlen = in->w->length; return 1; } if (*outlen < in->w->length) { BFIBEerr(BFIBE_F_BFIBE_DO_DECRYPT, BFIBE_R_BUFFER_TOO_SMALL); return 0; } /* BN_CTX */ if (!(bn_ctx = BN_CTX_new())) { BFIBEerr(BFIBE_F_BFIBE_DO_DECRYPT, ERR_R_MALLOC_FAILURE); goto end; } BN_CTX_start(bn_ctx); /* EC_GROUP */ if (!(group = EC_GROUP_new_type1curve(mpk->p, mpk->pointP->x, mpk->pointP->y, mpk->q, bn_ctx))) { BFIBEerr(BFIBE_F_BFIBE_DO_DECRYPT, BFIBE_R_INVALID_TYPE1CURVE); goto end; } point = EC_POINT_new(group); point1 = EC_POINT_new(group); theta = BN_GFP2_new(); k = BN_CTX_get(bn_ctx); if (!point || !point1 || !theta || !k) { BFIBEerr(BFIBE_F_BFIBE_DO_DECRYPT, ERR_R_MALLOC_FAILURE); goto end; } /* theta = e(ciphertext->u, sk->privateKey) */ if (!EC_POINT_set_affine_coordinates_GFp(group, point, in->u->x, in->u->y, bn_ctx)) { BFIBEerr(BFIBE_F_BFIBE_DO_DECRYPT, ERR_R_EC_LIB); goto end; } if (!EC_POINT_set_affine_coordinates_GFp(group, point1, sk->privateKey->x, sk->privateKey->y, bn_ctx)) { BFIBEerr(BFIBE_F_BFIBE_DO_DECRYPT, ERR_R_EC_LIB); goto end; } if (!EC_type1curve_tate(group, theta, point, point1, bn_ctx)) { BFIBEerr(BFIBE_F_BFIBE_DO_DECRYPT, ERR_R_EC_LIB); goto end; } /* md = mpk->hashfcn */ if (!(md = EVP_get_digestbyobj(mpk->hashfcn))) { BFIBEerr(BFIBE_F_BFIBE_DO_DECRYPT, BFIBE_R_INVALID_BFIBE_HASHFUNC); goto end; } /* rho = Hash(Canoncial(theta)) xor ciphertext->v */ size = sizeof(rho); if (!BN_GFP2_canonical(theta, rho, &size, 0, mpk->p, bn_ctx)) { BFIBEerr(BFIBE_F_BFIBE_DO_DECRYPT, ERR_R_EC_LIB); goto end; } len = size; if (!EVP_Digest(rho, size, rho, &len, md, NULL)) { BFIBEerr(BFIBE_F_BFIBE_DO_DECRYPT, ERR_R_EVP_LIB); goto end; } for (i = 0; i < EVP_MD_size(md); i++) { rho[i] ^= in->v->data[i]; } /* function hash_bytes() = kdf(md) */ if (!(hash_bytes = KDF_get_ibcs(md))) { BFIBEerr(BFIBE_F_BFIBE_DO_DECRYPT, BFIBE_R_INVALID_BFIBE_HASHFUNC); goto end; } /* out = HashBytes(rho) xor ciphertext->w */ size = in->w->length; if (!hash_bytes(rho, EVP_MD_size(md), out, &size)) { BFIBEerr(BFIBE_F_BFIBE_DO_DECRYPT, BFIBE_R_KDF_FAILURE); goto end; } for (i = 0; i < in->w->length; i++) { out[i] ^= in->w->data[i]; } /* k = HashToRange(rho || Hash(out)) in [0, mpk->q) */ len = EVP_MD_size(md); if (!EVP_Digest(out, in->w->length, rho + EVP_MD_size(md), &len, md, NULL)) { BFIBEerr(BFIBE_F_BFIBE_DO_DECRYPT, ERR_R_EVP_LIB); goto end; } if (!BN_hash_to_range(md, &k, rho, EVP_MD_size(md) * 2, mpk->q, bn_ctx)) { BFIBEerr(BFIBE_F_BFIBE_DO_DECRYPT, ERR_R_BN_LIB); goto end; } /* Verify that in->u == mpk->pointP * k */ if (!EC_POINT_mul(group, point, k, NULL, NULL, bn_ctx)) { BFIBEerr(BFIBE_F_BFIBE_DO_DECRYPT, ERR_R_EC_LIB); goto end; } if (1 != EC_POINT_cmp_fppoint(group, point, in->u, bn_ctx)) { BFIBEerr(BFIBE_F_BFIBE_DO_DECRYPT, BFIBE_R_BFIBE_CIPHERTEXT_FAILURE); goto end; } *outlen = in->w->length; ret = 1; end: if (bn_ctx) { BN_CTX_end(bn_ctx); } BN_CTX_free(bn_ctx); EC_GROUP_free(group); EC_POINT_free(point); EC_POINT_free(point1); BN_GFP2_free(theta); return ret; }
/* * Store a hash string and an offset to the index hash. * Based on longstr hash, with some simplifications. * * Returns 0 on success * Returns -1 on error. */ gint wg_idxhash_store(void* db, db_hash_area_header *ha, char* data, gint length, gint offset) { db_memsegment_header* dbh = dbmemsegh(db); wg_uint hash; gint head_offset, head, bucket; gint rec_head, rec_offset; gcell *rec_cell; hash = hash_bytes(db, data, length, ha->arraylength); head_offset = (ha->arraystart)+(sizeof(gint) * hash); head = dbfetch(db, head_offset); /* Traverse the hash chain to check if there is a matching * hash string already */ bucket = find_idxhash_bucket(db, data, length, &head_offset); if(!bucket) { size_t i; gint lengints, lenrest; char* dptr; /* Make a new bucket */ lengints = length / sizeof(gint); lenrest = length % sizeof(gint); if(lenrest) lengints++; bucket = wg_alloc_gints(db, &(dbh->indexhash_area_header), lengints + HASHIDX_HEADER_SIZE); if(!bucket) { return -1; } /* Copy the byte data */ dptr = (char *) (offsettoptr(db, bucket + HASHIDX_HEADER_SIZE*sizeof(gint))); memcpy(dptr, data, length); for(i=0;lenrest && i<sizeof(gint)-lenrest;i++) { *(dptr + length + i)=0; /* XXX: since we have the length, in meta, * this is possibly unnecessary. */ } /* Metadata */ dbstore(db, bucket + HASHIDX_META_POS*sizeof(gint), length); dbstore(db, bucket + HASHIDX_RECLIST_POS*sizeof(gint), 0); /* Prepend to hash chain */ dbstore(db, ((ha->arraystart)+(sizeof(gint) * hash)), bucket); dbstore(db, bucket + HASHIDX_HASHCHAIN_POS*sizeof(gint), head); } /* Add the record offset to the list. */ rec_head = dbfetch(db, bucket + HASHIDX_RECLIST_POS*sizeof(gint)); rec_offset = wg_alloc_fixlen_object(db, &(dbh->listcell_area_header)); rec_cell = (gcell *) offsettoptr(db, rec_offset); rec_cell->car = offset; rec_cell->cdr = rec_head; dbstore(db, bucket + HASHIDX_RECLIST_POS*sizeof(gint), rec_offset); return 0; }
static uint32_t mac_table_hash(const uint8_t mac[ETH_ADDR_LEN], uint16_t vlan) { return hash_bytes(mac, ETH_ADDR_LEN, vlan); }
u_int svccb::hash_value () const { return xid () ^ hash_bytes (addr, addrlen); }
/* Returns a hash value for null-terminated string S, starting from BASIS. */ unsigned int hash_string (const char *s, unsigned int basis) { return hash_bytes (s, strlen (s), basis); }
static bool object_hash_str(const char *str, size_t len, byte hash[HASH_SIZE]) { hash_bytes('u', (const byte *)str, len, hash); return true; }
std::vector<uint8_t> hash_bytes(const std::vector<uint8_t, A>& v) { return hash_bytes(v.data(), v.size()); }
static bool object_hash_bool(bool b, hash h) { hash_bytes('b', (byte *)(b ? "1" : "0"), 1, h); return true; }