| 1 | % (c) 2009-2026 Lehrstuhl fuer Softwaretechnik und Programmiersprachen, | |
| 2 | % Heinrich Heine Universitaet Duesseldorf | |
| 3 | % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html) | |
| 4 | ||
| 5 | :- module(probhash, [hash_term/2, hash_to_atom/2, raw_sha_hash/2, raw_sha_hash_file/3]). | |
| 6 | ||
| 7 | :- use_module('../../src/module_information.pl'). | |
| 8 | ||
| 9 | :- module_info(group,infrastructure). | |
| 10 | :- module_info(description,'This is the interface to C code for generating good hashes (SHA-1, 160 bits).'). | |
| 11 | ||
| 12 | :- use_module(probsrc(error_manager),[add_error/4]). | |
| 13 | :- use_module(probsrc(tools_strings),[ajoin/2]). | |
| 14 | ||
| 15 | :- load_files(library(system), [when(compile_time), imports([environ/2])]). | |
| 16 | ||
| 17 | :- if((predicate_property(load_foreign_resource(_), _), | |
| 18 | \+ environ(prob_c_probhash,false))). | |
| 19 | % -Dprob_c_probhash=false | |
| 20 | ||
| 21 | :- use_module(library(fastrw),[ fast_buf_read/2, | |
| 22 | fast_buf_write/3 ]). | |
| 23 | ||
| 24 | foreign_resource(probhash,[sha1,sha1_file]). | |
| 25 | foreign(sha1,sha1(+address(char),+integer,[-term])). | |
| 26 | foreign(sha1_file,sha1_file(+atom,[-term])). % returns the list of bytes or error(Reason) | |
| 27 | ||
| 28 | :- dynamic loaded/1. | |
| 29 | ||
| 30 | :- use_module(probsrc(pathes_lib),[safe_load_foreign_resource/2]). | |
| 31 | ||
| 32 | % loads the library once; if loading fails, the error is reported once by safe_load_foreign_resource | |
| 33 | % and init_probhash fails from then on (without trying to load the library again) | |
| 34 | init_probhash :- | |
| 35 | (loaded(Res) -> true | |
| 36 | ; (safe_load_foreign_resource(probhash,probhash) -> Res = success ; Res = failure), | |
| 37 | assertz(loaded(Res)) | |
| 38 | ), | |
| 39 | Res = success. | |
| 40 | ||
| 41 | ||
| 42 | % input: term | |
| 43 | % output: hash value as a biginteger (the byte order is reversed) | |
| 44 | hash_term(Term,Hash) :- raw_sha_hash(Term,H), hash_to_int(H,Hash). | |
| 45 | ||
| 46 | :- use_module(library(file_systems),[file_exists/1]). | |
| 47 | ||
| 48 | raw_sha_hash_file(Atom,_,Span) :- | |
| 49 | \+ file_exists(Atom),!, | |
| 50 | add_error(probhash,'File does not exist: ',Atom,Span),fail. | |
| 51 | raw_sha_hash_file(Atom,Hash,Span) :- | |
| 52 | init_probhash, | |
| 53 | sha1_file(Atom,Result), | |
| 54 | (Result = error(Reason) | |
| 55 | -> ajoin(['Could not read file (',Reason,'): '],Msg), | |
| 56 | add_error(probhash,Msg,Atom,Span), | |
| 57 | fail | |
| 58 | ; Hash = Result | |
| 59 | ). | |
| 60 | ||
| 61 | ||
| 62 | ||
| 63 | % input: raw hash | |
| 64 | % output: hash value as a biginteger (the byte order is reversed) | |
| 65 | hash_to_int(X,Y) :- hash_to_int(X,0,Y). | |
| 66 | hash_to_int([],A,A). | |
| 67 | hash_to_int([H|T],A,R) :- A2 is A * 256 + H, hash_to_int(T,A2,R). | |
| 68 | ||
| 69 | % raw sha hashing, input is a term, output a raw hash, i.e., a list of 20 bytes | |
| 70 | raw_sha_hash(Term,Digest) :- | |
| 71 | init_probhash, | |
| 72 | fast_buf_write(Term,Len,Addr), | |
| 73 | sha1(Addr,Len,Digest). | |
| 74 | ||
| 75 | % input: raw hash value | |
| 76 | % output: hash value as an atom | |
| 77 | hash_to_atom(H,ResultAtom) :- | |
| 78 | raw_sha_hash(H,H2), hash_to_int(H2,X), | |
| 79 | number_codes(X, C),atom_codes(ResultAtom,C). | |
| 80 | ||
| 81 | % input: raw hash value | |
| 82 | % output: hash value as 5 32-bit chunks | |
| 83 | hash_to_32bit([V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11,V12,V13,V14,V15,V16,V17,V18,V19,V20],[H1,H2,H3,H4,H5]) :- | |
| 84 | hash_to_int([V1,V2,V3,V4],H1), | |
| 85 | hash_to_int([V5,V6,V7,V8],H2), | |
| 86 | hash_to_int([V9,V10,V11,V12],H3), | |
| 87 | hash_to_int([V13,V14,V15,V16],H4), | |
| 88 | hash_to_int([V17,V18,V19,V20],H5). | |
| 89 | ||
| 90 | %----------------------- | |
| 91 | :- else. | |
| 92 | %----------------------- | |
| 93 | ||
| 94 | :- write('Using Prolog term_hash instead of probhash C SHA1 extension (can cause collisions!!)'),nl. | |
| 95 | ||
| 96 | :- use_module(probsrc(hashing),[my_term_hash/2]). | |
| 97 | hash_term(Term,Hash) :- my_term_hash(Term,Hash). | |
| 98 | hash_to_atom(Term,Hash) :- my_term_hash(Term,Hash). | |
| 99 | raw_sha_hash(Term,Hash) :- my_term_hash(Term,Hash). % TODO: convert to list | |
| 100 | ||
| 101 | raw_sha_hash_file(_,_,Span) :- | |
| 102 | add_error(probhash,'Not implemented: ',raw_sha_hash_file,Span),fail. | |
| 103 | ||
| 104 | :- endif. |