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
__pragma__('noskip')
else:
# Load json.js, jssha-sha256.js
# Load json.js
lib = __pragma__('js', '''
(function() {{
{}
{}
var exports = {{}};
exports.stringify = stringify_main;
exports.jsSHA = window.jsSHA;
return exports;
}})()''', __include__('eos/core/objects/json.js'), __include__('eos/core/objects/jssha-sha256.js'))
}})()''', __include__('eos/core/objects/json.js'))
# Database
# ========
@ -155,7 +153,7 @@ class EosObject(metaclass=EosObjectType):
@property
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
def serialise_and_wrap(value, object_type=None):
@ -184,22 +182,6 @@ class EosObject(metaclass=EosObjectType):
return json.loads(value)
else:
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):
def __init__(self, *args):

View File

@ -16,6 +16,7 @@
from eos.core.bigint import *
from eos.core.objects import *
from eos.core.hashing import *
# Common library things
# ===================
@ -95,7 +96,7 @@ class ObjectTestCase(EosTestCase):
class HashTestCase(EosTestCase):
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):
def test_basic(self):

View File

@ -16,9 +16,13 @@
import eos.core.objects
import eos.core.bigint
import eos.core.hashing
import eos.base.election
import eos.base.workflow
import eos.psr.bitstream
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.objects import *
from eos.core.hashing import *
from eos.base.election import *
class CyclicGroup(EmbeddedObject):
@ -120,7 +121,7 @@ class SEGPublicKey(EGPublicKey):
gamma = pow(self.group.g, r, self.group.p) # h
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
@ -136,6 +137,6 @@ class SEGCiphertext(EGCiphertext):
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
_, 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

View File

@ -16,6 +16,7 @@
from eos.core.bigint import *
from eos.core.objects import *
from eos.core.hashing import *
from eos.psr.election import *
class RPCMixnet:
@ -63,7 +64,7 @@ class RPCMixnet:
for i in range(len(permutations_and_reenc)):
val = permutations_and_reenc[i]
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:
for i in range(len(permutations_and_reenc)):
# Find the answer that went to 'i'
@ -71,7 +72,7 @@ class RPCMixnet:
val = permutations_and_reenc[idx]
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
return shuffled_answers, commitments

View File

@ -17,6 +17,7 @@
from eos.core.tests import *
from eos.core.bigint import *
from eos.core.hashing import *
from eos.psr.bitstream import *
from eos.psr.crypto import *
from eos.psr.election import *
@ -158,7 +159,7 @@ class MixnetTestCase(EosTestCase):
for i in range(len(pts)):
perm, reencs, rand = mixnet.challenge(i)
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:
verify_shuffle(i, perm, reencs)