@@ -55,6 +55,7 @@ typedef enum {
55
55
56
56
struct hash_params {
57
57
std::string input;
58
+ bool fnv = false ;
58
59
bool xxh64 = false ;
59
60
bool sha1 = false ;
60
61
bool sha256 = false ;
@@ -103,6 +104,7 @@ static void hash_print_usage(const char * executable) {
103
104
printf (" \n " );
104
105
printf (" options:\n " );
105
106
printf (" -h, --help show this help message and exit\n " );
107
+ printf (" --fnv use FNV-1a hash\n " );
106
108
printf (" --xxh64 use xxh64 hash\n " );
107
109
printf (" --sha1 use sha1 hash\n " );
108
110
printf (" --sha256 use sha256 hash\n " );
@@ -131,6 +133,11 @@ static void hash_params_parse_ex(int argc, const char ** argv, hash_params & par
131
133
exit (0 );
132
134
}
133
135
136
+ if (arg == " --fnv" ) {
137
+ arg_found = true ;
138
+ params.fnv = true ;
139
+ }
140
+
134
141
if (arg == " --xxh64" ) {
135
142
arg_found = true ;
136
143
params.xxh64 = true ;
@@ -188,6 +195,26 @@ static void hash_params_parse_ex(int argc, const char ** argv, hash_params & par
188
195
params.input = argv[arg_idx++];
189
196
}
190
197
198
+ struct fnv_ctx {
199
+ uint64_t hash;
200
+ };
201
+
202
+ static void fnv_init (fnv_ctx * ctx) {
203
+ ctx->hash = 0xcbf29ce484222325ULL ;
204
+ }
205
+
206
+ static void fnv_update (fnv_ctx * ctx, const uint8_t * data, size_t len) {
207
+ const uint64_t fnv_prime = 0x100000001b3ULL ;
208
+ for (size_t i = 0 ; i < len; ++i) {
209
+ ctx->hash ^= data[i];
210
+ ctx->hash *= fnv_prime;
211
+ }
212
+ }
213
+
214
+ static void fnv_final (fnv_ctx * ctx, uint64_t * digest) {
215
+ *digest = ctx->hash ;
216
+ }
217
+
191
218
static bool hash_params_parse (int argc, const char ** argv, hash_params & params) {
192
219
bool result = true ;
193
220
try {
@@ -306,6 +333,12 @@ static hash_exit_code_t gguf_hash(const hash_params & hash_params) {
306
333
}
307
334
}
308
335
336
+ // FNV init
337
+ fnv_ctx fnv_model_hash_ctx;
338
+ if (hash_params.fnv ) {
339
+ fnv_init (&fnv_model_hash_ctx);
340
+ }
341
+
309
342
// sha1 init
310
343
SHA1_CTX sha1_model_hash_ctx;
311
344
if (hash_params.sha1 ) {
@@ -326,7 +359,11 @@ static hash_exit_code_t gguf_hash(const hash_params & hash_params) {
326
359
SHA1Update ( &sha1_for_uuid_ctx, (unsigned char const *)uuidv5_namespace, sizeof (uuidv5_namespace));
327
360
}
328
361
362
+ struct gguf_context * ctx_out = gguf_init_empty ();
329
363
struct gguf_context * ctx = gguf_init_from_file (fname.c_str (), params);
364
+
365
+ gguf_set_kv (ctx_out, ctx);
366
+
330
367
const int n_tensors = gguf_get_n_tensors (ctx);
331
368
bool tensor_layer_in_manifest = false ;
332
369
bool model_in_manifest = false ;
@@ -335,10 +372,16 @@ static hash_exit_code_t gguf_hash(const hash_params & hash_params) {
335
372
for (int i = 0 ; i < n_tensors; ++i) {
336
373
const char * name = gguf_get_tensor_name (ctx, i);
337
374
struct ggml_tensor * cur = ggml_get_tensor (ctx_data, name);
375
+ gguf_add_tensor (ctx_out, cur);
338
376
auto n_bytes = ggml_nbytes (cur);
339
377
auto *raw_data = cur->data ;
340
378
const std::string tensor_layer_name = fname + " :" + name;
341
379
380
+ if (hash_params.fnv ) {
381
+ // Overall Model Hash
382
+ fnv_update (&fnv_model_hash_ctx, (const uint8_t *)raw_data, n_bytes);
383
+ }
384
+
342
385
if (hash_params.xxh64 ) {
343
386
344
387
if (!hash_params.no_layer ) {
@@ -455,6 +498,18 @@ static hash_exit_code_t gguf_hash(const hash_params & hash_params) {
455
498
}
456
499
}
457
500
501
+ if (hash_params.fnv ) {
502
+ uint64_t hash;
503
+ fnv_final (&fnv_model_hash_ctx, &hash);
504
+ char hex_result[17 ];
505
+ for (int offset = 0 ; offset < 8 ; offset++) {
506
+ unsigned int shift_bits_by = (8 * (8 - offset - 1 ));
507
+ snprintf ( ( hex_result + (2 *offset)), sizeof (hex_result) - (2 *offset), " %02x" , (unsigned char ) (hash >> shift_bits_by)&0xff );
508
+ }
509
+ printf (" %-8s %-s %s\n " , " fnv" , hex_result, fname.c_str ());
510
+ gguf_set_val_u64 (ctx_out, " model_hash" , hash);
511
+ }
512
+
458
513
if (hash_params.xxh64 ) {
459
514
XXH64_hash_t const hash = XXH64_digest (xxh64_model_hash_state);
460
515
@@ -580,6 +635,9 @@ static hash_exit_code_t gguf_hash(const hash_params & hash_params) {
580
635
}
581
636
}
582
637
638
+ auto fname_out = fname + " .rpc" ;
639
+ gguf_write_to_file (ctx_out, fname_out.c_str (), false );
640
+ gguf_free (ctx_out);
583
641
584
642
ggml_free (ctx_data);
585
643
gguf_free (ctx);
@@ -663,7 +721,7 @@ int main(int argc, const char ** argv) {
663
721
664
722
// Autoselect the highest security hash if manifest is provided but
665
723
// the user has not specifically defined the hash they care about
666
- if (!params.xxh64 && !params.sha1 && !params.uuid && !params.sha256 ) {
724
+ if (!params.fnv && !params. xxh64 && !params.sha1 && !params.uuid && !params.sha256 ) {
667
725
// User has not selected a specific value, pick most secure hash
668
726
if (manifest_check.sha256 ) {
669
727
params.sha256 = true ;
@@ -680,7 +738,7 @@ int main(int argc, const char ** argv) {
680
738
}
681
739
682
740
// By default if no swich argument provided, assume xxh64
683
- if (!params.xxh64 && !params.sha1 && !params.uuid && !params.sha256 ) {
741
+ if (!params.fnv && !params. xxh64 && !params.sha1 && !params.uuid && !params.sha256 ) {
684
742
params.xxh64 = true ;
685
743
}
686
744
0 commit comments