hash_xxhash.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Copyright (c) The PHP Group |
  4. +----------------------------------------------------------------------+
  5. | This source file is subject to version 3.01 of the PHP license, |
  6. | that is bundled with this package in the file LICENSE, and is |
  7. | available through the world-wide-web at the following url: |
  8. | https://www.php.net/license/3_01.txt |
  9. | If you did not receive a copy of the PHP license and are unable to |
  10. | obtain it through the world-wide-web, please send a note to |
  11. | license@php.net so we can mail you a copy immediately. |
  12. +----------------------------------------------------------------------+
  13. | Author: Anatol Belski <ab@php.net> |
  14. +----------------------------------------------------------------------+
  15. */
  16. #include "php_hash.h"
  17. #include "php_hash_xxhash.h"
  18. static int php_hash_xxh32_unserialize(
  19. php_hashcontext_object *hash, zend_long magic, const zval *zv);
  20. static int php_hash_xxh64_unserialize(
  21. php_hashcontext_object *hash, zend_long magic, const zval *zv);
  22. const php_hash_ops php_hash_xxh32_ops = {
  23. "xxh32",
  24. (php_hash_init_func_t) PHP_XXH32Init,
  25. (php_hash_update_func_t) PHP_XXH32Update,
  26. (php_hash_final_func_t) PHP_XXH32Final,
  27. (php_hash_copy_func_t) PHP_XXH32Copy,
  28. php_hash_serialize,
  29. php_hash_xxh32_unserialize,
  30. PHP_XXH32_SPEC,
  31. 4,
  32. 4,
  33. sizeof(PHP_XXH32_CTX),
  34. 0
  35. };
  36. PHP_HASH_API void PHP_XXH32Init(PHP_XXH32_CTX *ctx, HashTable *args)
  37. {
  38. /* XXH32_createState() is not used intentionally. */
  39. memset(&ctx->s, 0, sizeof ctx->s);
  40. if (args) {
  41. zval *seed = zend_hash_str_find_deref(args, "seed", sizeof("seed") - 1);
  42. /* This might be a bit too restrictive, but thinking that a seed might be set
  43. once and for all, it should be done a clean way. */
  44. if (seed && IS_LONG == Z_TYPE_P(seed)) {
  45. XXH32_reset(&ctx->s, (XXH32_hash_t)Z_LVAL_P(seed));
  46. } else {
  47. XXH32_reset(&ctx->s, 0);
  48. }
  49. } else {
  50. XXH32_reset(&ctx->s, 0);
  51. }
  52. }
  53. PHP_HASH_API void PHP_XXH32Update(PHP_XXH32_CTX *ctx, const unsigned char *in, size_t len)
  54. {
  55. XXH32_update(&ctx->s, in, len);
  56. }
  57. PHP_HASH_API void PHP_XXH32Final(unsigned char digest[4], PHP_XXH32_CTX *ctx)
  58. {
  59. XXH32_canonicalFromHash((XXH32_canonical_t*)digest, XXH32_digest(&ctx->s));
  60. }
  61. PHP_HASH_API int PHP_XXH32Copy(const php_hash_ops *ops, PHP_XXH32_CTX *orig_context, PHP_XXH32_CTX *copy_context)
  62. {
  63. copy_context->s = orig_context->s;
  64. return SUCCESS;
  65. }
  66. static int php_hash_xxh32_unserialize(
  67. php_hashcontext_object *hash, zend_long magic, const zval *zv)
  68. {
  69. PHP_XXH32_CTX *ctx = (PHP_XXH32_CTX *) hash->context;
  70. int r = FAILURE;
  71. if (magic == PHP_HASH_SERIALIZE_MAGIC_SPEC
  72. && (r = php_hash_unserialize_spec(hash, zv, PHP_XXH32_SPEC)) == SUCCESS
  73. && ctx->s.memsize < 16) {
  74. return SUCCESS;
  75. } else {
  76. return r != SUCCESS ? r : -2000;
  77. }
  78. }
  79. const php_hash_ops php_hash_xxh64_ops = {
  80. "xxh64",
  81. (php_hash_init_func_t) PHP_XXH64Init,
  82. (php_hash_update_func_t) PHP_XXH64Update,
  83. (php_hash_final_func_t) PHP_XXH64Final,
  84. (php_hash_copy_func_t) PHP_XXH64Copy,
  85. php_hash_serialize,
  86. php_hash_xxh64_unserialize,
  87. PHP_XXH64_SPEC,
  88. 8,
  89. 8,
  90. sizeof(PHP_XXH64_CTX),
  91. 0
  92. };
  93. PHP_HASH_API void PHP_XXH64Init(PHP_XXH64_CTX *ctx, HashTable *args)
  94. {
  95. /* XXH64_createState() is not used intentionally. */
  96. memset(&ctx->s, 0, sizeof ctx->s);
  97. if (args) {
  98. zval *seed = zend_hash_str_find_deref(args, "seed", sizeof("seed") - 1);
  99. /* This might be a bit too restrictive, but thinking that a seed might be set
  100. once and for all, it should be done a clean way. */
  101. if (seed && IS_LONG == Z_TYPE_P(seed)) {
  102. XXH64_reset(&ctx->s, (XXH64_hash_t)Z_LVAL_P(seed));
  103. } else {
  104. XXH64_reset(&ctx->s, 0);
  105. }
  106. } else {
  107. XXH64_reset(&ctx->s, 0);
  108. }
  109. }
  110. PHP_HASH_API void PHP_XXH64Update(PHP_XXH64_CTX *ctx, const unsigned char *in, size_t len)
  111. {
  112. XXH64_update(&ctx->s, in, len);
  113. }
  114. PHP_HASH_API void PHP_XXH64Final(unsigned char digest[8], PHP_XXH64_CTX *ctx)
  115. {
  116. XXH64_canonicalFromHash((XXH64_canonical_t*)digest, XXH64_digest(&ctx->s));
  117. }
  118. PHP_HASH_API int PHP_XXH64Copy(const php_hash_ops *ops, PHP_XXH64_CTX *orig_context, PHP_XXH64_CTX *copy_context)
  119. {
  120. copy_context->s = orig_context->s;
  121. return SUCCESS;
  122. }
  123. const php_hash_ops php_hash_xxh3_64_ops = {
  124. "xxh3",
  125. (php_hash_init_func_t) PHP_XXH3_64_Init,
  126. (php_hash_update_func_t) PHP_XXH3_64_Update,
  127. (php_hash_final_func_t) PHP_XXH3_64_Final,
  128. (php_hash_copy_func_t) PHP_XXH3_64_Copy,
  129. php_hash_serialize,
  130. php_hash_unserialize,
  131. NULL,
  132. 8,
  133. 8,
  134. sizeof(PHP_XXH3_64_CTX),
  135. 0
  136. };
  137. typedef XXH_errorcode (*xxh3_reset_with_secret_func_t)(XXH3_state_t*, const void*, size_t);
  138. typedef XXH_errorcode (*xxh3_reset_with_seed_func_t)(XXH3_state_t*, XXH64_hash_t);
  139. zend_always_inline static void _PHP_XXH3_Init(PHP_XXH3_64_CTX *ctx, HashTable *args,
  140. xxh3_reset_with_seed_func_t func_init_seed, xxh3_reset_with_secret_func_t func_init_secret, const char* algo_name)
  141. {
  142. memset(&ctx->s, 0, sizeof ctx->s);
  143. if (args) {
  144. zval *_seed = zend_hash_str_find_deref(args, "seed", sizeof("seed") - 1);
  145. zval *_secret = zend_hash_str_find_deref(args, "secret", sizeof("secret") - 1);
  146. if (_seed && _secret) {
  147. zend_throw_error(NULL, "%s: Only one of seed or secret is to be passed for initialization", algo_name);
  148. return;
  149. }
  150. if (_seed && IS_LONG == Z_TYPE_P(_seed)) {
  151. /* This might be a bit too restrictive, but thinking that a seed might be set
  152. once and for all, it should be done a clean way. */
  153. func_init_seed(&ctx->s, (XXH64_hash_t)Z_LVAL_P(_seed));
  154. return;
  155. } else if (_secret) {
  156. convert_to_string(_secret);
  157. size_t len = Z_STRLEN_P(_secret);
  158. if (len < PHP_XXH3_SECRET_SIZE_MIN) {
  159. zend_throw_error(NULL, "%s: Secret length must be >= %u bytes, %zu bytes passed", algo_name, XXH3_SECRET_SIZE_MIN, len);
  160. return;
  161. }
  162. if (len > sizeof(ctx->secret)) {
  163. len = sizeof(ctx->secret);
  164. php_error_docref(NULL, E_WARNING, "%s: Secret content exceeding %zu bytes discarded", algo_name, sizeof(ctx->secret));
  165. }
  166. memcpy((unsigned char *)ctx->secret, Z_STRVAL_P(_secret), len);
  167. func_init_secret(&ctx->s, ctx->secret, len);
  168. return;
  169. }
  170. }
  171. func_init_seed(&ctx->s, 0);
  172. }
  173. PHP_HASH_API void PHP_XXH3_64_Init(PHP_XXH3_64_CTX *ctx, HashTable *args)
  174. {
  175. _PHP_XXH3_Init(ctx, args, XXH3_64bits_reset_withSeed, XXH3_64bits_reset_withSecret, "xxh3");
  176. }
  177. PHP_HASH_API void PHP_XXH3_64_Update(PHP_XXH3_64_CTX *ctx, const unsigned char *in, size_t len)
  178. {
  179. XXH3_64bits_update(&ctx->s, in, len);
  180. }
  181. PHP_HASH_API void PHP_XXH3_64_Final(unsigned char digest[8], PHP_XXH3_64_CTX *ctx)
  182. {
  183. XXH64_canonicalFromHash((XXH64_canonical_t*)digest, XXH3_64bits_digest(&ctx->s));
  184. }
  185. PHP_HASH_API int PHP_XXH3_64_Copy(const php_hash_ops *ops, PHP_XXH3_64_CTX *orig_context, PHP_XXH3_64_CTX *copy_context)
  186. {
  187. copy_context->s = orig_context->s;
  188. return SUCCESS;
  189. }
  190. static int php_hash_xxh64_unserialize(
  191. php_hashcontext_object *hash, zend_long magic, const zval *zv)
  192. {
  193. PHP_XXH64_CTX *ctx = (PHP_XXH64_CTX *) hash->context;
  194. int r = FAILURE;
  195. if (magic == PHP_HASH_SERIALIZE_MAGIC_SPEC
  196. && (r = php_hash_unserialize_spec(hash, zv, PHP_XXH64_SPEC)) == SUCCESS
  197. && ctx->s.memsize < 32) {
  198. return SUCCESS;
  199. } else {
  200. return r != SUCCESS ? r : -2000;
  201. }
  202. }
  203. const php_hash_ops php_hash_xxh3_128_ops = {
  204. "xxh128",
  205. (php_hash_init_func_t) PHP_XXH3_128_Init,
  206. (php_hash_update_func_t) PHP_XXH3_128_Update,
  207. (php_hash_final_func_t) PHP_XXH3_128_Final,
  208. (php_hash_copy_func_t) PHP_XXH3_128_Copy,
  209. php_hash_serialize,
  210. php_hash_unserialize,
  211. NULL,
  212. 16,
  213. 8,
  214. sizeof(PHP_XXH3_128_CTX),
  215. 0
  216. };
  217. PHP_HASH_API void PHP_XXH3_128_Init(PHP_XXH3_128_CTX *ctx, HashTable *args)
  218. {
  219. _PHP_XXH3_Init(ctx, args, XXH3_128bits_reset_withSeed, XXH3_128bits_reset_withSecret, "xxh128");
  220. }
  221. PHP_HASH_API void PHP_XXH3_128_Update(PHP_XXH3_128_CTX *ctx, const unsigned char *in, size_t len)
  222. {
  223. XXH3_128bits_update(&ctx->s, in, len);
  224. }
  225. PHP_HASH_API void PHP_XXH3_128_Final(unsigned char digest[16], PHP_XXH3_128_CTX *ctx)
  226. {
  227. XXH128_canonicalFromHash((XXH128_canonical_t*)digest, XXH3_128bits_digest(&ctx->s));
  228. }
  229. PHP_HASH_API int PHP_XXH3_128_Copy(const php_hash_ops *ops, PHP_XXH3_128_CTX *orig_context, PHP_XXH3_128_CTX *copy_context)
  230. {
  231. copy_context->s = orig_context->s;
  232. return SUCCESS;
  233. }