RosettaCodeData/Task/SHA-1/Zig/sha-1.zig

127 lines
4.1 KiB
Zig

const std = @import("std");
const SHA1 = struct {
const BLOCK_LENGTH: u32 = 64;
fn messageDigest(message: []const u8) ![40]u8 {
var state = [5]u32{ 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 };
const bytes = try addPadding(message);
var i: usize = 0;
while (i < bytes.len / BLOCK_LENGTH) : (i += 1) {
var values = [_]u32{0} ** 80;
var j: u32 = 0;
while (j < BLOCK_LENGTH) : (j += 1) {
values[j / 4] |= @as(u32, @intCast(bytes[i * BLOCK_LENGTH + j] & 0xff)) << @intCast((3 - j % 4) * 8);
}
j = 16;
while (j < 80) : (j += 1) {
const value = values[j - 3] ^ values[j - 8] ^ values[j - 14] ^ values[j - 16];
values[j] = std.math.rotl(u32, value, 1);
}
var a = state[0];
var b = state[1];
var c = state[2];
var d = state[3];
var e = state[4];
var f: u32 = 0;
var k: u32 = 0;
j = 0;
while (j < 80) : (j += 1) {
switch (j / 20) {
0 => {
f = (b & c) | (~b & d);
k = 0x5a827999;
},
1 => {
f = b ^ c ^ d;
k = 0x6ed9eba1;
},
2 => {
f = (b & c) | (b & d) | (c & d);
k = 0x8f1bbcdc;
},
3 => {
f = b ^ c ^ d;
k = 0xca62c1d6;
},
else => unreachable,
}
// Use wrapping add to prevent integer overflow panics
const rotated_a = std.math.rotl(u32, a, 5);
const temp = @addWithOverflow(rotated_a, f)[0];
const temp2 = @addWithOverflow(temp, e)[0];
const temp3 = @addWithOverflow(temp2, k)[0];
const temp4 = @addWithOverflow(temp3, values[j])[0];
e = d;
d = c;
c = std.math.rotl(u32, b, 30);
b = a;
a = temp4;
}
// Use wrapping adds for state updates
state[0] = @addWithOverflow(state[0], a)[0];
state[1] = @addWithOverflow(state[1], b)[0];
state[2] = @addWithOverflow(state[2], c)[0];
state[3] = @addWithOverflow(state[3], d)[0];
state[4] = @addWithOverflow(state[4], e)[0];
}
var result: [40]u8 = undefined;
var buffer: [8]u8 = undefined;
for (0..20) |my_i| {
const byte_value: u8 = @intCast((state[my_i / 4] >> @intCast(24 - (my_i % 4) * 8)) & 0xff);
_ = try std.fmt.bufPrint(buffer[0..2], "{x:0>2}", .{byte_value});
result[my_i * 2] = buffer[0];
result[my_i * 2 + 1] = buffer[1];
}
return result;
}
fn addPadding(message: []const u8) ![]u8 {
const allocator = std.heap.page_allocator;
// Initialize with the message
var bytes = std.ArrayList(u8).init(allocator);
defer bytes.deinit();
try bytes.appendSlice(message);
try bytes.append(0x80);
var padding: u32 = BLOCK_LENGTH - @as(u32, @intCast(bytes.items.len % BLOCK_LENGTH));
if (padding < 8) {
padding += BLOCK_LENGTH;
}
var i: u32 = 0;
while (i < padding - 8) : (i += 1) {
try bytes.append(0x0);
}
const bit_length: u64 = 8 * message.len;
i = 0;
while (i < 8) : (i += 1) {
const shift_amount: u6 = @intCast(8 * (7 - i)); // Explicit cast to u6 for shift
try bytes.append(@intCast((bit_length >> shift_amount) & 0xff));
}
return bytes.toOwnedSlice();
}
};
pub fn main() !void {
const message = "Rosetta Code";
const result = try SHA1.messageDigest(message);
const stdout = std.io.getStdOut().writer();
try stdout.print("{s}\n", .{result});
}