Permalink
Browse files

Initial implementation of sha3 module.

  • Loading branch information...
1 parent 235b670 commit 771c8e550f695a39eda46f7e2a74bc224bb26283 @bjornedstrom committed Oct 3, 2012
Showing with 334 additions and 0 deletions.
  1. +3 −0 .gitignore
  2. +5 −0 LICENSE
  3. +23 −0 README.md
  4. +14 −0 setup.py
  5. +235 −0 sha3.c
  6. +43 −0 sha3/__init__.py
  7. +11 −0 test/test.py
View
@@ -0,0 +1,3 @@
+*~
+*.pyc
+build/
View
@@ -0,0 +1,5 @@
+Keccak is written by the Keccak author. See the
+KeccakReferenceAndOptimized directory for more information.
+
+The python binding is written by Björn Edström <be@bjrn.se>. See
+sha3.c header for license details.
View
@@ -0,0 +1,23 @@
+= python-sha3
+
+A fast `hashlib` style Python implementation of SHA-3 (Keccak)
+implemented in C, on top of the Keccak reference implementation.
+
+Sample usage:
+
+ import sha3
+ s = sha3.SHA3512() # also 224, 256, 384, 512
+ s.update('foo')
+ print s.hexdigest()
+
+== Building
+
+ python setup.py build
+
+== Caveats
+
+While Keccak is tweakable, can hash on a bit level etc, this module is
+not. It works on byte arrays only. It also works with the select block
+sizes only.
+
+There are probably bugs. Possibly endianness-issues.
View
@@ -0,0 +1,14 @@
+from distutils.core import setup, Extension
+
+_sha3 = Extension('_sha3',
+ sources = ['sha3.c',
+ 'KeccakReferenceAndOptimized/Sources/KeccakNISTInterface.c',
+ 'KeccakReferenceAndOptimized/Sources/KeccakSponge.c',
+ 'KeccakReferenceAndOptimized/Sources/KeccakF-1600-reference.c',
+ 'KeccakReferenceAndOptimized/Sources/displayIntermediateValues.c'])
+
+setup(name='_sha3',
+ version='0.1',
+ description='SHA-3',
+ ext_modules=[_sha3],
+ packages=['sha3'])
View
235 sha3.c
@@ -0,0 +1,235 @@
+/* SHA3 module */
+
+/* This module provides an interface to NIST's SHA-3 algorithms */
+
+/* This module is based on sha256module.c, which has the following header:
+
+ Additional work performed by:
+
+ Andrew Kuchling (amk@amk.ca)
+ Greg Stein (gstein@lyra.org)
+ Trevor Perrin (trevp@trevp.net)
+
+ Copyright (C) 2005 Gregory P. Smith (greg@krypto.org)
+ Licensed to PSF under a Contributor Agreement.
+
+*/
+
+/*
+ The SHA3-module is written by Björn Edström <be@bjrn.se> 2012.
+
+ It is placed under the same license as the original module:
+ Licensed to PSF under a Contributor Agreement.
+ */
+
+#include "Python.h"
+#include "structmember.h"
+#include "KeccakReferenceAndOptimized/Sources/KeccakNISTInterface.h"
+
+typedef unsigned char SHA_BYTE;
+
+#if SIZEOF_INT == 4
+typedef unsigned int SHA_INT32; /* 32-bit integer */
+#else
+/* not defined. compilation will die. */
+#endif
+
+
+typedef struct {
+ PyObject_HEAD
+ int hashbitlen;
+ hashState state;
+} SHAobject;
+
+static void SHAcopy(SHAobject *src, SHAobject *dest)
+{
+ dest->hashbitlen = src->hashbitlen;
+ memcpy(&dest->state, &src->state, sizeof(src->state));
+}
+
+//
+
+static PyTypeObject SHA3type;
+
+
+static SHAobject *
+newSHA3object(void)
+{
+ return (SHAobject *)PyObject_New(SHAobject, &SHA3type);
+}
+
+static void
+SHA_dealloc(PyObject *ptr)
+{
+ PyObject_Del(ptr);
+}
+
+
+PyDoc_STRVAR(SHA3_copy__doc__, "Return a copy of the hash object.");
+
+static PyObject *
+SHA3_copy(SHAobject *self, PyObject *unused)
+{
+ SHAobject *newobj;
+
+ if (Py_TYPE(self) == &SHA3type) {
+ if ( (newobj = newSHA3object())==NULL)
+ return NULL;
+ }
+ SHAcopy(self, newobj);
+ return (PyObject *)newobj;
+}
+
+PyDoc_STRVAR(SHA3_digest__doc__,
+"Return the digest value as a string of binary data.");
+
+static PyObject *
+SHA3_digest(SHAobject *self, PyObject *unused)
+{
+ unsigned char digest[512];
+ SHAobject temp;
+
+ SHAcopy(self, &temp);
+
+ Final(&temp.state, digest);
+
+ return PyString_FromStringAndSize((const char *)digest, self->hashbitlen / 8);
+}
+
+PyDoc_STRVAR(SHA3_update__doc__,
+"Update this hash object's state with the provided string.");
+
+static PyObject *
+SHA3_update(SHAobject *self, PyObject *args)
+{
+ unsigned char *cp;
+ int len;
+
+ if (!PyArg_ParseTuple(args, "s#:update", &cp, &len))
+ return NULL;
+
+ Update(&self->state, cp, len * 8);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+PyDoc_STRVAR(SHA3_init__doc__,
+"Init this hash object's state.");
+
+static PyObject *
+SHA3_init(SHAobject *self, PyObject *args)
+{
+ int hashbitlen;
+
+ if (!PyArg_ParseTuple(args, "i", &hashbitlen))
+ return NULL;
+
+ self->hashbitlen = hashbitlen;
+ Init(&self->state, hashbitlen);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+
+static PyMethodDef SHA_methods[] = {
+ {"copy", (PyCFunction)SHA3_copy, METH_NOARGS, SHA3_copy__doc__},
+ {"digest", (PyCFunction)SHA3_digest, METH_NOARGS, SHA3_digest__doc__},
+ {"update", (PyCFunction)SHA3_update, METH_VARARGS, SHA3_update__doc__},
+ {"init" , (PyCFunction)SHA3_init, METH_VARARGS, SHA3_init__doc__},
+ {NULL, NULL} /* sentinel */
+};
+
+
+static PyGetSetDef SHA_getseters[] = {
+ {NULL} /* Sentinel */
+};
+
+static PyMemberDef SHA_members[] = {
+ {NULL} /* Sentinel */
+};
+
+
+static PyTypeObject SHA3type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "_sha3.sha3", /*tp_name*/
+ sizeof(SHAobject), /*tp_size*/
+ 0, /*tp_itemsize*/
+ /* methods */
+ SHA_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash*/
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ 0, /*tp_doc*/
+ 0, /*tp_traverse*/
+ 0, /*tp_clear*/
+ 0, /*tp_richcompare*/
+ 0, /*tp_weaklistoffset*/
+ 0, /*tp_iter*/
+ 0, /*tp_iternext*/
+ SHA_methods, /* tp_methods */
+ SHA_members, /* tp_members */
+ SHA_getseters, /* tp_getset */
+};
+
+
+PyDoc_STRVAR(SHA3_new__doc__,
+"Return a new SHA-3 hash object.");
+
+
+static PyObject *
+SHA3_new(PyObject *self, PyObject *args, PyObject *kwdict)
+{
+ SHAobject *new;
+
+ if ((new = newSHA3object()) == NULL)
+ return NULL;
+
+ if (PyErr_Occurred()) {
+ Py_DECREF(new);
+ return NULL;
+ }
+
+ return (PyObject *)new;
+}
+
+
+static struct PyMethodDef SHA_functions[] = {
+ {"sha3", (PyCFunction)SHA3_new, METH_VARARGS|METH_KEYWORDS, SHA3_new__doc__},
+ {NULL, NULL} /* Sentinel */
+};
+
+
+
+#define insint(n,v) { PyModule_AddIntConstant(m,n,v); }
+
+
+PyMODINIT_FUNC
+init_sha3(void)
+{
+ PyObject *m;
+
+ Py_TYPE(&SHA3type) = &PyType_Type;
+ if (PyType_Ready(&SHA3type) < 0) {
+ return;
+ }
+ m = Py_InitModule("_sha3", SHA_functions);
+ if (m == NULL) {
+ return;
+ }
+}
View
@@ -0,0 +1,43 @@
+import _sha3
+
+class _SHA3Base(object):
+ block_size = None
+
+ def __init__(self, s=None):
+ self._s = _sha3.sha3()
+ self._s.init(self.digest_size * 8)
+ if s is not None:
+ self._s.update(s)
+
+ def update(self, s):
+ return self._s.update(s)
+
+ def digest(self):
+ return self._s.digest()
+
+ def hexdigest(self):
+ return self.digest().encode('hex')
+
+ @property
+ def digestsize(self):
+ return self.digest_size
+
+
+class SHA3224(_SHA3Base):
+ digest_size = 28
+ name = 'sha3-224'
+
+
+class SHA3256(_SHA3Base):
+ digest_size = 32
+ name = 'sha3-256'
+
+
+class SHA3384(_SHA3Base):
+ digest_size = 48
+ name = 'sha3-384'
+
+
+class SHA3512(_SHA3Base):
+ digest_size = 64
+ name = 'sha3-512'
View
@@ -0,0 +1,11 @@
+import sha3
+
+def c(inst, s):
+ h = inst()
+ h.update(s)
+ return h.hexdigest().upper()
+
+# Test vectors from KeccakKAT/ShortMsgKAT_512.txt
+assert c(sha3.SHA3512, '') == "0EAB42DE4C3CEB9235FC91ACFFE746B29C29A8C366B7C60E4E67C466F36A4304C00FA9CAF9D87976BA469BCBE06713B435F091EF2769FB160CDAB33D3670680E"
+assert c(sha3.SHA3512, '\xCC') == "8630C13CBD066EA74BBE7FE468FEC1DEE10EDC1254FB4C1B7C5FD69B646E44160B8CE01D05A0908CA790DFB080F4B513BC3B6225ECE7A810371441A5AC666EB9"
+assert c(sha3.SHA3512, '\x41\xFB') == "551DA6236F8B96FCE9F97F1190E901324F0B45E06DBBB5CDB8355D6ED1DC34B3F0EAE7DCB68622FF232FA3CECE0D4616CDEB3931F93803662A28DF1CD535B731"

0 comments on commit 771c8e5

Please sign in to comment.