Coverage report: /home/ellis/comp/ext/ironclad/src/macs/siphash.lisp
Kind | Covered | All | % |
expression | 0 | 271 | 0.0 |
branch | 0 | 18 | 0.0 |
Key
Not instrumented
Conditionalized out
Executed
Not executed
Both branches taken
One branch taken
Neither branch taken
1
;;;; siphash.lisp -- implementation of the SipHash MAC
4
(defclass siphash (mac)
5
((state :accessor siphash-state
6
:initform (make-array 4 :element-type '(unsigned-byte 64))
7
:type (simple-array (unsigned-byte 64) (4)))
8
(compression-rounds :accessor siphash-compression-rounds
9
:initarg :compression-rounds
12
(finalization-rounds :accessor siphash-finalization-rounds
13
:initarg :finalization-rounds
16
(digest-length :accessor siphash-digest-length
17
:initarg :digest-length
20
(data-length :accessor siphash-data-length
23
(buffer :accessor siphash-buffer
24
:initform (make-array 8 :element-type '(unsigned-byte 8))
25
:type (simple-array (unsigned-byte 8) (8)))
26
(buffer-length :accessor siphash-buffer-length
28
:type (integer 0 8))))
30
(defun make-siphash (key &key (compression-rounds 2) (finalization-rounds 4) (digest-length 8))
31
(declare (type (simple-array (unsigned-byte 8) (*)) key))
32
(unless (= (length key) 16)
33
(error 'invalid-mac-parameter
35
:message "The key length must be 16 bytes"))
36
(unless (or (= digest-length 8) (= digest-length 16))
37
(error 'invalid-mac-parameter
39
:message "The digest length must be 8 or 16 bytes"))
40
(make-instance 'siphash
42
:compression-rounds compression-rounds
43
:finalization-rounds finalization-rounds
44
:digest-length digest-length))
46
(defmethod shared-initialize :after ((mac siphash) slot-names &rest initargs &key key &allow-other-keys)
47
(declare (ignore slot-names initargs)
48
(type (simple-array (unsigned-byte 8) (16)) key))
49
(let ((state (siphash-state mac))
50
(k0 (ub64ref/le key 0))
51
(k1 (ub64ref/le key 8)))
52
(declare (type (simple-array (unsigned-byte 64) (4)) state)
53
(type (unsigned-byte 64) k0 k1))
54
(setf (aref state 0) (logxor k0 #x736f6d6570736575)
55
(aref state 1) (logxor k1 #x646f72616e646f6d)
56
(aref state 2) (logxor k0 #x6c7967656e657261)
57
(aref state 3) (logxor k1 #x7465646279746573))
58
(when (= (siphash-digest-length mac) 16)
59
(setf (aref state 1) (logxor (aref state 1) #xee)))
60
(setf (siphash-data-length mac) 0)
61
(setf (siphash-buffer-length mac) 0)
64
(defmacro siphash-round (v0 v1 v2 v3)
65
`(setf ,v0 (mod64+ ,v0 ,v1)
80
(defun siphash-compress (state data start remaining data-length n-rounds)
81
(declare (type (simple-array (unsigned-byte 64) (4)) state)
82
(type (simple-array (unsigned-byte 8) (*)) data)
83
(type fixnum start remaining data-length n-rounds)
84
(optimize (speed 3) (space 0) (safety 0) (debug 0)))
85
(let ((v0 (aref state 0))
89
(declare (type (unsigned-byte 64) v0 v1 v2 v3))
92
(declare (type (unsigned-byte 64) m))
93
(setf m (ub64ref/le data start))
94
(setf v3 (logxor v3 m))
96
(siphash-round v0 v1 v2 v3))
97
(setf v0 (logxor v0 m))
101
(setf (aref state 0) v0
105
(values start remaining data-length)))
107
(defun siphash-finalize (state n-rounds tag)
108
(declare (type (simple-array (unsigned-byte 64) (4)) state)
109
(type (simple-array (unsigned-byte 8) (*)) tag)
110
(type fixnum n-rounds)
111
(optimize (speed 3) (space 0) (safety 0) (debug 0)))
112
(let ((digest-length (length tag))
117
(declare (type fixnum digest-length)
118
(type (unsigned-byte 64) v0 v1 v2 v3))
119
(setf v2 (logxor v2 (if (= digest-length 16) #xee #xff)))
120
(dotimes (i n-rounds)
121
(siphash-round v0 v1 v2 v3))
122
(setf (ub64ref/le tag 0) (logxor v0 v1 v2 v3))
123
(when (= digest-length 16)
124
(setf v1 (logxor v1 #xdd))
125
(dotimes (i n-rounds)
126
(siphash-round v0 v1 v2 v3))
127
(setf (ub64ref/le tag 8) (logxor v0 v1 v2 v3)))
130
(defun update-siphash (mac data &key (start 0) (end (length data)))
131
(declare (type (simple-array (unsigned-byte 8) (*)) data)
132
(type fixnum start end)
133
(optimize (speed 3) (space 0) (safety 1) (debug 0)))
134
(let ((buffer (siphash-buffer mac))
135
(buffer-length (siphash-buffer-length mac))
136
(state (siphash-state mac))
137
(n-rounds (siphash-compression-rounds mac))
138
(data-length (siphash-data-length mac))
139
(remaining (- end start)))
140
(declare (type (simple-array (unsigned-byte 8) (8)) buffer)
141
(type (integer 0 8) buffer-length)
142
(type (simple-array (unsigned-byte 64) (4)) state)
143
(type fixnum n-rounds data-length remaining))
145
;; Fill the buffer with new data if necessary
146
(when (plusp buffer-length)
147
(let ((n (min remaining (- 8 buffer-length))))
148
(declare (type (integer 0 8) n))
150
:start1 buffer-length
153
(incf buffer-length n)
158
;; Process the buffer
159
(when (= buffer-length 8)
160
(siphash-compress state buffer 0 8 data-length n-rounds)
161
(setf buffer-length 0))
164
;; TODO: (siphash-process-full-blocks ...)
165
(multiple-value-setq (start remaining data-length)
166
(siphash-compress state data start remaining data-length n-rounds))
168
;; Put the remaining data in the buffer
169
(when (plusp remaining)
170
(replace buffer data :start1 0 :start2 start :end2 end)
171
(incf data-length remaining)
172
(setf buffer-length remaining))
175
(setf (siphash-data-length mac) data-length)
176
(setf (siphash-buffer-length mac) buffer-length)
179
(defun siphash-digest (mac)
180
(let ((buffer (copy-seq (siphash-buffer mac)))
181
(buffer-length (siphash-buffer-length mac))
182
(state (copy-seq (siphash-state mac)))
183
(compression-rounds (siphash-compression-rounds mac))
184
(finalization-rounds (siphash-finalization-rounds mac))
185
(digest-length (siphash-digest-length mac))
186
(data-length (siphash-data-length mac)))
187
(declare (type (simple-array (unsigned-byte 8) (8)) buffer)
188
(type (integer 0 8) buffer-length)
189
(type (simple-array (unsigned-byte 64) (4)) state)
190
(type fixnum compression-rounds finalization-rounds digest-length data-length)
191
(dynamic-extent buffer state))
193
;; Pad and process the buffer
194
(fill buffer 0 :start buffer-length)
195
(setf (aref buffer 7) (mod data-length 256))
196
(siphash-compress state buffer 0 8 data-length compression-rounds)
199
(let ((tag (make-array digest-length :element-type '(unsigned-byte 8))))
200
(siphash-finalize state finalization-rounds tag)