You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
74 lines
2.7 KiB
74 lines
2.7 KiB
![]()
2 years ago
|
from typing import TYPE_CHECKING
|
||
|
|
||
|
from trezor.enums import ButtonRequestType
|
||
|
from trezor.messages import CosiCommitment, CosiSign, CosiSignature
|
||
|
from trezor.wire import DataError
|
||
|
|
||
|
from apps.common.paths import PathSchema, unharden
|
||
|
|
||
|
if TYPE_CHECKING:
|
||
|
from trezor.messages import CosiCommit
|
||
|
from trezor.wire import Context
|
||
|
|
||
|
# This module implements the cosigner part of the CoSi collective signatures
|
||
|
# as described in https://dedis.cs.yale.edu/dissent/papers/witness.pdf
|
||
|
|
||
|
|
||
|
SCHEMA_SLIP18 = PathSchema.parse("m/10018'/address_index'/*'", slip44_id=())
|
||
|
# SLIP-26: m/10026'/model'/type'/rotation_index'
|
||
|
# - `model`: ASCII for 1, T, or R, or 0 for common things (keep the ASCII range open for future models).
|
||
|
# - `type`: 0 = bootloader, 1 = vendorheader, 2 = firmware, 3 = definitions, 4 = reserved
|
||
|
# - `rotation_index`: a fixed 0' for now
|
||
|
SCHEMA_SLIP26 = PathSchema.parse("m/10026'/[0-127]'/[0-4]'/0'", slip44_id=())
|
||
|
|
||
|
|
||
|
async def cosi_commit(ctx: Context, msg: CosiCommit) -> CosiSignature:
|
||
|
import storage.cache as storage_cache
|
||
|
from trezor.crypto.curve import ed25519
|
||
|
from trezor.ui.layouts import confirm_blob
|
||
|
from apps.common import paths
|
||
|
from apps.common.keychain import get_keychain
|
||
|
|
||
|
keychain = await get_keychain(ctx, "ed25519", [SCHEMA_SLIP18, SCHEMA_SLIP26])
|
||
|
await paths.validate_path(ctx, keychain, msg.address_n)
|
||
|
|
||
|
node = keychain.derive(msg.address_n)
|
||
|
seckey = node.private_key()
|
||
|
pubkey = ed25519.publickey(seckey)
|
||
|
|
||
|
if not storage_cache.is_set(storage_cache.APP_MISC_COSI_COMMITMENT):
|
||
|
nonce, commitment = ed25519.cosi_commit()
|
||
|
storage_cache.set(storage_cache.APP_MISC_COSI_NONCE, nonce)
|
||
|
storage_cache.set(storage_cache.APP_MISC_COSI_COMMITMENT, commitment)
|
||
|
commitment = storage_cache.get(storage_cache.APP_MISC_COSI_COMMITMENT)
|
||
|
if commitment is None:
|
||
|
raise RuntimeError
|
||
|
|
||
|
sign_msg = await ctx.call(
|
||
|
CosiCommitment(commitment=commitment, pubkey=pubkey), CosiSign
|
||
|
)
|
||
|
|
||
|
if sign_msg.address_n != msg.address_n:
|
||
|
raise DataError("Mismatched address_n")
|
||
|
|
||
|
title = "CoSi sign message"
|
||
|
if SCHEMA_SLIP18.match(sign_msg.address_n):
|
||
|
index = unharden(msg.address_n[1])
|
||
|
title = f"CoSi sign index {index}"
|
||
|
|
||
|
await confirm_blob(
|
||
|
ctx, "cosi_sign", title, sign_msg.data, br_code=ButtonRequestType.ProtectCall
|
||
|
)
|
||
|
|
||
|
# clear nonce from cache
|
||
|
nonce = storage_cache.get(storage_cache.APP_MISC_COSI_NONCE)
|
||
|
storage_cache.delete(storage_cache.APP_MISC_COSI_COMMITMENT)
|
||
|
storage_cache.delete(storage_cache.APP_MISC_COSI_NONCE)
|
||
|
if nonce is None:
|
||
|
raise RuntimeError
|
||
|
|
||
|
signature = ed25519.cosi_sign(
|
||
|
seckey, sign_msg.data, nonce, sign_msg.global_commitment, sign_msg.global_pubkey
|
||
|
)
|
||
|
return CosiSignature(signature=signature)
|