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.