progress on deterministic channel keys

This commit is contained in:
Lex Berezhny 2021-10-13 10:56:10 -04:00
parent 5eb95d7dd4
commit f741b00768
5 changed files with 40 additions and 8 deletions

View file

@ -2704,12 +2704,13 @@ class Daemon(metaclass=JSONRPCServerType):
name, claim, amount, claim_address, funding_accounts, funding_accounts[0]
)
txo = tx.outputs[0]
await txo.generate_channel_private_key()
txo.set_channel_private_key(
await funding_accounts[0].generate_channel_private_key()
)
await tx.sign(funding_accounts)
if not preview:
account.add_channel_private_key(txo.private_key)
wallet.save()
await self.broadcast_or_release(tx, blocking)
self.component_manager.loop.create_task(self.storage.save_claims([self._old_get_temp_claim_info(

View file

@ -34,6 +34,22 @@ def validate_claim_id(claim_id):
raise Exception("Claim id is not hex encoded")
class DeterministicChannelKeyManager:
def __init__(self, account):
self.account = account
self.public_key = account.public_key.child(2)
self.private_key = account.private_key.child(2) if account.private_key else None
def generate_next_key(self):
db = self.account.ledger.db
i = 0
while True:
next_key = self.private_key.child(i)
if not await db.is_channel_key_used(self.account, next_key.address):
return next_key
class AddressManager:
name: str
@ -252,6 +268,7 @@ class Account:
self.receiving, self.change = self.address_generator.from_dict(self, address_generator)
self.address_managers = {am.chain_number: am for am in (self.receiving, self.change)}
self.channel_keys = channel_keys
self.deterministic_channel_keys = DeterministicChannelKeyManager(self)
ledger.add_account(self)
wallet.add_account(self)
@ -520,6 +537,11 @@ class Account:
return tx
async def generate_channel_private_key(self):
key = self.deterministic_channel_keys.generate_next_key()
self.add_channel_private_key(key)
return key
def add_channel_private_key(self, private_key):
public_key_bytes = private_key.get_verifying_key().to_der()
channel_pubkey_hash = self.ledger.public_key_to_address(public_key_bytes)

View file

@ -1241,6 +1241,12 @@ class Database(SQLiteMixin):
async def set_address_history(self, address, history):
await self._set_address_history(address, history)
async def is_channel_key_used(self, account, address):
for channel in await self.get_channels(accounts=[account]):
if channel.private_key.address == address:
return True
return False
@staticmethod
def constrain_purchases(constraints):
accounts = constraints.pop('accounts', None)

View file

@ -469,13 +469,11 @@ class Output(InputOutput):
self.channel = None
self.signable.clear_signature()
async def generate_channel_private_key(self):
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()
def set_channel_private_key(self, private_key):
self.private_key = private_key
self.claim.channel.public_key_bytes = private_key.get_verifying_key().to_der()
self.script.generate()
return self.private_key
return private_key
def is_channel_private_key(self, private_key):
return self.claim.channel.public_key_bytes == private_key.get_verifying_key().to_der()

View file

@ -174,3 +174,8 @@ class AccountManagement(CommandTestCase):
bad_address = address[0:20] + '9999999' + address[27:]
with self.assertRaisesRegex(Exception, f"'{bad_address}' is not a valid address"):
await self.daemon.jsonrpc_account_send('0.1', addresses=[bad_address])
async def test_deterministic_channel_keys(self):
seed = self.account.seed
await self.channel_create('@foo1')
self.daemon2 = await self.add_daemon(seed=seed)