Last active
April 24, 2019 18:23
-
-
Save cathalmccabe/2c53db61f27cb2a09a01e3d5401318c4 to your computer and use it in GitHub Desktop.
SHA1 test
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"# Implementation of SHA-1 Core on SoC Ported to Python" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 1, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"# Internal constants definitions\n", | |
"ADDR_I_CS_DATA = 0x10\n", | |
"BITS_I_CS_DATA = 1\n", | |
"ADDR_I_WE_DATA = 0x18\n", | |
"BITS_I_WE_DATA = 1\n", | |
"ADDR_I_ADDRESS_DATA = 0x20\n", | |
"BITS_I_ADDRESS_DATA = 8\n", | |
"ADDR_I_WRITE_DATA = 0x28\n", | |
"BITS_I_WRITE_DATA = 32\n", | |
"ADDR_O_READ_DATA = 0x30\n", | |
"BITS_O_READ_DATA = 32\n", | |
"ADDR_O_READ_CTRL = 0x34\n", | |
"ADDR_O_ERROR_DATA = 0x38\n", | |
"BITS_O_ERROR_DATA = 1\n", | |
"ADDR_O_ERROR_CTRL = 0x3c" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 2, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"application/javascript": [ | |
"\n", | |
"require(['notebook/js/codecell'], function(codecell) {\n", | |
" codecell.CodeCell.options_default.highlight_modes[\n", | |
" 'magic_text/x-csrc'] = {'reg':[/^%%microblaze/]};\n", | |
" Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n", | |
" Jupyter.notebook.get_cells().map(function(cell){\n", | |
" if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n", | |
" });\n", | |
"});\n" | |
] | |
}, | |
"metadata": {}, | |
"output_type": "display_data" | |
} | |
], | |
"source": [ | |
"# Load the overlay containing the IP\n", | |
"from pynq import Overlay\n", | |
"\n", | |
"overlay = Overlay('/usr/local/lib/python3.6/dist-packages/sha1_pynq/bitstream/sha1_overlay.bit')" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 3, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"# See what attributes the overlay has\n", | |
"overlay?" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 4, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"# Access the the sha1 attribute to create a driver for the IP\n", | |
"sha1_ip = overlay.sha1_control_0\n", | |
"sha1_ip?" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 5, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"def check_core():\n", | |
" '''Print the name of the IP core and the version.\n", | |
" \n", | |
" Arguments:\n", | |
" None\n", | |
" \n", | |
" Return:\n", | |
" None\n", | |
" '''\n", | |
" \n", | |
" sha1_ip.write(ADDR_I_ADDRESS_DATA, 0)\n", | |
" sha1_ip.write(ADDR_I_CS_DATA, 1)\n", | |
" sha1_ip.write(ADDR_I_WE_DATA, 0)\n", | |
" name0 = sha1_ip.read(ADDR_O_READ_DATA)\n", | |
" print(bytearray.fromhex(hex(name0)[2:]).decode())\n", | |
" \n", | |
" sha1_ip.write(ADDR_I_ADDRESS_DATA, 1)\n", | |
" sha1_ip.write(ADDR_I_CS_DATA, 1)\n", | |
" sha1_ip.write(ADDR_I_WE_DATA, 0)\n", | |
" name1 = sha1_ip.read(ADDR_O_READ_DATA)\n", | |
" print(bytearray.fromhex(hex(name1)[2:]).decode())\n", | |
" \n", | |
" sha1_ip.write(ADDR_I_ADDRESS_DATA, 2)\n", | |
" sha1_ip.write(ADDR_I_CS_DATA, 1)\n", | |
" sha1_ip.write(ADDR_I_WE_DATA, 0)\n", | |
" version = sha1_ip.read(ADDR_O_READ_DATA)\n", | |
" print(bytearray.fromhex(hex(version)[2:]).decode())" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 6, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"def read_word(address):\n", | |
" '''Read a data word from the given address\n", | |
" \n", | |
" Arguments:\n", | |
" address - the address to read data from\n", | |
" \n", | |
" Return:\n", | |
" The data that was read from memory\n", | |
" '''\n", | |
" \n", | |
" sha1_ip.write(ADDR_I_ADDRESS_DATA, address)\n", | |
" sha1_ip.write(ADDR_I_CS_DATA, 1)\n", | |
" sha1_ip.write(ADDR_I_WE_DATA, 0)\n", | |
" word =0;\n", | |
" while(sha1_ip.read(ADDR_O_READ_DATA) != 0):\n", | |
" word = sha1_ip.read(ADDR_O_READ_DATA)\n", | |
" break\n", | |
" return word" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 7, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"def read_digest():\n", | |
" '''Read the digest of the message that was input\n", | |
" \n", | |
" Arguments:\n", | |
" None\n", | |
" \n", | |
" Return:\n", | |
" A byte array of length 20 containing the digest data\n", | |
" '''\n", | |
" \n", | |
" digest = bytearray()\n", | |
" for i in range(5):\n", | |
" data = read_word(0x20 + i)\n", | |
" digest.extend(data.to_bytes(4, byteorder='big'))\n", | |
" return digest" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 8, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"def write_word(address, word):\n", | |
" '''Write a data word to the given address\n", | |
" \n", | |
" Arguments:\n", | |
" address - the address to write to\n", | |
" word - the data to write\n", | |
" \n", | |
" Return:\n", | |
" None\n", | |
" '''\n", | |
" \n", | |
" sha1_ip.write(ADDR_I_ADDRESS_DATA, address)\n", | |
" sha1_ip.write(ADDR_I_WRITE_DATA, word)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 9, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"def pad_message(msg):\n", | |
" '''Pad the input message following the SHA1 documentation.\n", | |
" The purpose of the padding is to make the padded message have \n", | |
" a total length that is a multiple of 512, which can be processed\n", | |
" as sequential blocks of 512 bits.\n", | |
" \n", | |
" Arguments:\n", | |
" msg - input message as an ascii string\n", | |
" \n", | |
" Return:\n", | |
" A byte array containing the bytes of the padded message\n", | |
" '''\n", | |
" \n", | |
" blocks = bytearray(msg, 'ascii')\n", | |
" msgSize = len(msg)\n", | |
" blocks.append(0x80)\n", | |
" while len(blocks) % 64 != 56:\n", | |
" blocks.append(0x00)\n", | |
" reserved = (msgSize * 8).to_bytes(8, byteorder='big')\n", | |
" blocks.extend(reserved)\n", | |
" return bytes(blocks)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 10, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"def write_block(block, ctrl_val):\n", | |
" '''Write a block of the padded message.\n", | |
" \n", | |
" Arguments:\n", | |
" block - 512 bits of data to be written\n", | |
" ctrl_val - control value based on what block is being written\n", | |
" \n", | |
" Return:\n", | |
" None\n", | |
" '''\n", | |
" \n", | |
" sha1_ip.write(ADDR_I_CS_DATA, 1)\n", | |
" sha1_ip.write(ADDR_I_WE_DATA, 1)\n", | |
" j = 0\n", | |
" for i in range(16):\n", | |
" word = int.from_bytes(block[j:j+4], byteorder='big')\n", | |
" write_word(0x10 + i, word)\n", | |
" j += 4\n", | |
" write_word(0x8, ctrl_val)\n", | |
" sha1_ip.write(ADDR_I_WE_DATA, 0)\n", | |
" sha1_ip.write(ADDR_I_CS_DATA, 0)\n", | |
" sha1_ip.write(ADDR_I_CS_DATA, 1)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 11, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"def write_blocks(blocks):\n", | |
" '''Write each block of the padded message.\n", | |
" \n", | |
" Arguments:\n", | |
" blocks - A byte array containing the bytes of the padded message\n", | |
" \n", | |
" Return:\n", | |
" None\n", | |
" '''\n", | |
" \n", | |
" bytesWritten = 0\n", | |
" while bytesWritten < len(blocks):\n", | |
" if bytesWritten == 0:\n", | |
" write_block(blocks[bytesWritten:bytesWritten + 64], 0x1)\n", | |
" else:\n", | |
" write_block(blocks[bytesWritten:bytesWritten + 64], 0x2)\n", | |
" \n", | |
" status = read_word(0x09)\n", | |
" while status == 0:\n", | |
" status = read_word(0x09)\n", | |
" print(\"status:\", status)\n", | |
" \n", | |
" bytesWritten += 64" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 12, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"def hw_digest(msg):\n", | |
" '''Pad the inpute message, write the sequential blocks, and read the digest of the input.\n", | |
" \n", | |
" Arguements:\n", | |
" msg - input message as an ascii string\n", | |
" \n", | |
" Return:\n", | |
" A byte array of length 20 containing the digest data\n", | |
" '''\n", | |
" \n", | |
" msgPadded = pad_message(msg)\n", | |
" write_blocks(msgPadded)\n", | |
" digest = read_digest()\n", | |
" return digest" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 13, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"import hashlib\n", | |
"def sw_digest(msg):\n", | |
" '''Get the SHA1 digest of an ascii message using internal Python library.\n", | |
" \n", | |
" Arguments:\n", | |
" msg - input message as an ascii string\n", | |
" \n", | |
" Return:\n", | |
" A SHA1 hash object of the digest for the input message\n", | |
" '''\n", | |
" \n", | |
" digest = hashlib.sha1(msg.encode())\n", | |
" return digest" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 14, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"def test_sha1(msg):\n", | |
" '''Check if the message digests from hardware and software are the same.\n", | |
" \n", | |
" Arguments:\n", | |
" msg - input message as an ascii string\n", | |
" \n", | |
" Return:\n", | |
" None\n", | |
" '''\n", | |
" \n", | |
" swDigest = sw_digest(msg).hexdigest()\n", | |
" hwDigest = hw_digest(msg).hex()\n", | |
" print(\"hw digest: {}\".format(hwDigest))\n", | |
" print(\"sw digest: {}\".format(swDigest))\n", | |
" \n", | |
" if swDigest == hwDigest:\n", | |
" print(\"Test Passed!\")\n", | |
" else:\n", | |
" print(\"Test Failed!\")" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 15, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"----------------------------------------\n", | |
"Single Block Test\n", | |
"----------------------------------------\n", | |
"hw digest: a9993e364706816aba3e25717850c26c9cd0d89d\n", | |
"sw digest: a9993e364706816aba3e25717850c26c9cd0d89d\n", | |
"Test Passed!\n", | |
"\n", | |
"----------------------------------------\n", | |
"Double Block Test\n", | |
"----------------------------------------\n", | |
"hw digest: d4b3a5cfda922d7f02dbc77279682d73f00703d0\n", | |
"sw digest: 84983e441c3bd26ebaae4aa1f95129e5e54670f1\n", | |
"Test Failed!\n" | |
] | |
} | |
], | |
"source": [ | |
"# Test 1\n", | |
"print(\"----------------------------------------\")\n", | |
"print(\"Single Block Test\")\n", | |
"print(\"----------------------------------------\")\n", | |
"test_sha1(\"abc\")\n", | |
"print(\"\\n----------------------------------------\")\n", | |
"print(\"Double Block Test\")\n", | |
"print(\"----------------------------------------\")\n", | |
"test_sha1(\"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\")" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 16, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"hw digest: 7b502c3a1f48c8609ae212cdfb639dee39673f5e\n", | |
"sw digest: 7b502c3a1f48c8609ae212cdfb639dee39673f5e\n", | |
"Test Passed!\n" | |
] | |
} | |
], | |
"source": [ | |
"# Test 2\n", | |
"test_sha1(\"Hello world\")" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 17, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"hw digest: a3e0394d4643674d303170641382f6efefa15b7a\n", | |
"sw digest: a3e0394d4643674d303170641382f6efefa15b7a\n", | |
"Test Passed!\n" | |
] | |
} | |
], | |
"source": [ | |
"# Test 3\n", | |
"test_sha1(\"Reconfigurable GPU Computing Lab\")" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 21, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"Enter a message to hash with SHA1: f69f2445df4f9b17ad2b417be66c3710f69f2445df4f9b17ad2b417be66c3710f69f2445df4f9b17ad2b417be66c3710\n", | |
"hw digest: 594aed687bb569ee459c1e8d6ae04161cb6f7731\n", | |
"sw digest: 064743b8a9e3413abec46f784894429e283dd194\n", | |
"Test Failed!\n" | |
] | |
} | |
], | |
"source": [ | |
"# Custom message test\n", | |
"m = input(\"Enter a message to hash with SHA1: \")\n", | |
"test_sha1(m)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 22, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"The slowest run took 4.03 times longer than the fastest. This could mean that an intermediate result is being cached.\n", | |
"100000 loops, best of 3: 10.1 µs per loop\n" | |
] | |
} | |
], | |
"source": [ | |
"%%timeit\n", | |
"# Software Timing\n", | |
"sw_digest(\"Hello World!\")" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 23, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"100 loops, best of 3: 2.87 ms per loop\n" | |
] | |
} | |
], | |
"source": [ | |
"%%timeit\n", | |
"# Hardware Timing\n", | |
"hw_digest(\"Hello World!\")" | |
] | |
} | |
], | |
"metadata": { | |
"kernelspec": { | |
"display_name": "Python 3", | |
"language": "python", | |
"name": "python3" | |
}, | |
"language_info": { | |
"codemirror_mode": { | |
"name": "ipython", | |
"version": 3 | |
}, | |
"file_extension": ".py", | |
"mimetype": "text/x-python", | |
"name": "python", | |
"nbconvert_exporter": "python", | |
"pygments_lexer": "ipython3", | |
"version": "3.6.5" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 2 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment