authorgravatar for quae@daurnimator.comdaurnimator <quae@daurnimator.com> 2019-06-16 03:02:47+10:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-06-16 22:55:38-04:00
log6ce2a03985db3094634742ae2209477de998e70a
treef36a10a088f774aaf48b5ead7e9e228bea429601
parent72029c2fc8083b1c0f2501cfc9e24d3fca4d66c2

std: add gimli permutation to crypto


3 files changed, 172 insertions(+), 0 deletions(-)

CMakeLists.txt+1
......@@ -479,6 +479,7 @@ set(ZIG_STD_FILES
479479 "crypto.zig"
480480 "crypto/blake2.zig"
481481 "crypto/chacha20.zig"
482 "crypto/gimli.zig"
482483 "crypto/hmac.zig"
483484 "crypto/md5.zig"
484485 "crypto/poly1305.zig"
std/crypto.zig+3
......@@ -13,6 +13,8 @@ pub const Sha3_256 = sha3.Sha3_256;
1313pub const Sha3_384 = sha3.Sha3_384;
1414pub const Sha3_512 = sha3.Sha3_512;
1515
16pub const gimli = @import("crypto/gimli.zig");
17
1618const blake2 = @import("crypto/blake2.zig");
1719pub const Blake2s224 = blake2.Blake2s224;
1820pub const Blake2s256 = blake2.Blake2s256;
......@@ -38,6 +40,7 @@ pub const randomBytes = std.os.getrandom;
3840test "crypto" {
3941 _ = @import("crypto/blake2.zig");
4042 _ = @import("crypto/chacha20.zig");
43 _ = @import("crypto/gimli.zig");
4144 _ = @import("crypto/hmac.zig");
4245 _ = @import("crypto/md5.zig");
4346 _ = @import("crypto/poly1305.zig");
std/crypto/gimli.zig created+168
......@@ -0,0 +1,168 @@
1// Gimli is a 384-bit permutation designed to achieve high security with high
2// performance across a broad range of platforms, including 64-bit Intel/AMD
3// server CPUs, 64-bit and 32-bit ARM smartphone CPUs, 32-bit ARM
4// microcontrollers, 8-bit AVR microcontrollers, FPGAs, ASICs without
5// side-channel protection, and ASICs with side-channel protection.
6//
7// https://gimli.cr.yp.to/
8// https://csrc.nist.gov/CSRC/media/Projects/Lightweight-Cryptography/documents/round-1/spec-doc/gimli-spec.pdf
9
10const std = @import("../std.zig");
11const mem = std.mem;
12const math = std.math;
13const debug = std.debug;
14const assert = std.debug.assert;
15const testing = std.testing;
16const htest = @import("test.zig");
17
18pub const State = struct {
19 pub const BLOCKBYTES = 48;
20 pub const RATE = 16;
21
22 // TODO: https://github.com/ziglang/zig/issues/2673#issuecomment-501763017
23 data: [BLOCKBYTES / 4]u32,
24
25 const Self = @This();
26
27 pub fn toSlice(self: *Self) []u8 {
28 return @sliceToBytes(self.data[0..]);
29 }
30
31 pub fn toSliceConst(self: *Self) []const u8 {
32 return @sliceToBytes(self.data[0..]);
33 }
34
35 pub fn permute(self: *Self) void {
36 const state = &self.data;
37 var round = u32(24);
38 while (round > 0) : (round -= 1) {
39 var column = usize(0);
40 while (column < 4) : (column += 1) {
41 const x = math.rotl(u32, state[column], 24);
42 const y = math.rotl(u32, state[4 + column], 9);
43 const z = state[8 + column];
44 state[8 + column] = ((x ^ (z << 1)) ^ ((y & z) << 2));
45 state[4 + column] = ((y ^ x) ^ ((x | z) << 1));
46 state[column] = ((z ^ y) ^ ((x & y) << 3));
47 }
48 switch (round & 3) {
49 0 => {
50 mem.swap(u32, &state[0], &state[1]);
51 mem.swap(u32, &state[2], &state[3]);
52 state[0] ^= round | 0x9e377900;
53 },
54 2 => {
55 mem.swap(u32, &state[0], &state[2]);
56 mem.swap(u32, &state[1], &state[3]);
57 },
58 else => {},
59 }
60 }
61 }
62
63 pub fn squeeze(self: *Self, out: []u8) void {
64 var i = usize(0);
65 while (i + RATE <= out.len) : (i += RATE) {
66 self.permute();
67 mem.copy(u8, out[i..], self.toSliceConst()[0..RATE]);
68 }
69 const leftover = out.len - i;
70 if (leftover != 0) {
71 self.permute();
72 mem.copy(u8, out[i..], self.toSliceConst()[0..leftover]);
73 }
74 }
75};
76
77test "permute" {
78 // test vector from gimli-20170627
79 var state = State{
80 .data = blk: {
81 var input: [12]u32 = undefined;
82 var i = u32(0);
83 while (i < 12) : (i += 1) {
84 input[i] = i * i * i + i *% 0x9e3779b9;
85 }
86 testing.expectEqualSlices(u32, input, [_]u32{
87 0x00000000, 0x9e3779ba, 0x3c6ef37a, 0xdaa66d46,
88 0x78dde724, 0x1715611a, 0xb54cdb2e, 0x53845566,
89 0xf1bbcfc8, 0x8ff34a5a, 0x2e2ac522, 0xcc624026,
90 });
91 break :blk input;
92 },
93 };
94 state.permute();
95 testing.expectEqualSlices(u32, state.data, [_]u32{
96 0xba11c85a, 0x91bad119, 0x380ce880, 0xd24c2c68,
97 0x3eceffea, 0x277a921c, 0x4f73a0bd, 0xda5a9cd8,
98 0x84b673f0, 0x34e52ff7, 0x9e2bef49, 0xf41bb8d6,
99 });
100}
101
102pub const Hash = struct {
103 state: State,
104 buf_off: usize,
105
106 const Self = @This();
107
108 pub fn init() Self {
109 return Self{
110 .state = State{
111 .data = [_]u32{0} ** (State.BLOCKBYTES / 4),
112 },
113 .buf_off = 0,
114 };
115 }
116
117 /// Also known as 'absorb'
118 pub fn update(self: *Self, data: []const u8) void {
119 const buf = self.state.toSlice();
120 var in = data;
121 while (in.len > 0) {
122 var left = State.RATE - self.buf_off;
123 if (left == 0) {
124 self.state.permute();
125 self.buf_off = 0;
126 left = State.RATE;
127 }
128 const ps = math.min(in.len, left);
129 for (buf[self.buf_off .. self.buf_off + ps]) |*p, i| {
130 p.* ^= in[i];
131 }
132 self.buf_off += ps;
133 in = in[ps..];
134 }
135 }
136
137 /// Finish the current hashing operation, writing the hash to `out`
138 ///
139 /// From 4.9 "Application to hashing"
140 /// By default, Gimli-Hash provides a fixed-length output of 32 bytes
141 /// (the concatenation of two 16-byte blocks). However, Gimli-Hash can
142 /// be used as an “extendable one-way function” (XOF).
143 pub fn final(self: *Self, out: []u8) void {
144 const buf = self.state.toSlice();
145
146 // XOR 1 into the next byte of the state
147 buf[self.buf_off] ^= 1;
148 // XOR 1 into the last byte of the state, position 47.
149 buf[buf.len - 1] ^= 1;
150
151 self.state.squeeze(out);
152 }
153};
154
155pub fn hash(out: []u8, in: []const u8) void {
156 var st = Hash.init();
157 st.update(in);
158 st.final(out);
159}
160
161test "hash" {
162 // a test vector (30) from NIST KAT submission.
163 var msg: [58 / 2]u8 = undefined;
164 try std.fmt.hexToBytes(&msg, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C");
165 var md: [32]u8 = undefined;
166 hash(&md, msg);
167 htest.assertEqual("1C9A03DC6A5DDC5444CFC6F4B154CFF5CF081633B2CEA4D7D0AE7CCFED5AAA44", md);
168}