channel private key generation in a thread pool

This commit is contained in:
Jack Robison 2020-05-11 14:10:34 -04:00
parent 870e139fce
commit c22482f907
No known key found for this signature in database
GPG key ID: DF25C68FE0239BB2
7 changed files with 37 additions and 32 deletions

View file

@ -2550,7 +2550,7 @@ class Daemon(metaclass=JSONRPCServerType):
name, claim, amount, claim_address, funding_accounts, funding_accounts[0] name, claim, amount, claim_address, funding_accounts, funding_accounts[0]
) )
txo = tx.outputs[0] txo = tx.outputs[0]
txo.generate_channel_private_key() await txo.generate_channel_private_key()
await tx.sign(funding_accounts) await tx.sign(funding_accounts)
@ -2702,7 +2702,7 @@ class Daemon(metaclass=JSONRPCServerType):
new_txo = tx.outputs[0] new_txo = tx.outputs[0]
if new_signing_key: if new_signing_key:
new_txo.generate_channel_private_key() await new_txo.generate_channel_private_key()
else: else:
new_txo.private_key = old_txo.private_key new_txo.private_key = old_txo.private_key

View file

@ -525,11 +525,13 @@ class Account:
channel_pubkey_hash = self.ledger.public_key_to_address(public_key_bytes) channel_pubkey_hash = self.ledger.public_key_to_address(public_key_bytes)
self.channel_keys[channel_pubkey_hash] = private_key.to_pem().decode() self.channel_keys[channel_pubkey_hash] = private_key.to_pem().decode()
def get_channel_private_key(self, public_key_bytes): async def get_channel_private_key(self, public_key_bytes):
channel_pubkey_hash = self.ledger.public_key_to_address(public_key_bytes) channel_pubkey_hash = self.ledger.public_key_to_address(public_key_bytes)
private_key_pem = self.channel_keys.get(channel_pubkey_hash) private_key_pem = self.channel_keys.get(channel_pubkey_hash)
if private_key_pem: if private_key_pem:
return ecdsa.SigningKey.from_pem(private_key_pem, hashfunc=sha256) return await asyncio.get_event_loop().run_in_executor(
None, ecdsa.SigningKey.from_pem, private_key_pem, sha256
)
async def maybe_migrate_certificates(self): async def maybe_migrate_certificates(self):
def to_der(private_key_pem): def to_der(private_key_pem):

View file

@ -918,7 +918,7 @@ class Database(SQLiteMixin):
channel_ids.add(txo.claim.signing_channel_id) channel_ids.add(txo.claim.signing_channel_id)
if txo.claim.is_channel and wallet: if txo.claim.is_channel and wallet:
for account in wallet.accounts: for account in wallet.accounts:
private_key = account.get_channel_private_key( private_key = await account.get_channel_private_key(
txo.claim.channel.public_key_bytes txo.claim.channel.public_key_bytes
) )
if private_key: if private_key:

View file

@ -2,6 +2,7 @@ import struct
import hashlib import hashlib
import logging import logging
import typing import typing
import asyncio
from binascii import hexlify, unhexlify from binascii import hexlify, unhexlify
from typing import List, Iterable, Optional, Tuple from typing import List, Iterable, Optional, Tuple
@ -412,8 +413,10 @@ class Output(InputOutput):
self.channel = None self.channel = None
self.claim.clear_signature() self.claim.clear_signature()
def generate_channel_private_key(self): async def generate_channel_private_key(self):
self.private_key = ecdsa.SigningKey.generate(curve=ecdsa.SECP256k1, hashfunc=hashlib.sha256) self.private_key = await asyncio.get_event_loop().run_in_executor(
None, ecdsa.SigningKey.generate, ecdsa.SECP256k1, None, hashlib.sha256
)
self.claim.channel.public_key_bytes = self.private_key.get_verifying_key().to_der() self.claim.channel.public_key_bytes = self.private_key.get_verifying_key().to_der()
self.script.generate() self.script.generate()
return self.private_key return self.private_key

View file

@ -31,7 +31,7 @@ class BasicTransactionTest(IntegrationTestCase):
channel_txo = Output.pay_claim_name_pubkey_hash( channel_txo = Output.pay_claim_name_pubkey_hash(
l2d('1.0'), '@bar', channel, self.account.ledger.address_to_hash160(address1) l2d('1.0'), '@bar', channel, self.account.ledger.address_to_hash160(address1)
) )
channel_txo.generate_channel_private_key() await channel_txo.generate_channel_private_key()
channel_txo.script.generate() channel_txo.script.generate()
channel_tx = await Transaction.create([], [channel_txo], [self.account], self.account) channel_tx = await Transaction.create([], [channel_txo], [self.account], self.account)

View file

@ -18,31 +18,31 @@ class TestSigningComments(AsyncioTestCase):
'comment_id': hashlib.sha256(comment.encode()).hexdigest() 'comment_id': hashlib.sha256(comment.encode()).hexdigest()
} }
def test01_successful_create_sign_and_validate_comment(self): async def test01_successful_create_sign_and_validate_comment(self):
channel = get_channel('@BusterBluth') channel = await get_channel('@BusterBluth')
stream = get_stream('pop secret') stream = get_stream('pop secret')
comment = self.create_claim_comment_body('Cool stream', stream, channel) comment = self.create_claim_comment_body('Cool stream', stream, channel)
sign_comment(comment, channel) sign_comment(comment, channel)
self.assertTrue(is_comment_signed_by_channel(comment, channel)) self.assertTrue(is_comment_signed_by_channel(comment, channel))
def test02_fail_to_validate_spoofed_channel(self): async def test02_fail_to_validate_spoofed_channel(self):
pdiddy = get_channel('@PDitty') pdiddy = await get_channel('@PDitty')
channel2 = get_channel('@TomHaverford') channel2 = await get_channel('@TomHaverford')
stream = get_stream() stream = get_stream()
comment = self.create_claim_comment_body('Woahh This is Sick!! Shout out 2 my boy Tommy H', stream, pdiddy) comment = self.create_claim_comment_body('Woahh This is Sick!! Shout out 2 my boy Tommy H', stream, pdiddy)
sign_comment(comment, channel2) sign_comment(comment, channel2)
self.assertFalse(is_comment_signed_by_channel(comment, pdiddy)) self.assertFalse(is_comment_signed_by_channel(comment, pdiddy))
def test03_successful_sign_abandon_comment(self): async def test03_successful_sign_abandon_comment(self):
rswanson = get_channel('@RonSwanson') rswanson = await get_channel('@RonSwanson')
dsilver = get_stream('Welcome to the Pawnee, and give a big round for Ron Swanson, AKA Duke Silver') dsilver = get_stream('Welcome to the Pawnee, and give a big round for Ron Swanson, AKA Duke Silver')
comment_body = self.create_claim_comment_body('COMPUTER, DELETE ALL VIDEOS OF RON.', dsilver, rswanson) comment_body = self.create_claim_comment_body('COMPUTER, DELETE ALL VIDEOS OF RON.', dsilver, rswanson)
sign_comment(comment_body, rswanson, abandon=True) sign_comment(comment_body, rswanson, abandon=True)
self.assertTrue(is_comment_signed_by_channel(comment_body, rswanson, abandon=True)) self.assertTrue(is_comment_signed_by_channel(comment_body, rswanson, abandon=True))
def test04_invalid_signature(self): async def test04_invalid_signature(self):
rswanson = get_channel('@RonSwanson') rswanson = await get_channel('@RonSwanson')
jeanralphio = get_channel('@JeanRalphio') jeanralphio = await get_channel('@JeanRalphio')
chair = get_stream('This is a nice chair. I made it with Mahogany wood and this electric saw') chair = get_stream('This is a nice chair. I made it with Mahogany wood and this electric saw')
chair_comment = self.create_claim_comment_body( chair_comment = self.create_claim_comment_body(
'Hah. You use an electric saw? Us swansons have been making chairs with handsaws just three after birth.', 'Hah. You use an electric saw? Us swansons have been making chairs with handsaws just three after birth.',

View file

@ -21,9 +21,9 @@ def get_tx():
return Transaction().add_inputs([get_input()]) return Transaction().add_inputs([get_input()])
def get_channel(claim_name='@foo'): async def get_channel(claim_name='@foo'):
channel_txo = Output.pay_claim_name_pubkey_hash(CENT, claim_name, Claim(), b'abc') channel_txo = Output.pay_claim_name_pubkey_hash(CENT, claim_name, Claim(), b'abc')
channel_txo.generate_channel_private_key() await channel_txo.generate_channel_private_key()
get_tx().add_outputs([channel_txo]) get_tx().add_outputs([channel_txo])
return channel_txo return channel_txo
@ -36,32 +36,32 @@ def get_stream(claim_name='foo'):
class TestSigningAndValidatingClaim(AsyncioTestCase): class TestSigningAndValidatingClaim(AsyncioTestCase):
def test_successful_create_sign_and_validate(self): async def test_successful_create_sign_and_validate(self):
channel = get_channel() channel = await get_channel()
stream = get_stream() stream = get_stream()
stream.sign(channel) stream.sign(channel)
self.assertTrue(stream.is_signed_by(channel)) self.assertTrue(stream.is_signed_by(channel))
def test_fail_to_validate_on_wrong_channel(self): async def test_fail_to_validate_on_wrong_channel(self):
stream = get_stream() stream = get_stream()
stream.sign(get_channel()) stream.sign(await get_channel())
self.assertFalse(stream.is_signed_by(get_channel())) self.assertFalse(stream.is_signed_by(await get_channel()))
def test_fail_to_validate_altered_claim(self): async def test_fail_to_validate_altered_claim(self):
channel = get_channel() channel = await get_channel()
stream = get_stream() stream = get_stream()
stream.sign(channel) stream.sign(channel)
self.assertTrue(stream.is_signed_by(channel)) self.assertTrue(stream.is_signed_by(channel))
stream.claim.stream.title = 'hello' stream.claim.stream.title = 'hello'
self.assertFalse(stream.is_signed_by(channel)) self.assertFalse(stream.is_signed_by(channel))
def test_valid_private_key_for_cert(self): async def test_valid_private_key_for_cert(self):
channel = get_channel() channel = await get_channel()
self.assertTrue(channel.is_channel_private_key(channel.private_key)) self.assertTrue(channel.is_channel_private_key(channel.private_key))
def test_fail_to_load_wrong_private_key_for_cert(self): async def test_fail_to_load_wrong_private_key_for_cert(self):
channel = get_channel() channel = await get_channel()
self.assertFalse(channel.is_channel_private_key(get_channel().private_key)) self.assertFalse(channel.is_channel_private_key((await get_channel()).private_key))
class TestValidatingOldSignatures(AsyncioTestCase): class TestValidatingOldSignatures(AsyncioTestCase):