17 Commits

Author SHA1 Message Date
a4baa05e72 Switch to 16bit implementation for Lispworks8 64bit
This avoids an optimization problem in keccak-state-merge-input and is
also slightly faster due to less consing in this variant.
2023-08-21 22:29:49 +02:00
92e0e0b916 Update docs and copyrights for 1.1.1 release 2018-02-24 13:08:14 +01:00
de40c49ce9 Fix ACL results due to adjust-array anomaly
The old code relied on adjust-array of a simple-array yielding a new
simple-array, which is the case on most implementations and corresponds
with my reading of the standard. However ACL returns a non-simple array
in this case, which would later on clash with the declared types in
keccak-state-merge-input, leading to erroneous data accesses and
possible non-termination, etc. Since our use of adjust-array is not
central to the pad-message-to-width function, and that function is not
really performance critical (only called once during the digest
finalization), we just switch to new allocation and replace.
2018-02-24 12:56:32 +01:00
55979bd429 Change README to markdown syntax, add CI status 2018-02-23 12:52:12 +01:00
0aca46e76c Fix travis CI build for clisp/ecl 2018-02-23 02:20:56 +01:00
5d6f1bb7f2 Add Travis CI setup 2018-02-23 02:04:01 +01:00
41d5059acc Added testing with SHA3 test vectors from Keccak Code Package. 2016-09-14 17:37:59 +02:00
02ccb5d139 Adjust documentation for release 1.1.0, adjust copyrights. 2016-09-14 16:55:42 +02:00
abe192b75f Fix erroneous buffer handling in sha3-update again (fixes #3). 2016-09-14 16:48:31 +02:00
e57d7c32cd Make sha3 wrapper functions match FIPS 202 suffix appending.
The final FIPS 202 SHA-3 standard mandates the prepending of a
01 suffix to the message prior to padding, which the original
Keccak submission did not specify.  This change adjusts all
sha3 wrappers to behave standard conforming, and adds an optional
keyword argument raw-keccak-p to specify the original treatment.
Fixes #2.
2016-09-13 01:21:58 +02:00
5f50f7eca4 Adjust version number info in ASDF definition. 2013-11-21 13:43:17 +01:00
ec555c785c Add notice of the partial buffer bug to README. 2013-09-15 13:15:18 +02:00
a9cd1d2d5e Fix sha3.asd ident breakage again. 2013-09-15 13:09:23 +02:00
c89cddace7 Update NEWS for 1.0.2 release. 2013-09-15 00:27:57 +02:00
fc1c70579e Remove superfluous final iteration in sha3-update.
The superfluous last iteration when start = end wasn't harmful, since the
iteration body winds up as a no-op in that case anyway, but wasn't
intended or needed.
2013-09-14 23:57:51 +02:00
9391b65603 Fix buffer handling for partial updates (fix #1).
Calls to sha3-update that did not completely fill an already partially
filled buffer were handled incorrectly, in that the buffer-index wasn't
properly updated. Thanks to Orivej Desh for the bug report.
2013-09-14 23:55:52 +02:00
4cb18313ac Fix .gitattributes settings and spurious ids. 2013-09-14 23:45:09 +02:00
14 changed files with 332 additions and 161 deletions

4
.gitattributes vendored
View File

@ -1,2 +1,2 @@
/*.lisp ident *.lisp ident
/*.asd ident *.asd ident

27
.travis.yml Normal file
View File

@ -0,0 +1,27 @@
language: lisp
sudo: required
env:
matrix:
- LISP=abcl
- LISP=allegro
- LISP=sbcl
- LISP=sbcl32
- LISP=ccl
- LISP=ccl32
- LISP=clisp
- LISP=clisp32
- LISP=ecl
install:
- curl -L https://github.com/luismbo/cl-travis/raw/master/install.sh | sh
- git clone https://github.com/gvanas/KeccakCodePackage.git
script:
- cl -e '(asdf:load-system "sha3")
(load (compile-file "keccak-reference.lisp"))
(unless (keccak:test-sha3-msgkat "KeccakCodePackage/TestVectors/"
(lambda (cl-user::total-bits cl-user::bit-rate cl-user::output-bits cl-user::message)
(declare (ignore cl-user::total-bits cl-user::bit-rate))
(sha3:sha3-digest-vector cl-user::message :output-bit-length cl-user::output-bits)))
(uiop:quit 1))'

2
COPYING Normal file → Executable file
View File

@ -1,4 +1,4 @@
Copyright (C) 2012 PMSF IT Consulting Pierre R. Mai Copyright (C) 2012 -- 2018 PMSF IT Consulting Pierre R. Mai
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the a copy of this software and associated documentation files (the

37
NEWS Normal file → Executable file
View File

@ -1,3 +1,40 @@
Release 1.1.2
=============
* Switch to 16bit implementation for 64bit LispWorks 8, to avoid
compiler optimization problems in keccak-state-merge-input, and
also slightly higher performance due to non-consing.
Release 1.1.1
=============
* Fix a bug in pad-message-to-width on ACL, which would lead to
completely erroneous results being calculated for all inputs
due to differences in the result of adjust-array between ACL
and all other currently supported implementations.
Release 1.1.0
=============
* Change sha3 functions to match the final FIPS 202 SHA3 standard,
by appending a 01 suffix to messages prior to digest calculation.
The old Keccak submission behavior can be retained by passing in
the new raw-keccak-p keyword argument with true to the relevant
functions. Thanks to David McClain for prompting this change.
* Fixes a bug in the bug fix of release 1.0.2 for the sha3-update
handling of not completely filled buffers reported by David McClain,
which could lead to out-of-bounds accesses in calls to the
pad-message-to-width function.
Release 1.0.2
=============
* Fixes a bug reported by Orivej Desh where two or more calls to
sha3-update which didn't fill the buffer could lead to the second
and later updates being ignored, thereby creating wrong message
digests.
Release 1.0.1 Release 1.0.1
============= =============

114
README
View File

@ -1,114 +0,0 @@
This library is an implementation of the Secure Hash Algorithm 3
(SHA-3), also known as Keccak. The implementation is constrained to
messages with an integral number of octets, i.e. sub-byte length
messages are not supported.
The code should be portable across nearly all ANSI compliant CL
implementations with specialized versions tuned for implementations
that offer unboxed 64bit arithmetic, unboxed 32bit arithmetic and for
implementations with efficient fixnum arithmetic (requiring fixnums
that can represent (unsigned-byte 16)). Especially the 64 and 32bit
implementations have been mostly optimized for SBCL and CMU CL. For
those implementations, digests with a 1024 bit-rate (and 288 bit
digest output) can be generated in between 30 (64bit SBCL) to around
100 (32bit CMU CL) cycles/byte on an i7-640M; whereas optimized
C/assembler implementations reach around 12 to 50 cycles/byte on 64/32
bit Intel hardware. The reason for the discrepancy probably lies in
missing peephole and dependency optimizations in the SBCL/CMU CL
compiler backend.
The mid-level interfaces to the digest routines are the functions
- sha3:sha3-init &key output-bit-length bit-rate
Create and return a new SHA-3 state. If `output-bit-length' is
specified then the state will run at the bit rate specified for the
given output bit length. If `output-bit-length' is unspecified,
`bit-rate' can be specified to select a suitable bit rate. If both
are left unspecified then a default bit rate of 1024 bits is
selected, which is suitable for arbitrary output bit lengths of up
to 288 bits.
- sha3:sha3-copy state
Return an independent copy of the SHA-3 state `state'.
- sha3:sha3-state-p state
Test whether a given object is a SHA-3 state, i.e. is an instance of
the class sha3:sha3-state.
- sha3:sha3-update state vector &key (start 0) (end (length vector))
Update the given SHA-3 state `state' from `vector', which must be a
simple-array with element-type (unsigned-byte 8), bounded by `start'
and `end', which must be numeric bounding-indices.
- sha3:sha3-final state &key output-bit-length
If the given SHA-3 state `state' has not already been finalized,
finalize it by processing any remaining input in its buffer, with
suitable padding as specified by the SHA-3 standard. Returns the
message digest as a simple-array of (unsigned-byte 8). The length
of the returned digest is determined either by the output bit length
or bit rate specified on state creation, or for the special case of
default parameters being used, by the optional keyword argument
`output-bit-length'. If the state has previously been finalized,
the function will return the digest again.
For convenience the following high-level functions produce digests in
one step from 1d simple-arrays and streams with element-type
(unsigned-byte 8), as well as files:
- sha3:sha3-digest-vector vector &key (start 0) end (output-bit-length 512)
Calculate an SHA-3 message-digest of data in `vector', which should
be a 1d simple-array with element type (unsigned-byte 8), bounded by
`start' and `end'. The bit length of the message digest produced is
controlled by `output-bit-length', which can take on the values 224,
256, 288, 384 and 512, which is the default value.
- sha3:sha3-digest-stream stream &key (output-bit-length 512)
Calculate an SHA-3 message-digest of data read from `stream', which
should be a stream with element type (unsigned-byte 8). The bit
length of the message digest produced is controlled by
`output-bit-length', which can take on the values 224, 256, 288, 384
and 512, which is the default value.
- sha3:sha3-digest-file pathname &key (output-bit-length 512)
Calculate an SHA-3 message-digest of the file specified by
`pathname'. The bit length of the message digest produced is
controlled by `output-bit-length', which can take on the values 224,
256, 288, 384 and 512, which is the default value.
Note that in order to generate a message digest of a string it will
have to be converted to a simple-array with element-type
(unsigned-byte 8) in the proper output-encoding. This will have to
rely on implementation-specific functions and is not part of the SHA3
library.
The file keccak-reference.lisp contains a slow simple reference
implementation, and testdriver code, which allows testing of the tuned
implementations against this reference and against test data available
from the Keccak Site at: http://keccak.noekeon.org/KeccakKAT-3.zip
The testcases from the Keccak test data can be run with the following
form:
(keccak:test-keccak-msgkat
"/Path/To/MsgKatDirectory"
(lambda (total-bits bit-rate output-bits message)
(declare (ignore total-bits bit-rate))
(sha3:sha3-digest-vector message :output-bit-length output-bits)))
This SHA-3 implementation is licensed under the MIT-style license
contained in the file COPYING and the header of each source file.
Many thanks go to the Keccak Team (Guido Bertoni, Joan Daemen, Michaël
Peeters and Gilles Van Assche, cf. http://keccak.noekeon.org) for
their algorithm and excellent documentation and reference
implementations.
Please direct any feedback to pmai@pmsf.de. A git repository of this
library is available under git://github.com/pmai/sha3.git

168
README.md Executable file
View File

@ -0,0 +1,168 @@
[![Build Status](https://travis-ci.org/pmai/sha3.svg?branch=master)](https://travis-ci.org/pmai/sha3)
This library is an implementation of the Secure Hash Algorithm 3
([SHA-3][]), also known as [Keccak][]. The implementation is
constrained to messages with an integral number of octets, i.e.
sub-byte length messages are not supported.
**NOTE** that prior to release 1.0.2 this package had a bug in the
generation of message digests where multiple calls to sha3-update
with partial buffers could lead to input data being ignored and
therefore erroneous message digests being generated. Uses with
only one call to sha3-update and the high-level routines were not
affected by this bug.
**NOTE** that prior to release 1.1.0 this package computed digests
based on the Keccak submission to the SHA-3 contest and did not
yet take into account the added suffix that the FIPS 202 SHA-3
final standard adds to messages prior to calculating the digest,
since this was not part of the Keccak submission. Starting with
1.1.0 the functions in the sha3 package do by default calculate
disgests that match the FIPS 202 standard, and will calculate
the old pre-standard digests only if the new optional keyword
argument `:raw-keccak-p` is passed with a true value.
The code should be portable across nearly all ANSI compliant CL
implementations with specialized versions tuned for implementations
that offer unboxed 64bit arithmetic, unboxed 32bit arithmetic and for
implementations with efficient fixnum arithmetic (requiring fixnums
that can represent (unsigned-byte 16)). Especially the 64 and 32bit
implementations have been mostly optimized for SBCL and CMU CL. For
those implementations, digests with a 1024 bit-rate (and 288 bit
digest output) can be generated in between 30 (64bit SBCL) to around
100 (32bit CMU CL) cycles/byte on an i7-640M; whereas optimized
C/assembler implementations reach around 12 to 50 cycles/byte on 64/32
bit Intel hardware. The reason for the discrepancy probably lies in
missing peephole and dependency optimizations in the SBCL/CMU CL
compiler backend.
The mid-level interfaces to the digest routines are the functions
- `sha3:sha3-init &key output-bit-length bit-rate`
Create and return a new SHA-3 state. If `output-bit-length` is
specified then the state will run at the bit rate specified for the
given output bit length. If `output-bit-length` is unspecified,
`bit-rate` can be specified to select a suitable bit rate. If both
are left unspecified then a default bit rate of 1024 bits is
selected, which is suitable for arbitrary output bit lengths of up
to 288 bits.
- `sha3:sha3-copy state`
Return an independent copy of the SHA-3 state `state`.
- `sha3:sha3-state-p state`
Test whether a given object is a SHA-3 state, i.e. is an instance of
the class `sha3:sha3-state`.
- `sha3:sha3-update state vector &key (start 0) (end (length vector))`
Update the given SHA-3 state `state` from `vector`, which must be a
simple-array with element-type (unsigned-byte 8), bounded by `start`
and `end`, which must be numeric bounding-indices.
- `sha3:sha3-final state &key output-bit-length raw-keccak-p`
If the given SHA-3 state `state` has not already been finalized,
finalize it by processing any remaining input in its buffer, with
the specified suffix of 01 and suitable padding as specified by the
SHA-3 standard (the specified SHA-3 suffix can be elided with the
optional keyword argument `raw-keccak-p` to generate digests as the
initial Keccak submission would have generated). Returns the
message digest as a `simple-array` of `(unsigned-byte 8)`. The
length of the returned digest is determined either by the output bit
length or bit rate specified on state creation, or for the special
case of default parameters being used, by the optional keyword
argument `output-bit-length`. If the state has previously been
finalized, the function will return the digest again.
For convenience the following high-level functions produce digests in
one step from 1d simple-arrays and streams with element-type
`(unsigned-byte 8)`, as well as files:
- `sha3:sha3-digest-vector vector &key (start 0) end (output-bit-length 512) raw-keccak-p`
Calculate an SHA-3 message-digest of data in `vector`, which should
be a 1d simple-array with element type `(unsigned-byte 8)`, bounded
by `start` and `end`. The bit length of the message digest produced
is controlled by `output-bit-length`, which can take on the values
224, 256, 288, 384 and 512, which is the default value. Using the
optional `raw-keccak-p` keyword argument the SHA-3 mandated 01 suffix
that is appended to the actual message prior to padding can be elided
to yield message digests that match the original Keccak submission
instead of the actual SHA-3 standard. Use this option only for
compatibility with historical implementations.
- `sha3:sha3-digest-stream stream &key (output-bit-length 512) raw-keccak-p`
Calculate an SHA-3 message-digest of data read from `stream`, which
should be a `stream` with element type `(unsigned-byte 8)`. The bit
length of the message digest produced is controlled by
`output-bit-length`, which can take on the values 224, 256, 288, 384
and 512, which is the default value. Using the optional `raw-keccak-p`
keyword argument the SHA-3 mandated 01 suffix that is appended to the
actual message prior to padding can be elided to yield message digests
that match the original Keccak submission instead of the actual SHA-3
standard. Use this option only for compatibility with historical
implementations.
- `sha3:sha3-digest-file pathname &key (output-bit-length 512) raw-keccak-p`
Calculate an SHA-3 message-digest of the file specified by
`pathname`. The bit length of the message digest produced is
controlled by `output-bit-length`, which can take on the values 224,
256, 288, 384 and 512, which is the default value. Using the optional
`raw-keccak-p` keyword argument the SHA-3 mandated 01 suffix that is
appended to the actual message prior to padding can be elided to yield
message digests that match the original Keccak submission instead of
the actual SHA-3 standard. Use this option only for compatibility
with historical implementations.
Note that in order to generate a message digest of a string it will
have to be converted to a `simple-array` with element-type
`(unsigned-byte 8)` in the proper output-encoding. This will have to
rely on implementation-specific functions and is not part of the SHA3
library.
The file `keccak-reference.lisp` contains a slow simple reference
implementation, and testdriver code, which allows testing of the tuned
implementations against this reference and against test data available
from the Keccak Site at: http://keccak.noekeon.org/KeccakKAT-3.zip
The testcases from the Keccak test data can be run with the following
form:
```lisp
(keccak:test-keccak-msgkat
"/Path/To/MsgKatDirectory"
(lambda (total-bits bit-rate output-bits message)
(declare (ignore total-bits bit-rate))
(sha3:sha3-digest-vector message :output-bit-length output-bits :raw-keccak-p t)))
```
The adapted SHA-3 testcases from the Keccak Code Package test vectors
available under https://github.com/gvanas/KeccakCodePackage/tree/master/TestVectors
can be run with the following form:
```lisp
(keccak:test-sha3-msgkat
"/Path/To/MsgKatDirectory"
(lambda (total-bits bit-rate output-bits message)
(declare (ignore total-bits bit-rate))
(sha3:sha3-digest-vector message :output-bit-length output-bits)))
```
This SHA-3 implementation is licensed under the MIT-style license
contained in the file COPYING and the header of each source file.
Many thanks go to the Keccak Team (Guido Bertoni, Joan Daemen, Michaël
Peeters and Gilles Van Assche, cf. http://keccak.team) for
their algorithm and excellent documentation and reference
implementations.
Please direct any feedback to pmai@pmsf.de. A git repository of this
library is available under git://github.com/pmai/sha3.git
[SHA-3]: https://en.wikipedia.org/wiki/SHA-3
[Keccak]: https://keccak.team/

28
common.lisp Normal file → Executable file
View File

@ -1,6 +1,6 @@
;;;; SHA3 --- Secure Hash Algorithm 3 (Keccak) Implementation ;;;; SHA3 --- Secure Hash Algorithm 3 (Keccak) Implementation
;;;; ;;;;
;;;; Copyright (C) 2012 PMSF IT Consulting Pierre R. Mai. ;;;; Copyright (C) 2012 -- 2018 PMSF IT Consulting Pierre R. Mai.
;;;; ;;;;
;;;; Permission is hereby granted, free of charge, to any person obtaining ;;;; Permission is hereby granted, free of charge, to any person obtaining
;;;; a copy of this software and associated documentation files (the ;;;; a copy of this software and associated documentation files (the
@ -181,16 +181,22 @@ Only supports atoms and function forms, no special forms."
;;; Message Padding for last block ;;; Message Padding for last block
;;; ;;;
(defun pad-message-to-width (message bit-width) (defun pad-message-to-width (message bit-width add-fips-202-suffix-p)
"Destructively pad the given message to the given bit-width according to "Destructively pad the given message to the given bit-width according to
Keccak padding rules and return the padded message." the Keccak 10*1 padding rules, optionally appending the FIPS 202/SHA-3
(let ((message-byte-length (length message)) mandated 01 suffix first, and return the padded message."
(width-bytes (truncate bit-width 8))) (let* ((message-byte-length (length message))
(setq message (adjust-array message (list width-bytes))) (width-bytes (truncate bit-width 8))
(setf (aref message message-byte-length) #x01) (padded (make-array width-bytes
:element-type '(unsigned-byte 8))))
(replace padded message)
;; FIPS 202 SHA-3 mandates the appending of a 01 suffix prior to the
;; final Keccak padding so that the first byte following the message
;; will be #b00000101 instead of #b00000001 for raw Keccak.
(setf (aref padded message-byte-length) (if add-fips-202-suffix-p #x06 #x01))
(loop for index from (1+ message-byte-length) below width-bytes (loop for index from (1+ message-byte-length) below width-bytes
do (setf (aref message index) #x00) do (setf (aref padded index) #x00)
finally finally
(setf (aref message (1- width-bytes)) (setf (aref padded (1- width-bytes))
(logior #x80 (aref message (1- width-bytes)))))) (logior #x80 (aref padded (1- width-bytes)))))
message) padded))

2
keccak-16bit.lisp Normal file → Executable file
View File

@ -1,6 +1,6 @@
;;;; SHA3 --- Secure Hash Algorithm 3 (Keccak) Implementation ;;;; SHA3 --- Secure Hash Algorithm 3 (Keccak) Implementation
;;;; ;;;;
;;;; Copyright (C) 2012 PMSF IT Consulting Pierre R. Mai. ;;;; Copyright (C) 2012 -- 2018 PMSF IT Consulting Pierre R. Mai.
;;;; ;;;;
;;;; Permission is hereby granted, free of charge, to any person obtaining ;;;; Permission is hereby granted, free of charge, to any person obtaining
;;;; a copy of this software and associated documentation files (the ;;;; a copy of this software and associated documentation files (the

2
keccak-32bit.lisp Normal file → Executable file
View File

@ -1,6 +1,6 @@
;;;; SHA3 --- Secure Hash Algorithm 3 (Keccak) Implementation ;;;; SHA3 --- Secure Hash Algorithm 3 (Keccak) Implementation
;;;; ;;;;
;;;; Copyright (C) 2012 PMSF IT Consulting Pierre R. Mai. ;;;; Copyright (C) 2012 -- 2018 PMSF IT Consulting Pierre R. Mai.
;;;; ;;;;
;;;; Permission is hereby granted, free of charge, to any person obtaining ;;;; Permission is hereby granted, free of charge, to any person obtaining
;;;; a copy of this software and associated documentation files (the ;;;; a copy of this software and associated documentation files (the

2
keccak-64bit.lisp Normal file → Executable file
View File

@ -1,6 +1,6 @@
;;;; SHA3 --- Secure Hash Algorithm 3 (Keccak) Implementation ;;;; SHA3 --- Secure Hash Algorithm 3 (Keccak) Implementation
;;;; ;;;;
;;;; Copyright (C) 2012 PMSF IT Consulting Pierre R. Mai. ;;;; Copyright (C) 2012 -- 2018 PMSF IT Consulting Pierre R. Mai.
;;;; ;;;;
;;;; Permission is hereby granted, free of charge, to any person obtaining ;;;; Permission is hereby granted, free of charge, to any person obtaining
;;;; a copy of this software and associated documentation files (the ;;;; a copy of this software and associated documentation files (the

24
keccak-reference.lisp Normal file → Executable file
View File

@ -1,6 +1,6 @@
;;;; SHA3 --- Secure Hash Algorithm 3 (Keccak) Implementation ;;;; SHA3 --- Secure Hash Algorithm 3 (Keccak) Implementation
;;;; ;;;;
;;;; Copyright (C) 2012 PMSF IT Consulting Pierre R. Mai. ;;;; Copyright (C) 2012 -- 2018 PMSF IT Consulting Pierre R. Mai.
;;;; ;;;;
;;;; Permission is hereby granted, free of charge, to any person obtaining ;;;; Permission is hereby granted, free of charge, to any person obtaining
;;;; a copy of this software and associated documentation files (the ;;;; a copy of this software and associated documentation files (the
@ -36,7 +36,8 @@
#:test-with-testsuite #:test-with-testsuite
#:read-testsuite-from-file #:read-testsuite-from-file
#:test-with-testsuite-from-file #:test-with-testsuite-from-file
#:test-keccak-msgkat)) #:test-keccak-msgkat
#:test-sha3-msgkat))
(cl:in-package #:keccak-reference) (cl:in-package #:keccak-reference)
@ -380,3 +381,22 @@
(setq result nil)) (setq result nil))
finally finally
(return result))) (return result)))
(defun test-sha3-msgkat (directory &optional function)
(loop with result = t
for (filename total-bits bit-rate output-bits) in
'(("ShortMsgKAT_SHA3-224.txt" 1600 1152 224)
("ShortMsgKAT_SHA3-256.txt" 1600 1088 256)
("ShortMsgKAT_SHA3-384.txt" 1600 832 384)
("ShortMsgKAT_SHA3-512.txt" 1600 576 512))
do
(unless
(test-with-testsuite-from-file
(merge-pathnames filename directory)
(if (null function)
(lambda (message) (keccak total-bits bit-rate output-bits message))
(lambda (message)
(funcall function total-bits bit-rate output-bits message))))
(setq result nil))
finally
(return result)))

2
pkgdef.lisp Normal file → Executable file
View File

@ -1,6 +1,6 @@
;;;; SHA3 --- Secure Hash Algorithm 3 (Keccak) Implementation ;;;; SHA3 --- Secure Hash Algorithm 3 (Keccak) Implementation
;;;; ;;;;
;;;; Copyright (C) 2012 PMSF IT Consulting Pierre R. Mai. ;;;; Copyright (C) 2012 -- 2018 PMSF IT Consulting Pierre R. Mai.
;;;; ;;;;
;;;; Permission is hereby granted, free of charge, to any person obtaining ;;;; Permission is hereby granted, free of charge, to any person obtaining
;;;; a copy of this software and associated documentation files (the ;;;; a copy of this software and associated documentation files (the

16
sha3.asd Normal file → Executable file
View File

@ -1,6 +1,6 @@
;;;; SHA3 --- Secure Hash Algorithm 3 (Keccak) Implementation ;;;; SHA3 --- Secure Hash Algorithm 3 (Keccak) Implementation
;;;; ;;;;
;;;; Copyright (C) 2012 PMSF IT Consulting Pierre R. Mai. ;;;; Copyright (C) 2012 -- 2018 PMSF IT Consulting Pierre R. Mai.
;;;; ;;;;
;;;; Permission is hereby granted, free of charge, to any person obtaining ;;;; Permission is hereby granted, free of charge, to any person obtaining
;;;; a copy of this software and associated documentation files (the ;;;; a copy of this software and associated documentation files (the
@ -26,7 +26,7 @@
;;;; other dealings in this Software without prior written authorization ;;;; other dealings in this Software without prior written authorization
;;;; from the author. ;;;; from the author.
;;;; ;;;;
;;;; $Id: 2cbc5857639b13160ef580514a78749c02b70c0b $ ;;;; $Id$
(cl:in-package #:cl-user) (cl:in-package #:cl-user)
@ -42,7 +42,7 @@
:author "Pierre R. Mai <pmai@pmsf.de>" :author "Pierre R. Mai <pmai@pmsf.de>"
:maintainer "Pierre R. Mai <pmai@pmsf.de>" :maintainer "Pierre R. Mai <pmai@pmsf.de>"
:licence "MIT/X11" :licence "MIT/X11"
:version "1.0.0" :version "1.1.2"
#+sbcl :depends-on #+sbcl ("sb-rotate-byte") #+sbcl :depends-on #+sbcl ("sb-rotate-byte")
:components ((:file "pkgdef") :components ((:file "pkgdef")
(:file "common" :depends-on ("pkgdef")) (:file "common" :depends-on ("pkgdef"))
@ -51,10 +51,10 @@
#+(or (and :sbcl (not (or :x86-64 :alpha))) #+(or (and :sbcl (not (or :x86-64 :alpha)))
:cmucl :cmucl
(and :ccl :64-bit-target) (and :ccl :64-bit-target)
(and :lispworks :lispworks-64bit)) (and :lispworks :lispworks-64bit (not :lispworks8)))
(:file "keccak-32bit" :depends-on ("pkgdef" "common")) (:file "keccak-32bit" :depends-on ("pkgdef" "common"))
#-(or :sbcl :cmucl (and :ccl :64-bit-target) #-(or :sbcl :cmucl (and :ccl :64-bit-target)
(and :lispworks :lispworks-64bit)) (and :lispworks :lispworks-64bit (not :lispworks8)))
(:file "keccak-16bit" :depends-on ("pkgdef" "common")) (:file "keccak-16bit" :depends-on ("pkgdef" "common"))
(:file "sha3" (:file "sha3"
:depends-on ("pkgdef" :depends-on ("pkgdef"
@ -64,8 +64,10 @@
#+(or (and :sbcl (not (or :x86-64 :alpha))) #+(or (and :sbcl (not (or :x86-64 :alpha)))
:cmucl :cmucl
(and :ccl :64-bit-target) (and :ccl :64-bit-target)
(and :lispworks :lispworks-64bit)) (and :lispworks :lispworks-64bit
(not :lispworks8)))
"keccak-32bit" "keccak-32bit"
#-(or :sbcl :cmucl (and :ccl :64-bit-target) #-(or :sbcl :cmucl (and :ccl :64-bit-target)
(and :lispworks :lispworks-64bit)) (and :lispworks :lispworks-64bit
(not :lispworks8)))
"keccak-16bit")))) "keccak-16bit"))))

63
sha3.lisp Normal file → Executable file
View File

@ -1,6 +1,6 @@
;;;; SHA3 --- Secure Hash Algorithm 3 (Keccak) Implementation ;;;; SHA3 --- Secure Hash Algorithm 3 (Keccak) Implementation
;;;; ;;;;
;;;; Copyright (C) 2012 PMSF IT Consulting Pierre R. Mai. ;;;; Copyright (C) 2012 -- 2018 PMSF IT Consulting Pierre R. Mai.
;;;; ;;;;
;;;; Permission is hereby granted, free of charge, to any person obtaining ;;;; Permission is hereby granted, free of charge, to any person obtaining
;;;; a copy of this software and associated documentation files (the ;;;; a copy of this software and associated documentation files (the
@ -110,16 +110,21 @@ and `end', which must be numeric bounding-indices."
#.*optimize-declaration*) #.*optimize-declaration*)
;; Handle potential remaining bytes ;; Handle potential remaining bytes
(unless (zerop buffer-index) (unless (zerop buffer-index)
(let ((remainder (- (length buffer) buffer-index))) (let ((remainder (- rate-bytes buffer-index))
(declare (type fixnum remainder)) (length (- end start)))
(declare (type fixnum remainder length))
(replace buffer vector :start1 buffer-index :start2 start :end2 end) (replace buffer vector :start1 buffer-index :start2 start :end2 end)
(when (>= (- end start) remainder) ;; Return if still unfilled buffer
(when (< length remainder)
(incf (sha3-state-buffer-index state) length)
(return-from sha3-update))
;; Else handle now complete buffer
(keccak-state-merge-input keccak-state bit-rate buffer 0) (keccak-state-merge-input keccak-state bit-rate buffer 0)
(keccak-f keccak-state)) (keccak-f keccak-state)
(setf (sha3-state-buffer-index state) 0 (setf (sha3-state-buffer-index state) 0
start (min (+ start remainder) end)))) start (+ start remainder))))
;; Now handle full blocks, stuff any remainder into buffer ;; Now handle full blocks, stuff any remainder into buffer
(loop for block-offset of-type fixnum from start to end by rate-bytes (loop for block-offset of-type fixnum from start below end by rate-bytes
do do
(cond (cond
((<= (+ block-offset rate-bytes) end) ((<= (+ block-offset rate-bytes) end)
@ -129,10 +134,13 @@ and `end', which must be numeric bounding-indices."
(replace buffer vector :start1 0 :start2 block-offset) (replace buffer vector :start1 0 :start2 block-offset)
(setf (sha3-state-buffer-index state) (- end block-offset))))))) (setf (sha3-state-buffer-index state) (- end block-offset)))))))
(defun sha3-final (state &key (output-bit-length nil output-bit-length-p)) (defun sha3-final (state &key (output-bit-length nil output-bit-length-p) raw-keccak-p)
"If the given SHA-3 state `state' has not already been finalized, "If the given SHA-3 state `state' has not already been finalized,
finalize it by processing any remaining input in its buffer, with finalize it by processing any remaining input in its buffer, with
suitable padding as specified by the SHA-3 standard. Returns the the specified suffix of 01 and suitable padding as specified by the
SHA-3 standard (the specified SHA-3 suffix can be elided with the
optional keyword argument `raw-keccak-p' to generate digests as the
initial Keccak submission would have generated). Returns the
message digest as a simple-array of (unsigned-byte 8). The length message digest as a simple-array of (unsigned-byte 8). The length
of the returned digest is determined either by the output bit length of the returned digest is determined either by the output bit length
or bit rate specified on state creation, or for the special case of or bit rate specified on state creation, or for the special case of
@ -172,7 +180,8 @@ the function will return the digest again."
(keccak-state-merge-input keccak-state bit-rate (keccak-state-merge-input keccak-state bit-rate
(pad-message-to-width (pad-message-to-width
(subseq buffer 0 buffer-index) (subseq buffer 0 buffer-index)
bit-rate) bit-rate
(not raw-keccak-p))
0) 0)
(keccak-f keccak-state) (keccak-f keccak-state)
(setf (sha3-state-buffer-index state) 0 (setf (sha3-state-buffer-index state) 0
@ -184,12 +193,18 @@ the function will return the digest again."
;;; ;;;
(defun sha3-digest-vector (vector &key (start 0) end (defun sha3-digest-vector (vector &key (start 0) end
(output-bit-length 512)) (output-bit-length 512)
raw-keccak-p)
"Calculate an SHA-3 message-digest of data in `vector', which should "Calculate an SHA-3 message-digest of data in `vector', which should
be a 1d simple-array with element type (unsigned-byte 8), bounded by be a 1d simple-array with element type (unsigned-byte 8), bounded by
`start' and `end'. The bit length of the message digest produced is `start' and `end'. The bit length of the message digest produced is
controlled by `output-bit-length', which can take on the values 224, controlled by `output-bit-length', which can take on the values 224,
256, 288, 384 and 512, which is the default value." 256, 288, 384 and 512, which is the default value. Using the optional
`raw-keccak-p' keyword argument the SHA-3 mandated 01 suffix that is
appended to the actual message prior to padding can be elided to yield
message digests that match the original Keccak submission instead of
the actual SHA-3 standard. Use this option only for compatibility
with historical implementations."
(declare (optimize (speed 3) (safety 3) (space 0) (debug 1)) (declare (optimize (speed 3) (safety 3) (space 0) (debug 1))
(type (simple-array (unsigned-byte 8) (*)) vector) (type (simple-array (unsigned-byte 8) (*)) vector)
(type fixnum start) (type fixnum start)
@ -202,7 +217,7 @@ controlled by `output-bit-length', which can take on the values 224,
(let ((real-end (or end (length vector)))) (let ((real-end (or end (length vector))))
(declare (type fixnum real-end)) (declare (type fixnum real-end))
(sha3-update state vector :start start :end real-end)) (sha3-update state vector :start start :end real-end))
(sha3-final state)))) (sha3-final state :raw-keccak-p raw-keccak-p))))
(eval-when (:compile-toplevel :load-toplevel :execute) (eval-when (:compile-toplevel :load-toplevel :execute)
(defconstant +buffer-size+ (* 128 1024) (defconstant +buffer-size+ (* 128 1024)
@ -211,12 +226,17 @@ controlled by `output-bit-length', which can take on the values 224,
(deftype buffer-index () `(integer 0 ,+buffer-size+)) (deftype buffer-index () `(integer 0 ,+buffer-size+))
(defun sha3-digest-stream (stream &key (output-bit-length 512)) (defun sha3-digest-stream (stream &key (output-bit-length 512) raw-keccak-p)
"Calculate an SHA-3 message-digest of data read from `stream', which "Calculate an SHA-3 message-digest of data read from `stream', which
should be a stream with element type (unsigned-byte 8). The bit should be a stream with element type (unsigned-byte 8). The bit
length of the message digest produced is controlled by length of the message digest produced is controlled by
`output-bit-length', which can take on the values 224, 256, 288, 384 `output-bit-length', which can take on the values 224, 256, 288, 384
and 512, which is the default value." and 512, which is the default value. Using the optional `raw-keccak-p'
keyword argument the SHA-3 mandated 01 suffix that is appended to the
actual message prior to padding can be elided to yield message digests
that match the original Keccak submission instead of the actual SHA-3
standard. Use this option only for compatibility with historical
implementations."
(declare (optimize (speed 3) (safety 3) (space 0) (debug 1)) (declare (optimize (speed 3) (safety 3) (space 0) (debug 1))
(type stream stream) (type stream stream)
(type (integer 0 1600) output-bit-length)) (type (integer 0 1600) output-bit-length))
@ -233,16 +253,21 @@ and 512, which is the default value."
do (sha3-update state buffer :end bytes) do (sha3-update state buffer :end bytes)
until (< bytes +buffer-size+) until (< bytes +buffer-size+)
finally finally
(return (sha3-final state)))))) (return (sha3-final state :raw-keccak-p raw-keccak-p))))))
(defun sha3-digest-file (pathname &key (output-bit-length 512)) (defun sha3-digest-file (pathname &key (output-bit-length 512) raw-keccak-p)
"Calculate an SHA-3 message-digest of the file specified by "Calculate an SHA-3 message-digest of the file specified by
`pathname'. The bit length of the message digest produced is `pathname'. The bit length of the message digest produced is
controlled by `output-bit-length', which can take on the values 224, controlled by `output-bit-length', which can take on the values 224,
256, 288, 384 and 512, which is the default value." 256, 288, 384 and 512, which is the default value. Using the optional
`raw-keccak-p' keyword argument the SHA-3 mandated 01 suffix that is
appended to the actual message prior to padding can be elided to yield
message digests that match the original Keccak submission instead of
the actual SHA-3 standard. Use this option only for compatibility
with historical implementations."
(declare (optimize (speed 3) (safety 3) (space 0) (debug 1)) (declare (optimize (speed 3) (safety 3) (space 0) (debug 1))
(type (integer 0 1600) output-bit-length)) (type (integer 0 1600) output-bit-length))
(locally (locally
(declare (optimize (safety 1) (debug 0))) (declare (optimize (safety 1) (debug 0)))
(with-open-file (stream pathname :element-type '(unsigned-byte 8)) (with-open-file (stream pathname :element-type '(unsigned-byte 8))
(sha3-digest-stream stream :output-bit-length output-bit-length)))) (sha3-digest-stream stream :output-bit-length output-bit-length :raw-keccak-p raw-keccak-p))))