Coverage report: /home/ellis/comp/ext/ironclad/src/digests/sha3.lisp
Kind | Covered | All | % |
expression | 346 | 666 | 52.0 |
branch | 9 | 20 | 45.0 |
Key
Not instrumented
Conditionalized out
Executed
Not executed
Both branches taken
One branch taken
Neither branch taken
1
;;;; sha3.lisp -- implementation of SHA-3 from NIST
4
;;; Keccak state and parameters
5
(eval-when (:compile-toplevel :load-toplevel :execute)
6
(defconstant +keccak-state-columns+ 5)
7
(defconstant +keccak-state-rows+ 5)
8
(defconstant +keccak-state-lanes+ 25)
9
(defconstant +keccak-lane-width+ 64)
10
(defconstant +keccak-lane-byte-width+ 8)
11
(defconstant +keccak-rounds+ 24))
13
(deftype keccak-lane ()
14
`(unsigned-byte ,+keccak-lane-width+))
16
(deftype keccak-state ()
17
`(simple-array keccak-lane (,+keccak-state-lanes+)))
19
(eval-when (:compile-toplevel :load-toplevel :execute)
20
(defconst +keccak-rotate-offsets+
21
(make-array (list +keccak-state-columns+ +keccak-state-rows+)
22
:element-type '(unsigned-byte 8)
23
:initial-contents '(( 0 36 3 41 18)
29
(defconst +keccak-round-constants+
31
:element-type 'keccak-lane
32
:initial-contents '(#x0000000000000001
55
#x8000000080008008))))
57
(defmacro get-keccak-rotate-offset (x y &environment env)
58
(aref +keccak-rotate-offsets+
59
(eval (trivial-macroexpand-all x env))
60
(eval (trivial-macroexpand-all y env))))
62
(declaim (inline get-keccak-round-constant)
63
(ftype (function ((integer 0 23)) keccak-lane) get-keccak-round-constant))
64
(defun get-keccak-round-constant (i)
65
(declare (type (integer 0 23) i)
66
(optimize (speed 3) (space 0) (safety 0) (debug 0)))
67
(let ((constants (load-time-value +keccak-round-constants+ t)))
68
(declare (type (simple-array keccak-lane (24)) constants))
71
(declaim (inline make-keccak-state)
72
(ftype (function () keccak-state) make-keccak-state))
73
(defun make-keccak-state ()
74
(declare (optimize (speed 3) (space 0) (safety 0) (debug 0)))
75
(make-array #.+keccak-state-lanes+ :element-type 'keccak-lane :initial-element 0))
77
;;; Transforming linear input/output to state array
78
(defun keccak-state-merge-input (state bit-rate input start)
79
(declare (type keccak-state state)
80
(type (integer 0 1600) bit-rate)
81
(type (simple-array (unsigned-byte 8) (*)) input)
83
(optimize (speed 3) (space 0) (safety 0) (debug 0)))
84
(let ((rate-bytes (truncate bit-rate 8)))
85
(declare (type (integer 0 200) rate-bytes))
86
(dotimes (y +keccak-state-rows+)
87
(dotimes (x +keccak-state-columns+)
88
(let* ((element (+ (the fixnum (* y +keccak-state-columns+)) x))
89
(offset (* element +keccak-lane-byte-width+))
90
(index (the fixnum (+ start offset))))
91
(when (>= offset rate-bytes)
92
(return-from keccak-state-merge-input))
93
(setf (aref state element)
97
#.(loop for byte-index from 0 below +keccak-lane-byte-width+
98
collect `(the keccak-lane (ash (aref input (+ index ,byte-index))
99
,(* byte-index 8)))))))))))
101
(defun keccak-state-extract-output (state output-bytes)
102
(let ((digest (make-array (list output-bytes) :element-type '(unsigned-byte 8))))
103
(dotimes (x +keccak-state-columns+)
104
(dotimes (y +keccak-state-rows+)
105
(let* ((element (+ (* y +keccak-state-columns+) x))
106
(offset (* element +keccak-lane-byte-width+)))
107
(unless (>= offset output-bytes)
108
(loop with value = (aref state element)
109
for index from offset below (min (+ offset +keccak-lane-byte-width+) output-bytes)
110
do (setf (aref digest index) (ldb (byte 8 0) value)
111
value (ash value -8)))))))
115
(defmacro with-keccak-state-accessors ((&rest states) &body body)
116
"Bind the contents of the state(s) array(s) to local variables, and save
117
the content on normal form exit."
118
(let ((bindings nil) (mappings nil) (save-forms nil))
119
(loop for state in states
120
for map = (make-array '(#.+keccak-state-columns+ #.+keccak-state-rows+))
122
(dotimes (y +keccak-state-rows+)
123
(dotimes (x +keccak-state-columns+)
124
(let ((sym (make-symbol (format nil "~A-~D-~D" state x y))))
125
(setf (aref map x y) sym)
126
(push `(,sym (aref ,state ,(+ x (* y +keccak-state-columns+))))
128
(push `(setf (aref ,state ,(+ x (* y +keccak-state-columns+))) ,sym)
130
(push (cons state map) mappings))
132
(declare (ignorable ,@(mapcar #'car bindings))
133
(type keccak-lane ,@(mapcar #'car bindings)))
134
(macrolet ((state-aref (state x y &environment env)
135
(let ((entry (assoc state ',mappings)))
136
(unless entry (error 'ironclad-error
137
:format-control "Strange: ~S!"
138
:format-arguments (list state)))
140
(eval (trivial-macroexpand-all x env))
141
(eval (trivial-macroexpand-all y env))))))
142
(multiple-value-prog1 (progn ,@body)
145
(defmacro with-temp-keccak-state ((&rest temps) &body body)
146
"Bind local variables for each temporary state."
147
(let ((bindings nil) (mappings nil))
148
(loop for temp in temps
149
for map = (make-array '(#.+keccak-state-columns+ #.+keccak-state-rows+))
151
(dotimes (y +keccak-state-rows+)
152
(dotimes (x +keccak-state-columns+)
153
(let ((sym (make-symbol (format nil "~A-~D-~D" temp x y))))
154
(setf (aref map x y) sym)
155
(push `(,sym 0) bindings))))
156
(push (cons temp map) mappings))
158
(declare (ignorable ,@(mapcar #'car bindings))
159
(type keccak-lane ,@(mapcar #'car bindings)))
160
(macrolet ((temp-state-aref (temp x y &environment env)
161
(let ((entry (assoc temp ',mappings)))
162
(unless entry (error 'ironclad-error
163
:format-control "Strange: ~S!"
164
:format-arguments (list temp)))
166
(eval (trivial-macroexpand-all x env))
167
(eval (trivial-macroexpand-all y env))))))
170
(defmacro with-temp-keccak-rows ((&rest rows) &body body)
171
"Bind local variables for each temporary row."
172
(let ((bindings nil) (mappings nil))
173
(loop for row in rows
174
for map = (make-array '(#.+keccak-state-columns+))
176
(dotimes (x +keccak-state-columns+)
177
(let ((sym (make-symbol (format nil "~A-~D" row x))))
178
(setf (aref map x) sym)
179
(push `(,sym 0) bindings)))
180
(push (cons row map) mappings))
182
(declare (ignorable ,@(mapcar #'car bindings))
183
(type keccak-lane ,@(mapcar #'car bindings)))
184
(macrolet ((temp-row-aref (row x &environment env)
185
(let ((entry (assoc row ',mappings)))
186
(unless entry (error 'ironclad-error
187
:format-control "Strange: ~S!"
188
:format-arguments (list row)))
190
(eval (trivial-macroexpand-all x env))))))
193
(declaim (ftype (function (keccak-state)) keccak-rounds))
194
(defun keccak-rounds (state)
195
(declare (type keccak-state state)
196
(optimize (speed 3) (space 0) (safety 0) (debug 0)))
197
(with-keccak-state-accessors (state)
198
(with-temp-keccak-state (b)
199
(with-temp-keccak-rows (c d)
200
(dotimes (i #.+keccak-rounds+)
201
(dotimes-unrolled (x +keccak-state-columns+)
202
(setf (temp-row-aref c x)
203
(logxor (state-aref state x 0)
204
(state-aref state x 1)
205
(state-aref state x 2)
206
(state-aref state x 3)
207
(state-aref state x 4))))
208
(dotimes-unrolled (x +keccak-state-columns+)
209
(setf (temp-row-aref d x)
210
(logxor (temp-row-aref c (mod (+ +keccak-state-columns+ (1- x)) +keccak-state-columns+))
211
(rol64 (temp-row-aref c (mod (1+ x) +keccak-state-columns+)) 1))))
212
(dotimes-unrolled (x +keccak-state-columns+)
213
(dotimes-unrolled (y +keccak-state-rows+)
214
(setf (state-aref state x y)
215
(logxor (state-aref state x y) (temp-row-aref d x)))))
216
(dotimes-unrolled (x +keccak-state-columns+)
217
(dotimes-unrolled (y +keccak-state-rows+)
218
(setf (temp-state-aref b y (mod (+ (* 2 x) (* 3 y)) +keccak-state-rows+))
219
(rol64 (state-aref state x y) (get-keccak-rotate-offset x y)))))
220
(dotimes-unrolled (x +keccak-state-columns+)
221
(dotimes-unrolled (y +keccak-state-rows+)
222
(setf (state-aref state x y)
223
(logxor (temp-state-aref b x y)
224
(logandc1 (temp-state-aref b (mod (1+ x) +keccak-state-columns+) y)
225
(temp-state-aref b (mod (+ x 2) +keccak-state-columns+) y))))))
226
(setf (state-aref state 0 0) (logxor (state-aref state 0 0)
227
(get-keccak-round-constant i)))))))
230
;;; Message Padding for last block
231
(defun pad-message-to-width (message bit-width padding-type)
232
(let* ((message-byte-length (length message))
233
(width-bytes (truncate bit-width 8))
234
(padding-bytes (- width-bytes (mod message-byte-length width-bytes)))
235
(padded-message-byte-length (+ message-byte-length padding-bytes))
236
(padded-message (make-array padded-message-byte-length :element-type '(unsigned-byte 8))))
237
(replace padded-message message :end2 message-byte-length)
238
(setf (aref padded-message message-byte-length) (ecase padding-type
242
(loop for index from (1+ message-byte-length) below padded-message-byte-length
243
do (setf (aref padded-message index) #x00))
244
(setf (aref padded-message (1- padded-message-byte-length))
245
(logior #x80 (aref padded-message (1- padded-message-byte-length))))
250
(:constructor %make-sha3-digest nil)
252
(state (make-keccak-state) :type keccak-state)
253
(bit-rate 576 :type (integer 0 1600))
254
(buffer (make-array 200 :element-type '(unsigned-byte 8))
255
:type (simple-array (unsigned-byte 8) (200)))
256
(buffer-index 0 :type (integer 0 199))
261
(:constructor %make-sha3/384-digest
268
(:constructor %make-sha3/256-digest
269
(&aux (bit-rate 1088)
275
(:constructor %make-sha3/224-digest
276
(&aux (bit-rate 1152)
282
(:constructor %make-keccak-digest
287
(defstruct (keccak/384
289
(:constructor %make-keccak/384-digest
294
(defstruct (keccak/256
296
(:constructor %make-keccak/256-digest
297
(&aux (bit-rate 1088)
301
(defstruct (keccak/224
303
(:constructor %make-keccak/224-digest
304
(&aux (bit-rate 1152)
310
(:constructor %make-shake256 (bit-rate output-length))
315
(:constructor %make-shake128 (bit-rate output-length))
318
(defun %make-shake256-digest (&key (output-length 32))
319
(%make-shake256 1088 output-length))
321
(defun %make-shake128-digest (&key (output-length 16))
322
(%make-shake128 1344 output-length))
324
(defmethod block-length ((state shake256))
327
(defmethod block-length ((state shake128))
330
(defmethod digest-length ((state shake256))
331
(sha3-output-length state))
333
(defmethod digest-length ((state shake128))
334
(sha3-output-length state))
336
(defmethod reinitialize-instance ((state sha3) &rest initargs)
337
(declare (ignore initargs))
338
(setf (sha3-state state) (make-keccak-state))
339
(setf (sha3-buffer-index state) 0)
342
(defmethod copy-digest ((state sha3) &optional copy)
343
(check-type copy (or null sha3))
347
(shake128 (%make-shake128-digest))
348
(shake256 (%make-shake256-digest))
349
(keccak/224 (%make-keccak/224-digest))
350
(keccak/256 (%make-keccak/256-digest))
351
(keccak/384 (%make-keccak/384-digest))
352
(keccak (%make-keccak-digest))
353
(sha3/224 (%make-sha3/224-digest))
354
(sha3/256 (%make-sha3/256-digest))
355
(sha3/384 (%make-sha3/384-digest))
356
(sha3 (%make-sha3-digest))))))
357
(declare (type sha3 copy))
358
(replace (sha3-state copy) (sha3-state state))
359
(setf (sha3-bit-rate copy) (sha3-bit-rate state))
360
(replace (sha3-buffer copy) (sha3-buffer state))
361
(setf (sha3-buffer-index copy) (sha3-buffer-index state))
362
(setf (sha3-output-length copy) (sha3-output-length state))
365
(defun sha3-update (state vector start end)
366
(declare (type sha3 state)
367
(type (simple-array (unsigned-byte 8) (*)) vector)
368
(type fixnum start end)
369
(optimize (speed 3) (safety 0) (space 0) (debug 0)))
370
(let* ((keccak-state (sha3-state state))
371
(buffer (sha3-buffer state))
372
(buffer-index (sha3-buffer-index state))
373
(bit-rate (sha3-bit-rate state))
374
(rate-bytes (truncate bit-rate 8)))
375
(declare (type keccak-state keccak-state)
376
(type (simple-array (unsigned-byte 8) (200)) buffer)
377
(type (integer 0 199) buffer-index)
378
(type (integer 0 1600) bit-rate)
379
(type (integer 0 200) rate-bytes))
381
;; Handle potential remaining bytes
382
(unless (zerop buffer-index)
383
(let ((remainder (- rate-bytes buffer-index))
384
(length (- end start)))
385
(declare (type fixnum remainder length))
386
(replace buffer vector :start1 buffer-index :end1 rate-bytes :start2 start :end2 end)
388
;; Return if still unfilled buffer
389
(when (< length remainder)
390
(incf (sha3-buffer-index state) length)
391
(return-from sha3-update))
393
;; Else handle now complete buffer
394
(keccak-state-merge-input keccak-state bit-rate buffer 0)
395
(keccak-rounds keccak-state)
396
(setf (sha3-buffer-index state) 0)
397
(setf start (+ start remainder))))
399
;; Now handle full blocks, stuff any remainder into buffer
400
(loop for block-offset of-type fixnum from start below end by rate-bytes
402
((<= (+ block-offset rate-bytes) end)
403
(keccak-state-merge-input keccak-state bit-rate vector block-offset)
404
(keccak-rounds keccak-state))
406
(replace buffer vector :start1 0 :end1 rate-bytes :start2 block-offset :end2 end)
407
(setf (sha3-buffer-index state) (- end block-offset))))))
410
(defun sha3-finalize (state digest digest-start)
411
(declare (type sha3 state)
412
(type (simple-array (unsigned-byte 8) (*)) digest)
413
(type integer digest-start)
414
(optimize (speed 3) (safety 1) (space 0) (debug 0)))
415
(let ((padding-type (typecase state
423
(keccak-state (sha3-state state))
424
(buffer (sha3-buffer state))
425
(buffer-index (sha3-buffer-index state))
426
(bit-rate (sha3-bit-rate state))
427
(output-byte-length (digest-length state)))
428
(declare (type keccak-state keccak-state)
429
(type (simple-array (unsigned-byte 8) (200)) buffer)
430
(type (integer 0 199) buffer-index)
431
(type (integer 0 1600) bit-rate)
432
(type integer output-byte-length))
434
;; Process remaining data after padding it
435
(keccak-state-merge-input keccak-state
437
(pad-message-to-width (subseq buffer 0 buffer-index)
441
(keccak-rounds keccak-state)
442
(setf (sha3-buffer-index state) 0)
445
(let ((output-size 0)
446
(chunk-size (truncate bit-rate 8)))
447
(loop until (= output-size output-byte-length) do
448
(let* ((n (min (- output-byte-length output-size) chunk-size))
449
(output (keccak-state-extract-output keccak-state n)))
450
(replace digest output :start1 (+ digest-start output-size) :end2 n)
452
(keccak-rounds keccak-state))))
455
(define-digest-updater sha3
456
(sha3-update state sequence start end))
458
(define-digest-finalizer ((sha3 64)
466
(sha3-finalize state digest digest-start))
468
(defdigest sha3 :digest-length 64 :block-length 72)
469
(defdigest sha3/384 :digest-length 48 :block-length 104)
470
(defdigest sha3/256 :digest-length 32 :block-length 136)
471
(defdigest sha3/224 :digest-length 28 :block-length 144)
473
(defdigest keccak :digest-length 64 :block-length 72)
474
(defdigest keccak/384 :digest-length 48 :block-length 104)
475
(defdigest keccak/256 :digest-length 32 :block-length 136)
476
(defdigest keccak/224 :digest-length 28 :block-length 144)
478
(defmethod produce-digest ((state shake256) &key digest (digest-start 0))
479
(let ((digest-size (digest-length state))
480
(state-copy (copy-digest state)))
482
(if (> digest-size (- (length digest) digest-start))
483
(error 'insufficient-buffer-space
484
:buffer digest :start digest-start
486
(sha3-finalize state-copy digest digest-start))
487
(sha3-finalize state-copy
488
(make-array digest-size :element-type '(unsigned-byte 8))
491
(defmethod produce-digest ((state shake128) &key digest (digest-start 0))
492
(let ((digest-size (digest-length state))
493
(state-copy (copy-digest state)))
495
(if (> digest-size (- (length digest) digest-start))
496
(error 'insufficient-buffer-space
497
:buffer digest :start digest-start
499
(sha3-finalize state-copy digest digest-start))
500
(sha3-finalize state-copy
501
(make-array digest-size :element-type '(unsigned-byte 8))
504
(setf (get 'shake256 '%digest-length) 32)
505
(setf (get 'shake256 '%make-digest) (symbol-function '%make-shake256-digest))
506
(setf (get 'shake128 '%digest-length) 16)
507
(setf (get 'shake128 '%make-digest) (symbol-function '%make-shake128-digest))