Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add benfen support #219

Merged
merged 3 commits into from
Dec 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions common/protob/messages-benfen.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
syntax = "proto2";
package hw.trezor.messages.benfen;

// Sugar for easier handling in Java
option java_package = "com.satoshilabs.trezor.lib.protobuf";
option java_outer_classname = "TrezorMessageSui";

/**
* Request: Address at the specified index
* @start
* @next BenfenAddress
*/
message BenfenGetAddress {
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
optional bool show_display = 2; // optionally show on display before sending the result
}

/**
* Response: Address for the given index
* @end
*/
message BenfenAddress {
optional string address = 1; // Benfen address as hex-encoded string
}

/**
* Request: ask device to sign Sui transaction
* @start
* @next BenfenSignedTx/SuiTxRequest
*/
message BenfenSignTx {
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
required bytes raw_tx = 2; // serialized raw transaction
optional bytes data_initial_chunk = 3 [default='']; // The initial data chunk (<= 1024 bytes)
optional bytes coin_type = 4;
optional uint32 data_length = 5; // Length of transaction payload
}


/**
* Response: signature for transaction
* @end
*/
message BenfenSignedTx {
required bytes public_key = 1; // public key for the private key used to sign tx
required bytes signature = 2; // the signature of the raw transaction
}

/**
* Response: Device asks for more data from transaction payload, or returns the signature.
* If data_length is set, device awaits that many more bytes of payload.
* Otherwise, the signature fields contain the computed transaction signature. All three fields will be present.
* @end
* @next SuiTxAck
*/
message BenfenTxRequest {
optional uint32 data_length = 1; // Number of bytes being requested (<= 1024)
optional bytes public_key = 2; // public key for the private key used to sign tx
optional bytes signature = 3; // the signature of the raw transaction
}

/**
* Request: Transaction payload data.
* @next BenfenTxRequest
*/
message BenfenTxAck {
required bytes data_chunk = 1; // Bytes from transaction payload (<= 1024 bytes)
}

/**
* Request: Ask device to sign message
* @next SuiMessageSignature
* @next Failure
*/
message BenfenSignMessage {
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
required bytes message = 2; // message to be signed
}

/**
* Response: Signed message
* @end
*/
message BenfenMessageSignature {
required bytes signature = 1; // signature of the message
required string address = 2; // address used to sign the message
}
10 changes: 10 additions & 0 deletions common/protob/messages.proto
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,16 @@ enum MessageType {
MessageType_AlephiumSignMessage = 12109 [(wire_in) = true];
MessageType_AlephiumMessageSignature = 12110 [(wire_out) = true];

// benfen
MessageType_BenfenGetAddress = 12201 [(wire_in) = true];
MessageType_BenfenAddress = 12202 [(wire_out) = true];
MessageType_BenfenSignTx = 12203 [(wire_in) = true];
MessageType_BenfenSignedTx = 12204 [(wire_out) = true];
MessageType_BenfenSignMessage = 12205 [(wire_in) = true];
MessageType_BenfenMessageSignature = 12206 [(wire_out) = true];
MessageType_BenfenTxRequest = 12207 [(wire_out) = true];
MessageType_BenfenTxAck = 12208 [(wire_in) = true];


//onekey
MessageType_DeviceBackToBoot = 903 [(wire_in) = true];
Expand Down
1 change: 1 addition & 0 deletions core/SConscript.firmware
Original file line number Diff line number Diff line change
Expand Up @@ -967,6 +967,7 @@ if FROZEN:
SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/scdo/*.py'))

SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/alephium/*.py'))
SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/benfen/*.py'))
guowei0105 marked this conversation as resolved.
Show resolved Hide resolved

SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/ur_registry/*.py'))
SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/ur_registry/*/*.py'))
Expand Down
2 changes: 1 addition & 1 deletion core/embed/firmware/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#define FIX_VERSION_BUILD 99

#define ONEKEY_VERSION_MAJOR 4
#define ONEKEY_VERSION_MINOR 11
#define ONEKEY_VERSION_MINOR 12
#define ONEKEY_VERSION_PATCH 0
#define ONEKEY_VERSION_BUILD 0

Expand Down
14 changes: 14 additions & 0 deletions core/src/all_modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,20 @@
import apps.aptos.sign_tx
apps.base
import apps.base
apps.benfen
import apps.benfen
apps.benfen.get_address
import apps.benfen.get_address
apps.benfen.helper
import apps.benfen.helper
apps.benfen.layout
import apps.benfen.layout
apps.benfen.sign_message
import apps.benfen.sign_message
apps.benfen.sign_tx
import apps.benfen.sign_tx
apps.benfen.tx_parser
import apps.benfen.tx_parser
apps.bitcoin
import apps.bitcoin
apps.bitcoin.addresses
Expand Down
8 changes: 8 additions & 0 deletions core/src/apps/benfen/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from apps.common.paths import PATTERN_BIP44_ED25519

CURVE = "ed25519"
SLIP44_ID = 728

PATTERN = PATTERN_BIP44_ED25519
PRIMARY_COLOR = 0xCD4937
ICON = "A:/res/chain-benfen.png"
41 changes: 41 additions & 0 deletions core/src/apps/benfen/get_address.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from typing import TYPE_CHECKING

from trezor.lvglui.scrs import lv
from trezor.messages import BenfenAddress
from trezor.ui.layouts import show_address

from apps.common import paths, seed
from apps.common.keychain import auto_keychain

from . import ICON, PRIMARY_COLOR
from .helper import benfen_address_from_pubkey, try_convert_to_bfc_address

if TYPE_CHECKING:
from trezor.messages import BenfenGetAddress
from trezor.wire import Context
from apps.common.keychain import Keychain


@auto_keychain(__name__)
async def get_address(
ctx: Context, msg: BenfenGetAddress, keychain: Keychain
guowei0105 marked this conversation as resolved.
Show resolved Hide resolved
) -> BenfenAddress:
await paths.validate_path(ctx, keychain, msg.address_n)
ctx.primary_color, ctx.icon_path = lv.color_hex(PRIMARY_COLOR), ICON
node = keychain.derive(msg.address_n)
pub_key_bytes = seed.remove_ed25519_prefix(node.public_key())
address = benfen_address_from_pubkey(pub_key_bytes)

bfc_address = try_convert_to_bfc_address(address)
if bfc_address:
address = bfc_address

if msg.show_display:
path = paths.address_n_to_str(msg.address_n)
await show_address(
ctx,
address=address,
address_n=path,
network="BENFEN",
)
return BenfenAddress(address=address)
57 changes: 57 additions & 0 deletions core/src/apps/benfen/helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
from ubinascii import hexlify

from trezor.crypto.hashlib import blake2b, sha256
from trezor.strings import format_amount

INTENT_BYTES = b"\x00\x00\x00"
PERSONALMESSAGE_INTENT_BYTES = b"\x03\x00\x00"


def benfen_address_from_pubkey(pub_key_bytes: bytes) -> str:
payloads = b"\x00" + pub_key_bytes
h = blake2b(data=payloads, outlen=32).digest()
return f"0x{hexlify(h).decode()}"


def try_convert_to_bfc_address(sui_addr: str) -> str | None:

if len(sui_addr) < 3 or not (sui_addr[0] == "0" and (sui_addr[1] in "xX")):
return None

hex_part = sui_addr[2:]
if len(hex_part) == 0 or len(hex_part) > 64:
return None

for c in hex_part:
if not (c.isdigit() or c in "abcdefABCDEF"):
return None

padding = 64 - len(hex_part)
if padding > 0:
hex_part = "0" * padding + hex_part

h = sha256()
h.update(hex_part.encode("utf-8"))
digest = h.digest()

checksum = "".join([f"{b:02x}" for b in digest[:2]])

return "BFC" + hex_part + checksum


def uleb_encode(num: int) -> bytes:
arr = bytearray()
while num > 0:
val = num & 127
num = num >> 7
if num != 0:
val |= 128
arr.append(val)
return arr


def format_benfen_amount(amount: int, currency_symbol: str = "BFC") -> str:

decimals = 9
formatted = format_amount(amount, decimals)
return f"{formatted} {currency_symbol}"
53 changes: 53 additions & 0 deletions core/src/apps/benfen/layout.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from trezor.enums import ButtonRequestType
from trezor.lvglui.i18n import gettext as _, keys as i18n_keys
from trezor.ui.layouts import should_show_details
from trezor.wire import Context

from .helper import format_benfen_amount


async def require_show_overview(
ctx: Context,
to_addr: str,
value: int,
currency_symbol: str = "BFC",
) -> bool:
from trezor.strings import strip_amount

return await should_show_details(
ctx,
title=_(i18n_keys.TITLE__SEND_MULTILINE).format(
strip_amount(format_benfen_amount(value, currency_symbol))[0]
guowei0105 marked this conversation as resolved.
Show resolved Hide resolved
),
address=to_addr,
br_code=ButtonRequestType.SignTx,
)


async def require_confirm_fee(
ctx: Context,
from_address: str,
to_address: str,
value: int,
gas_price: int,
gas_budget: int,
guowei0105 marked this conversation as resolved.
Show resolved Hide resolved
currency_symbol: str = "BFC",
) -> None:
from trezor.ui.layouts.lvgl.altcoin import confirm_total_ethereum

total_amount = (
format_benfen_amount(value + gas_price, currency_symbol)
if currency_symbol == "BFC"
else None
)
fee_currency = currency_symbol if currency_symbol == "BFC" else "BFC"

await confirm_total_ethereum(
ctx=ctx,
amount=format_benfen_amount(value, currency_symbol),
gas_price=None,
fee_max=format_benfen_amount(gas_price, fee_currency),
from_address=from_address,
to_address=to_address,
total_amount=total_amount,
)
47 changes: 47 additions & 0 deletions core/src/apps/benfen/sign_message.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from trezor import wire
from trezor.crypto.curve import ed25519
from trezor.crypto.hashlib import blake2b
from trezor.lvglui.scrs import lv
from trezor.messages import BenfenMessageSignature, BenfenSignMessage

from apps.common import paths, seed
from apps.common.keychain import Keychain, auto_keychain
from apps.common.signverify import decode_message

from . import ICON, PRIMARY_COLOR
from .helper import (
PERSONALMESSAGE_INTENT_BYTES,
benfen_address_from_pubkey,
try_convert_to_bfc_address,
uleb_encode,
)


@auto_keychain(__name__)
async def sign_message(
ctx: wire.Context, msg: BenfenSignMessage, keychain: Keychain
) -> BenfenMessageSignature:

await paths.validate_path(ctx, keychain, msg.address_n)

node = keychain.derive(msg.address_n)
pub_key_bytes = seed.remove_ed25519_prefix(node.public_key())
address = benfen_address_from_pubkey(pub_key_bytes)
bfc_address = try_convert_to_bfc_address(address)
if bfc_address is None:
raise wire.DataError("bfc_address is none")
guowei0105 marked this conversation as resolved.
Show resolved Hide resolved

len_bytes = uleb_encode(len(msg.message))
intentMessage = PERSONALMESSAGE_INTENT_BYTES + len_bytes + msg.message

from trezor.ui.layouts import confirm_signverify

ctx.primary_color, ctx.icon_path = lv.color_hex(PRIMARY_COLOR), ICON
await confirm_signverify(
ctx, "Benfen", decode_message(msg.message), bfc_address, False
)
guowei0105 marked this conversation as resolved.
Show resolved Hide resolved

signature = ed25519.sign(
node.private_key(), blake2b(data=intentMessage, outlen=32).digest()
)
return BenfenMessageSignature(signature=signature, address=bfc_address)
Loading
Loading