Refactor hashing out into separate library
This commit is contained in:
parent
3427b376b5
commit
a242f1f666
82
eos/core/hashing/__init__.py
Normal file
82
eos/core/hashing/__init__.py
Normal 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)
|
@ -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):
|
||||||
|
@ -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):
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user