Skip to content

Commit

Permalink
Initial implementation of sha3 module.
Browse files Browse the repository at this point in the history
  • Loading branch information
bjornedstrom committed Oct 3, 2012
1 parent 235b670 commit 771c8e5
Show file tree
Hide file tree
Showing 7 changed files with 334 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
@@ -0,0 +1,3 @@
*~
*.pyc
build/
5 changes: 5 additions & 0 deletions LICENSE
@@ -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.
23 changes: 23 additions & 0 deletions README.md
@@ -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.
14 changes: 14 additions & 0 deletions setup.py
@@ -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'])
235 changes: 235 additions & 0 deletions 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;
}
}
43 changes: 43 additions & 0 deletions sha3/__init__.py
@@ -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'
11 changes: 11 additions & 0 deletions test/test.py
@@ -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.