lib/reticulum/src/hash.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

 1 const std = @import("std");
 2 
 3 const Sha256 = std.crypto.hash.sha2.Sha256;
 4 
 5 /// 32 bytes, the width of a complete SHA-256 digest, following Reticulum@1.5.0
 6 /// RNS/Identity.py:352.
 7 pub const full_bytes: usize = 32;
 8 /// 16 bytes, the width a destination hash and an identity hash take on the
 9 /// wire, following Reticulum@1.5.0 RNS/Identity.py:362 and Reticulum@1.5.0
10 /// RNS/Reticulum.py:148.
11 pub const truncated_bytes: usize = 16;
12 /// 10 bytes, the width a destination's announced name hash and a rotating key's
13 /// identifier take, following Reticulum@1.5.0 RNS/Identity.py:83.
14 pub const name_bytes: usize = 10;
15 
16 /// Returns the complete 32-byte SHA-256 digest of some bytes, following
17 /// Reticulum@1.5.0 RNS/Identity.py:352.
18 pub fn full(bytes: []const u8) [full_bytes]u8 {
19     var hasher = Hasher.init();
20     hasher.update(bytes);
21     return hasher.finalFull();
22 }
23 
24 /// Returns the first 16 bytes of the SHA-256 digest of some bytes, following
25 /// Reticulum@1.5.0 RNS/Identity.py:362 and Reticulum@1.5.0
26 /// RNS/Reticulum.py:148.
27 pub fn truncated(bytes: []const u8) [truncated_bytes]u8 {
28     var hasher = Hasher.init();
29     hasher.update(bytes);
30     return hasher.finalTruncated();
31 }
32 
33 /// Returns the first 10 bytes of the SHA-256 digest of some bytes, following
34 /// Reticulum@1.5.0 RNS/Identity.py:83 and Reticulum@1.5.0
35 /// RNS/Destination.py:120.
36 pub fn name(bytes: []const u8) [name_bytes]u8 {
37     var hasher = Hasher.init();
38     hasher.update(bytes);
39     return hasher.finalName();
40 }
41 
42 /// A SHA-256 state that takes its input in pieces and then gives any of the
43 /// three widths. Reticulum hashes joined transcripts, so a caller feeds the
44 /// pieces in turn and needs no buffer holding them all at once. Taking a digest
45 /// works on a copy of the state, so one hasher gives more than one width.
46 pub const Hasher = struct {
47     state: Sha256,
48 
49     pub fn init() Hasher {
50         return .{ .state = Sha256.init(.{}) };
51     }
52 
53     pub fn update(self: *Hasher, bytes: []const u8) void {
54         self.state.update(bytes);
55     }
56 
57     pub fn finalFull(self: Hasher) [full_bytes]u8 {
58         var state = self.state;
59         var result: [full_bytes]u8 = undefined;
60         state.final(&result);
61         return result;
62     }
63 
64     pub fn finalTruncated(self: Hasher) [truncated_bytes]u8 {
65         const result = self.finalFull();
66         return result[0..truncated_bytes].*;
67     }
68 
69     pub fn finalName(self: Hasher) [name_bytes]u8 {
70         const result = self.finalFull();
71         return result[0..name_bytes].*;
72     }
73 };