commit 4db893a68a324c3ac16ece85c4f3b36e2d768fa8 Author: Damian Johnson atagar@torproject.org Date: Thu Nov 7 15:22:13 2019 -0800
Merge ed25519_exts_ref into hsv3_crypto
Moving the subset of ed25519_exts_ref that's used into hsv3_crypto to give myself one fewer modules to puzzle out. --- stem/descriptor/ed25519_exts_ref.py | 243 ------------------------------------ stem/descriptor/hsv3_crypto.py | 46 +++++-- 2 files changed, 39 insertions(+), 250 deletions(-)
diff --git a/stem/descriptor/ed25519_exts_ref.py b/stem/descriptor/ed25519_exts_ref.py deleted file mode 100644 index 23701315..00000000 --- a/stem/descriptor/ed25519_exts_ref.py +++ /dev/null @@ -1,243 +0,0 @@ -#!/usr/bin/python -# Copyright 2014-2019, The Tor Project, Inc -# See LICENSE for licensing information - -""" - Reference implementations for the ed25519 tweaks that Tor uses. - - Includes self-tester and test vector generator. -""" - -from stem.descriptor import slow_ed25519 - -import os -import unittest -import binascii -import textwrap - -# define a synonym that doesn't look like 1 -ell = slow_ed25519.l - -# This replaces expmod above and makes it go a lot faster. -slow_ed25519.expmod = pow - - -def blindESK(esk, param): - mult = 2 ** (slow_ed25519.b - 2) + sum(2 ** i * slow_ed25519.bit(param, i) for i in range(3, slow_ed25519.b - 2)) - s = slow_ed25519.decodeint(esk[:32]) - s_prime = (s * mult) % ell - k = esk[32:] - assert(len(k) == 32) - k_prime = slow_ed25519.H(b'Derive temporary signing key hash input' + k)[:32] - return slow_ed25519.encodeint(s_prime) + k_prime - - -def blindPK(pk, param): - mult = 2 ** (slow_ed25519.b - 2) + sum(2 ** i * slow_ed25519.bit(param, i) for i in range(3, slow_ed25519.b - 2)) - P = slow_ed25519.decodepoint(pk) - return slow_ed25519.encodepoint(slow_ed25519.scalarmult(P, mult)) - - -def expandSK(sk): - h = slow_ed25519.H(sk) - a = 2 ** (slow_ed25519.b - 2) + sum(2 ** i * slow_ed25519.bit(h, i) for i in range(3, slow_ed25519.b - 2)) - k = b''.join([h[i:i + 1] for i in range(slow_ed25519.b // 8, slow_ed25519.b // 4)]) - assert len(k) == 32 - return slow_ed25519.encodeint(a) + k - - -def publickeyFromESK(h): - a = slow_ed25519.decodeint(h[:32]) - A = slow_ed25519.scalarmult(slow_ed25519.B, a) - return slow_ed25519.encodepoint(A) - - -def signatureWithESK(m, h, pk): - a = slow_ed25519.decodeint(h[:32]) - r = slow_ed25519.Hint(b''.join([h[i:i + 1] for i in range(slow_ed25519.b // 8, slow_ed25519.b // 4)]) + m) - R = slow_ed25519.scalarmult(slow_ed25519.B, r) - S = (r + slow_ed25519.Hint(slow_ed25519.encodepoint(R) + pk + m) * a) % slow_ed25519.l - - return slow_ed25519.encodepoint(R) + slow_ed25519.encodeint(S) - - -def newSK(): - return os.urandom(32) - - -def random_scalar(entropy_f): - # 0..L-1 inclusive - # reduce the bias to a safe level by generating 256 extra bits - - oversized = int(binascii.hexlify(entropy_f(32 + 32)), 16) - return oversized % ell - - -# ------------------------------------------------------------ - -MSG = b'This is extremely silly. But it is also incredibly serious business!' - - -class SelfTest(unittest.TestCase): - def _testSignatures(self, esk, pk): - sig = signatureWithESK(MSG, esk, pk) - slow_ed25519.checkvalid(sig, MSG, pk) - bad = False - - try: - slow_ed25519.checkvalid(sig, MSG * 2, pk) - bad = True - except Exception: - pass - - self.assertFalse(bad) - - def testExpand(self): - sk = newSK() - pk = slow_ed25519.publickey(sk) - esk = expandSK(sk) - sig1 = slow_ed25519.signature(MSG, sk, pk) - sig2 = signatureWithESK(MSG, esk, pk) - self.assertEqual(sig1, sig2) - - def testSignatures(self): - sk = newSK() - esk = expandSK(sk) - pk = publickeyFromESK(esk) - pk2 = slow_ed25519.publickey(sk) - self.assertEqual(pk, pk2) - - self._testSignatures(esk, pk) - - def testBlinding(self): - sk = newSK() - esk = expandSK(sk) - pk = publickeyFromESK(esk) - param = os.urandom(32) - besk = blindESK(esk, param) - bpk = blindPK(pk, param) - bpk2 = publickeyFromESK(besk) - self.assertEqual(bpk, bpk2) - - self._testSignatures(besk, bpk) - - def testIdentity(self): - # Get identity E by doing: E = l*B, where l is the group order - identity = slow_ed25519.scalarmult(slow_ed25519.B, ell) - - # Get identity E by doing: E = l*A, where A is a random point - sk = newSK() - pk = slow_ed25519.decodepoint(slow_ed25519.publickey(sk)) - identity2 = slow_ed25519.scalarmult(pk, ell) - - # Check that identities match - assert(identity == identity2) - # Check that identity is the point (0, 1) - assert(identity == [0, 1]) - - # Check identity element: a*E = E, where a is a random scalar - scalar = random_scalar(os.urandom) - result = slow_ed25519.scalarmult(identity, scalar) - assert(result == identity == identity2) - - -# ------------------------------------------------------------ - -# From pprint.pprint([binascii.b2a_hex(os.urandom(32)) for _ in xrange(8)]) -RAND_INPUTS = [ - '26c76712d89d906e6672dafa614c42e5cb1caac8c6568e4d2493087db51f0d36', - 'fba7a5366b5cb98c2667a18783f5cf8f4f8d1a2ce939ad22a6e685edde85128d', - '67e3aa7a14fac8445d15e45e38a523481a69ae35513c9e4143eb1c2196729a0e', - 'd51385942033a76dc17f089a59e6a5a7fe80d9c526ae8ddd8c3a506b99d3d0a6', - '5c8eac469bb3f1b85bc7cd893f52dc42a9ab66f1b02b5ce6a68e9b175d3bb433', - 'eda433d483059b6d1ff8b7cfbd0fe406bfb23722c8f3c8252629284573b61b86', - '4377c40431c30883c5fbd9bc92ae48d1ed8a47b81d13806beac5351739b5533d', - 'c6bbcce615839756aed2cc78b1de13884dd3618f48367a17597a16c1cd7a290b'] - -# From pprint.pprint([binascii.b2a_hex(os.urandom(32)) for _ in xrange(8)]) -BLINDING_PARAMS = [ - '54a513898b471d1d448a2f3c55c1de2c0ef718c447b04497eeb999ed32027823', - '831e9b5325b5d31b7ae6197e9c7a7baf2ec361e08248bce055908971047a2347', - 'ac78a1d46faf3bfbbdc5af5f053dc6dc9023ed78236bec1760dadfd0b2603760', - 'f9c84dc0ac31571507993df94da1b3d28684a12ad14e67d0a068aba5c53019fc', - 'b1fe79d1dec9bc108df69f6612c72812755751f21ecc5af99663b30be8b9081f', - '81f1512b63ab5fb5c1711a4ec83d379c420574aedffa8c3368e1c3989a3a0084', - '97f45142597c473a4b0e9a12d64561133ad9e1155fe5a9807fe6af8a93557818', - '3f44f6a5a92cde816635dfc12ade70539871078d2ff097278be2a555c9859cd0'] - -PREFIX = 'ED25519_' - - -def writeArray(name, array): - print('static const char *{prefix}{name}[] = {{'.format(prefix = PREFIX, name = name)) - - for a in array: - h = a.hex() - - if len(h) > 70: - h1 = h[:70] - h2 = h[70:] - print(' "{0}"\n "{1}",'.format(h1, h2)) - else: - print(' "{0}",'.format(h)) - - print('};\n') - - -def comment(text, initial='/**'): - print(initial) - print(textwrap.fill(text, initial_indent = ' * ', subsequent_indent = ' * ')) - print(' */') - - -def makeTestVectors(): - comment("""Test vectors for our ed25519 implementation and related - functions. These were automatically generated by the - ed25519_exts_ref.py script.""", initial = '/*') - - comment("""Secret key seeds used as inputs for the ed25519 test vectors. - Randomly generated. """) - secretKeys = [bytes.fromhex(r) for r in RAND_INPUTS] - writeArray('SECRET_KEYS', secretKeys) - - comment("""Secret ed25519 keys after expansion from seeds. This is how Tor - represents them internally.""") - expandedSecretKeys = [expandSK(sk) for sk in secretKeys] - writeArray('EXPANDED_SECRET_KEYS', expandedSecretKeys) - - comment('Public keys derived from the above secret keys') - publicKeys = [slow_ed25519.publickey(sk) for sk in secretKeys] - writeArray('PUBLIC_KEYS', publicKeys) - - comment('Parameters used for key blinding tests. Randomly generated.') - blindingParams = [binascii.a2b_hex(r) for r in BLINDING_PARAMS] - writeArray('BLINDING_PARAMS', blindingParams) - - comment("""Blinded secret keys for testing key blinding. The nth blinded - key corresponds to the nth secret key blidned with the nth - blinding parameter.""") - - writeArray('BLINDED_SECRET_KEYS', (blindESK(expandSK(sk), bp) for sk, bp in zip(secretKeys, blindingParams))) - - comment("""Blinded public keys for testing key blinding. The nth blinded - key corresponds to the nth public key blidned with the nth - blinding parameter.""") - - writeArray('BLINDED_PUBLIC_KEYS', (blindPK(pk, bp) for pk, bp in zip(publicKeys, blindingParams))) - - comment("""Signatures of the public keys, made with their corresponding - secret keys.""") - writeArray('SELF_SIGNATURES', (slow_ed25519.signature(pk, sk, pk) for pk, sk in zip(publicKeys, secretKeys))) - - -if __name__ == '__main__': - import sys - - if len(sys.argv) == 1 or sys.argv[1] not in ('SelfTest', 'MakeVectors'): - print ("You should specify one of 'SelfTest' or 'MakeVectors'") - sys.exit(1) - - if sys.argv[1] == 'SelfTest': - unittest.main() - else: - makeTestVectors() diff --git a/stem/descriptor/hsv3_crypto.py b/stem/descriptor/hsv3_crypto.py index 5bce5dcf..80759aa2 100644 --- a/stem/descriptor/hsv3_crypto.py +++ b/stem/descriptor/hsv3_crypto.py @@ -2,8 +2,7 @@ import hashlib import struct import os
-import stem.descriptor.ed25519_exts_ref -import stem.descriptor.slow_ed25519 +from stem.descriptor import slow_ed25519
""" @@ -21,6 +20,39 @@ certificate module. """
+def blindESK(esk, param): + mult = 2 ** (slow_ed25519.b - 2) + sum(2 ** i * slow_ed25519.bit(param, i) for i in range(3, slow_ed25519.b - 2)) + s = slow_ed25519.decodeint(esk[:32]) + s_prime = (s * mult) % slow_ed25519.l + k = esk[32:] + assert(len(k) == 32) + k_prime = slow_ed25519.H(b'Derive temporary signing key hash input' + k)[:32] + return slow_ed25519.encodeint(s_prime) + k_prime + + +def blindPK(pk, param): + mult = 2 ** (slow_ed25519.b - 2) + sum(2 ** i * slow_ed25519.bit(param, i) for i in range(3, slow_ed25519.b - 2)) + P = slow_ed25519.decodepoint(pk) + return slow_ed25519.encodepoint(slow_ed25519.scalarmult(P, mult)) + + +def expandSK(sk): + h = slow_ed25519.H(sk) + a = 2 ** (slow_ed25519.b - 2) + sum(2 ** i * slow_ed25519.bit(h, i) for i in range(3, slow_ed25519.b - 2)) + k = b''.join([h[i:i + 1] for i in range(slow_ed25519.b // 8, slow_ed25519.b // 4)]) + assert len(k) == 32 + return slow_ed25519.encodeint(a) + k + + +def signatureWithESK(m, h, pk): + a = slow_ed25519.decodeint(h[:32]) + r = slow_ed25519.Hint(b''.join([h[i:i + 1] for i in range(slow_ed25519.b // 8, slow_ed25519.b // 4)]) + m) + R = slow_ed25519.scalarmult(slow_ed25519.B, r) + S = (r + slow_ed25519.Hint(slow_ed25519.encodepoint(R) + pk + m) * a) % slow_ed25519.l + + return slow_ed25519.encodepoint(R) + slow_ed25519.encodeint(S) + + class HSv3PrivateBlindedKey(object): def __init__(self, hazmat_private_key, blinding_param): from cryptography.hazmat.primitives import serialization @@ -28,14 +60,14 @@ class HSv3PrivateBlindedKey(object): secret_seed = hazmat_private_key.private_bytes(encoding = serialization.Encoding.Raw, format = serialization.PrivateFormat.Raw, encryption_algorithm = serialization.NoEncryption()) assert(len(secret_seed) == 32)
- expanded_identity_priv_key = stem.descriptor.ed25519_exts_ref.expandSK(secret_seed) - identity_public_key = stem.descriptor.slow_ed25519.publickey(secret_seed) + expanded_identity_priv_key = expandSK(secret_seed) + identity_public_key = slow_ed25519.publickey(secret_seed)
- self.blinded_secret_key = stem.descriptor.ed25519_exts_ref.blindESK(expanded_identity_priv_key, blinding_param) - self.blinded_pubkey = stem.descriptor.ed25519_exts_ref.blindPK(identity_public_key, blinding_param) + self.blinded_secret_key = blindESK(expanded_identity_priv_key, blinding_param) + self.blinded_pubkey = blindPK(identity_public_key, blinding_param)
def sign(self, msg): - return stem.descriptor.ed25519_exts_ref.signatureWithESK(msg, self.blinded_secret_key, self.blinded_pubkey) + return signatureWithESK(msg, self.blinded_secret_key, self.blinded_pubkey)
"""