diff --git a/opentimestamps/core/op.py b/opentimestamps/core/op.py index b67a2b7..efe5ba9 100644 --- a/opentimestamps/core/op.py +++ b/opentimestamps/core/op.py @@ -347,3 +347,6 @@ def _do_op_call(self, msg): r = sha3.keccak_256(bytes(msg)).digest() assert len(r) == self.DIGEST_LENGTH return r + +from opentimestamps.core.s2c import OpSignToContract + diff --git a/opentimestamps/core/s2c.py b/opentimestamps/core/s2c.py index a877457..efeb6a5 100644 --- a/opentimestamps/core/s2c.py +++ b/opentimestamps/core/s2c.py @@ -9,6 +9,27 @@ # modified, propagated, or distributed except according to the terms contained # in the LICENSE file. +import hashlib + +from opentimestamps.core.op import BinaryOp, MsgValueError + +@BinaryOp._register_op +class OpSignToContract(BinaryOp): + """Execute the map commit -> [P + sha256(P||commit)G]_x for a given secp256k1 point P""" + TAG = b'\x09' + TAG_NAME = 'signtocontract' + + def _do_op_call(self, msg): + hasher = hashlib.sha256() + pt = Point.decode(self[0]) + hasher.update(pt.encode()) + hasher.update(msg) + tweak = int.from_bytes(hasher.digest(), 'big') + tweak_pt = SECP256K1_GEN.scalar_mul(tweak) + final_pt = pt.add(tweak_pt) + return final_pt.x.to_bytes(32, 'big') + + ## What follows is a lot of inefficient but explicit secp256k1 math class Point(object): inf = True diff --git a/opentimestamps/tests/core/test_s2c.py b/opentimestamps/tests/core/test_s2c.py index 19fc8dd..56e320c 100644 --- a/opentimestamps/tests/core/test_s2c.py +++ b/opentimestamps/tests/core/test_s2c.py @@ -9,6 +9,7 @@ # modified, propagated, or distributed except according to the terms contained # in the LICENSE file. +import hashlib import binascii import unittest @@ -20,7 +21,7 @@ def test_point_rt(self): gen = SECP256K1_GEN encode = gen.encode() self.assertEqual(encode, binascii.unhexlify("0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798")) - gen2 = Point().decode(encode) + gen2 = Point.decode(encode) self.assertEqual(gen, gen2) def test_pinv(self): @@ -99,3 +100,9 @@ def test_scalar_mul(self): self.assertEqual(p2.scalar_mul(-1), np2) self.assertEqual(p1.scalar_mul(3), p3) + def test_op_signtocontract(self): + pt_encode = binascii.unhexlify("0308aec434612f56df3f02c4e678260424415882ebd3efc16d52e3f9c1e39afdb0") + msg = hashlib.sha256("This is andytoshi on 2017-05-16 21:30 UTC".encode()).digest() + result = binascii.unhexlify("d386ef692770fcecad43362cf541858662e4ebe31d3ad04d196f94168897947a") + self.assertEqual(OpSignToContract(pt_encode)(msg), result) +