Refactor hashing out into separate library

This commit is contained in:
Yingtong Li 2017-09-28 20:02:20 +10:00
parent 3427b376b5
commit a242f1f666
Signed by: RunasSudo
GPG Key ID: 7234E476BF21C61A
8 changed files with 99 additions and 27 deletions

View File

@ -0,0 +1,82 @@
# Eos - Verifiable elections
# Copyright © 2017 RunasSudo (Yingtong Li)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
try:
__pragma__ = __pragma__
is_python = False
except:
is_python = True
def __pragma__(*args):
pass
from eos.core.bigint import *
# Libraries
# =========
if is_python:
__pragma__('skip')
import base64
import hashlib
__pragma__('noskip')
else:
# Load jssha-sha256.js
lib = __pragma__('js', '''
(function() {{
{}
var exports = {{}};
exports.jsSHA = window.jsSHA;
return exports;
}})()''', __include__('eos/core/hashing/jssha-sha256.js'))
# Implementation
# ==============
class SHA256:
def __init__(self):
if is_python:
self.impl = hashlib.sha256()
else:
# TNYI: This is completely borked
self.impl = __pragma__('js', '{}', 'new lib.jsSHA("SHA-256", "TEXT")')
def update_text(self, *values):
for value in values:
if is_python:
self.impl.update(value.encode('utf-8'))
else:
self.impl.js_update(value)
return self
def update_bigint(self, *values):
for value in values:
self.update_text(str(value))
return self
def hash_as_b64(self):
if is_python:
return base64.b64encode(self.impl.digest()).decode('utf-8')
else:
return self.impl.getHash('B64')
def hash_as_hex(self):
if is_python:
return self.impl.hexdigest()
else:
return self.impl.getHash('HEX')
def hash_as_bigint(self):
return BigInt(self.hash_as_hex(), 16)

View File

@ -36,16 +36,14 @@ if is_python:
import uuid import uuid
__pragma__('noskip') __pragma__('noskip')
else: else:
# Load json.js, jssha-sha256.js # Load json.js
lib = __pragma__('js', ''' lib = __pragma__('js', '''
(function() {{ (function() {{
{}
{} {}
var exports = {{}}; var exports = {{}};
exports.stringify = stringify_main; exports.stringify = stringify_main;
exports.jsSHA = window.jsSHA;
return exports; return exports;
}})()''', __include__('eos/core/objects/json.js'), __include__('eos/core/objects/jssha-sha256.js')) }})()''', __include__('eos/core/objects/json.js'))
# Database # Database
# ======== # ========
@ -155,7 +153,7 @@ class EosObject(metaclass=EosObjectType):
@property @property
def hash(self): def hash(self):
return EosObject.to_sha256(EosObject.to_json(EosObject.serialise_and_wrap(self)))[0] return SHA256().update_text(EosObject.to_json(EosObject.serialise_and_wrap(self))).hash_as_b64()
@staticmethod @staticmethod
def serialise_and_wrap(value, object_type=None): def serialise_and_wrap(value, object_type=None):
@ -184,22 +182,6 @@ class EosObject(metaclass=EosObjectType):
return json.loads(value) return json.loads(value)
else: else:
return JSON.parse(value) return JSON.parse(value)
@staticmethod
def to_sha256(*values):
from eos.core.bigint import BigInt
if is_python:
sha_obj = hashlib.sha256()
for value in values:
sha_obj.update(value.encode('utf-8'))
return base64.b64encode(sha_obj.digest()).decode('utf-8'), BigInt(sha_obj.hexdigest(), 16)
else:
# TNYI: This is completely borked
sha_obj = __pragma__('js', '{}', 'new lib.jsSHA("SHA-256", "TEXT")')
for value in values:
sha_obj.js_update(value)
return sha_obj.getHash('B64'), BigInt(sha_obj.getHash('HEX'), 16)
class EosList(EosObject): class EosList(EosObject):
def __init__(self, *args): def __init__(self, *args):

View File

@ -16,6 +16,7 @@
from eos.core.bigint import * from eos.core.bigint import *
from eos.core.objects import * from eos.core.objects import *
from eos.core.hashing import *
# Common library things # Common library things
# =================== # ===================
@ -95,7 +96,7 @@ class ObjectTestCase(EosTestCase):
class HashTestCase(EosTestCase): class HashTestCase(EosTestCase):
def test_hash(self): def test_hash(self):
self.assertEqual(EosObject.to_sha256('Hello World!')[0], 'f4OxZX/x/FO5LcGBSKHWXfwtSx+j1ncoSt3SABJtkGk=') self.assertEqual(SHA256().update_text('Hello World!').hash_as_b64(), 'f4OxZX/x/FO5LcGBSKHWXfwtSx+j1ncoSt3SABJtkGk=')
class BigIntTestCase(EosTestCase): class BigIntTestCase(EosTestCase):
def test_basic(self): def test_basic(self):

View File

@ -16,9 +16,13 @@
import eos.core.objects import eos.core.objects
import eos.core.bigint import eos.core.bigint
import eos.core.hashing
import eos.base.election import eos.base.election
import eos.base.workflow import eos.base.workflow
import eos.psr.bitstream import eos.psr.bitstream
import eos.psr.crypto import eos.psr.crypto
import eos.psr.election
import eos.psr.mixnet
import eos.psr.workflow

View File

@ -16,6 +16,7 @@
from eos.core.bigint import * from eos.core.bigint import *
from eos.core.objects import * from eos.core.objects import *
from eos.core.hashing import *
from eos.base.election import * from eos.base.election import *
class CyclicGroup(EmbeddedObject): class CyclicGroup(EmbeddedObject):
@ -120,7 +121,7 @@ class SEGPublicKey(EGPublicKey):
gamma = pow(self.group.g, r, self.group.p) # h gamma = pow(self.group.g, r, self.group.p) # h
delta = (message * pow(self.X, r, self.group.p)) % self.group.p # f delta = (message * pow(self.X, r, self.group.p)) % self.group.p # f
_, c = EosObject.to_sha256(str(pow(self.group.g, s, self.group.p)), str(gamma), str(delta)) c = SHA256().update_bigint(pow(self.group.g, s, self.group.p), gamma, delta).hash_as_bigint()
z = s + c*r z = s + c*r
@ -136,6 +137,6 @@ class SEGCiphertext(EGCiphertext):
def is_signature_valid(self): def is_signature_valid(self):
gs = (pow(self.public_key.group.g, self.z, self.public_key.group.p) * pow(self.gamma, self.public_key.group.p - ONE - self.c, self.public_key.group.p)) % self.public_key.group.p gs = (pow(self.public_key.group.g, self.z, self.public_key.group.p) * pow(self.gamma, self.public_key.group.p - ONE - self.c, self.public_key.group.p)) % self.public_key.group.p
_, c = EosObject.to_sha256(str(gs), str(self.gamma), str(self.delta)) c = SHA256().update_bigint(gs, self.gamma, self.delta).hash_as_bigint()
return self.c == c return self.c == c

View File

@ -16,6 +16,7 @@
from eos.core.bigint import * from eos.core.bigint import *
from eos.core.objects import * from eos.core.objects import *
from eos.core.hashing import *
from eos.psr.election import * from eos.psr.election import *
class RPCMixnet: class RPCMixnet:
@ -63,7 +64,7 @@ class RPCMixnet:
for i in range(len(permutations_and_reenc)): for i in range(len(permutations_and_reenc)):
val = permutations_and_reenc[i] val = permutations_and_reenc[i]
val_obj = MixChallengeResponse(index=val[0], reenc=val[1], rand=val[2]) val_obj = MixChallengeResponse(index=val[0], reenc=val[1], rand=val[2])
commitments.append(EosObject.to_sha256(EosObject.to_json(val_obj.serialise()))[1]) commitments.append(SHA256().update_text(EosObject.to_json(val_obj.serialise())).hash_as_bigint())
else: else:
for i in range(len(permutations_and_reenc)): for i in range(len(permutations_and_reenc)):
# Find the answer that went to 'i' # Find the answer that went to 'i'
@ -71,7 +72,7 @@ class RPCMixnet:
val = permutations_and_reenc[idx] val = permutations_and_reenc[idx]
val_obj = MixChallengeResponse(index=idx, reenc=val[1], rand=val[3]) val_obj = MixChallengeResponse(index=idx, reenc=val[1], rand=val[3])
commitments.append(EosObject.to_sha256(EosObject.to_json(val_obj.serialise()))[1]) commitments.append(SHA256().update_text(EosObject.to_json(val_obj.serialise())).hash_as_bigint())
self.params = permutations_and_reenc self.params = permutations_and_reenc
return shuffled_answers, commitments return shuffled_answers, commitments

View File

@ -17,6 +17,7 @@
from eos.core.tests import * from eos.core.tests import *
from eos.core.bigint import * from eos.core.bigint import *
from eos.core.hashing import *
from eos.psr.bitstream import * from eos.psr.bitstream import *
from eos.psr.crypto import * from eos.psr.crypto import *
from eos.psr.election import * from eos.psr.election import *
@ -158,7 +159,7 @@ class MixnetTestCase(EosTestCase):
for i in range(len(pts)): for i in range(len(pts)):
perm, reencs, rand = mixnet.challenge(i) perm, reencs, rand = mixnet.challenge(i)
val_obj = MixChallengeResponse(index=perm, reenc=reencs, rand=rand) val_obj = MixChallengeResponse(index=perm, reenc=reencs, rand=rand)
self.assertEqual(commitments[i], EosObject.to_sha256(EosObject.to_json(val_obj.serialise()))[1]) self.assertEqual(commitments[i], SHA256().update_text(EosObject.to_json(val_obj.serialise())).hash_as_bigint())
if mixnet.is_left: if mixnet.is_left:
verify_shuffle(i, perm, reencs) verify_shuffle(i, perm, reencs)