Add native Segwit addresses support and pivx, vertcoin, viacoin

This commit is contained in:
BTChip github 2017-10-20 16:10:19 +02:00
parent 6fcd9d27f0
commit d69b8dd70c
No known key found for this signature in database
GPG Key ID: 48BCF826EBFA4D17
25 changed files with 1133 additions and 91 deletions

View File

@ -24,7 +24,7 @@ APP_LOAD_PARAMS=--appFlags 0x50 --path "" --curve secp256k1 $(COMMON_LOAD_PARAMS
APPVERSION_M=1
APPVERSION_N=1
APPVERSION_P=8
APPVERSION_P=12
APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)
# ifndef COIN
@ -33,11 +33,11 @@ APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)
ifeq ($(COIN),bitcoin_testnet)
# Bitcoin testnet
DEFINES += BTCHIP_P2PKH_VERSION=111 BTCHIP_P2SH_VERSION=196 BTCHIP_COIN_FAMILY=1 BTCHIP_COINID=\"Bitcoin\" COINID_UPCASE=\"BITCOIN\" COLOR_HDR=0xFCB653 COLOR_DB=0xFEDBA9 COINID_NAME=\"Bitcoin\" COINID=$(COIN) BTCHIP_COINID_SHORT=\"TEST\" COIN_BITCOIN_TESTNET
DEFINES += BTCHIP_P2PKH_VERSION=111 BTCHIP_P2SH_VERSION=196 BTCHIP_COIN_FAMILY=1 BTCHIP_COINID=\"Bitcoin\" COINID_UPCASE=\"BITCOIN\" COLOR_HDR=0xFCB653 COLOR_DB=0xFEDBA9 COINID_NAME=\"Bitcoin\" COINID=$(COIN) BTCHIP_COINID_SHORT=\"TEST\" NATIVE_SEGWIT_PREFIX=\"tb\" COIN_BITCOIN_TESTNET HAVE_SEGWIT_CHANGE_SUPPORT
APPNAME ="Bitcoin Test"
else ifeq ($(COIN),bitcoin)
# Bitcoin mainnet
DEFINES += BTCHIP_P2PKH_VERSION=0 BTCHIP_P2SH_VERSION=5 BTCHIP_COIN_FAMILY=1 BTCHIP_COINID=\"Bitcoin\" COINID_UPCASE=\"BITCOIN\" COLOR_HDR=0xFCB653 COLOR_DB=0xFEDBA9 COINID_NAME=\"Bitcoin\" COINID=$(COIN) BTCHIP_COINID_SHORT=\"BTC\" COIN_BITCOIN
DEFINES += BTCHIP_P2PKH_VERSION=0 BTCHIP_P2SH_VERSION=5 BTCHIP_COIN_FAMILY=1 BTCHIP_COINID=\"Bitcoin\" COINID_UPCASE=\"BITCOIN\" COLOR_HDR=0xFCB653 COLOR_DB=0xFEDBA9 COINID_NAME=\"Bitcoin\" COINID=$(COIN) BTCHIP_COINID_SHORT=\"BTC\" NATIVE_SEGWIT_PREFIX=\"bc\" COIN_BITCOIN HAVE_SEGWIT_CHANGE_SUPPORT
APPNAME ="Bitcoin"
else ifeq ($(COIN),bitcoin_cash)
# Bitcoin cash
@ -45,7 +45,7 @@ DEFINES += BTCHIP_P2PKH_VERSION=0 BTCHIP_P2SH_VERSION=5 BTCHIP_COIN_FAMILY=1 B
APPNAME ="Bitcoin Cash"
else ifeq ($(COIN),litecoin)
# Litecoin
DEFINES += BTCHIP_P2PKH_VERSION=48 BTCHIP_P2SH_VERSION=5 BTCHIP_COIN_FAMILY=1 BTCHIP_COINID=\"Litecoin\" COINID_UPCASE=\"LITECOIN\" COLOR_HDR=0xCCCCCC COLOR_DB=0xE6E6E6 COINID_NAME=\"Litecoin\" COINID=$(COIN) BTCHIP_COINID_SHORT=\"LTC\" COIN_LITECOIN
DEFINES += BTCHIP_P2PKH_VERSION=48 BTCHIP_P2SH_VERSION=50 BTCHIP_COIN_FAMILY=1 BTCHIP_COINID=\"Litecoin\" COINID_UPCASE=\"LITECOIN\" COLOR_HDR=0xCCCCCC COLOR_DB=0xE6E6E6 COINID_NAME=\"Litecoin\" COINID=$(COIN) BTCHIP_COINID_SHORT=\"LTC\" COIN_LITECOIN HAVE_SEGWIT_CHANGE_SUPPORT
APPNAME ="Litecoin"
else ifeq ($(COIN),dogecoin)
# Doge
@ -74,9 +74,21 @@ APPNAME ="Peercoin"
else ifeq ($(COIN),posw)
DEFINES += BTCHIP_P2PKH_VERSION=55 BTCHIP_P2SH_VERSION=85 BTCHIP_COIN_FAMILY=2 BTCHIP_COINID=\"PoSWallet\" COINID_UPCASE=\"POSW\" COLOR_HDR=0x23273D COLOR_DB=0x91939E COINID_NAME=\"PoSW\" COINID=$(COIN) BTCHIP_COINID_SHORT=\"POSW\" COIN_POSW HAVE_PEERCOIN_SUPPORT
APPNAME ="PoSW"
else ifeq ($(COIN),pivx)
# PivX
DEFINES += BTCHIP_P2PKH_VERSION=30 BTCHIP_P2SH_VERSION=13 BTCHIP_COIN_FAMILY=1 BTCHIP_COINID=\"DarkNet\" COINID_UPCASE=\"PIVX\" COLOR_HDR=0x46385D COLOR_DB=0x9E96AA COINID_NAME=\"PivX\" COINID=$(COIN) BTCHIP_COINID_SHORT=\"PIV\" COIN_PIVX
APPNAME ="PIVX"
else ifeq ($(COIN),viacoin)
# Viacoin
DEFINES += BTCHIP_P2PKH_VERSION=71 BTCHIP_P2SH_VERSION=33 BTCHIP_COIN_FAMILY=1 BTCHIP_COINID=\"Viacoin\" COINID_UPCASE=\"VIACOIN\" COLOR_HDR=0x414141 COLOR_DB=0xA0A0A0 COINID_NAME=\"Viacoin\" COINID=$(COIN) BTCHIP_COINID_SHORT=\"VIA\" COIN_VIACOIN HAVE_SEGWIT_CHANGE_SUPPORT
APPNAME ="Viacoin"
else ifeq ($(COIN),vertcoin)
# Vertcoin
DEFINES += BTCHIP_P2PKH_VERSION=71 BTCHIP_P2SH_VERSION=5 BTCHIP_COIN_FAMILY=1 BTCHIP_COINID=\"Vertcoin\" COINID_UPCASE=\"VERTCOIN\" COLOR_HDR=0x1B5C2E COLOR_DB=0x8DAE97 COINID_NAME=\"Vertcoin\" COINID=$(COIN) BTCHIP_COINID_SHORT=\"VTC\" COIN_VERTCOIN HAVE_SEGWIT_CHANGE_SUPPORT
APPNAME ="Vertcoin"
else
ifeq ($(filter clean,$(MAKECMDGOALS)),)
$(error Unsupported COIN - use bitcoin_testnet, bitcoin, bitcoin_cash, litecoin, dogecoin, dash, zcash, komodo, stratis, peercoin, posw)
$(error Unsupported COIN - use bitcoin_testnet, bitcoin, bitcoin_cash, litecoin, dogecoin, dash, zcash, komodo, stratis, peercoin, posw, pivx, viacoin, vertcoin)
endif
endif

BIN
blue_app_pivx.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 395 B

BIN
blue_app_vertcoin.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 397 B

BIN
blue_app_viacoin.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 433 B

593
doc/btc.asc Normal file
View File

@ -0,0 +1,593 @@
Bitcoin application : Common Technical Specifications
=====================================================
Ledger Firmware Team <hello@ledger.fr>
Application version 1.1.9
== 1.1.9
- Split specification from common firmware
- Add display and segwit options to GET WALLET PUBLIC KEY
== About
This specification describes the APDU messages interface to communicate with the Bitcoin
application. It is based on the HW.1 firmware specification detailed on https://github.com/LedgerHQ/btchip-doc
== Wallet usage APDUs
=== GET WALLET PUBLIC KEY
==== Description
This command returns the public key and Base58 encoded address for the given BIP 32 path.
==== Coding
'Command'
[width="80%"]
|==============================================================================================================================
| *CLA* | *INS* | *P1* | *P2* | *Lc* | *Le*
| E0 | 40 | 00 : do not display the address
01 : display the address
| 00 : return a legacy address
01 : return a P2SH-P2WPKH address
02 : return a Bech32 encoded P2WPKH address | variable | variable
|==============================================================================================================================
'Input data'
[width="80%"]
|==============================================================================================================================
| *Description* | *Length*
| Number of BIP 32 derivations to perform (max 10) | 1
| First derivation index (big endian) | 4
| ... | 4
| Last derivation index (big endian) | 4
|==============================================================================================================================
'Output data'
[width="80%"]
|==============================================================================================================================
| *Description* | *Length*
| Public Key length | 1
| Uncompressed Public Key | var
| Bitcoin address length | 1
| Bitcoin address | var
| BIP32 Chain code | 32
|==============================================================================================================================
=== GET TRUSTED INPUT
==== Description
This command is used to extract a Trusted Input (encrypted transaction hash, output index, output amount) from a transaction.
The transaction data to be provided should be encoded using bitcoin standard raw transaction encoding. Scripts can be sent over several APDUs. Other individual transaction elements split over different APDUs will be rejected. 64 bits varints are rejected.
==== Coding
'Command'
[width="80%"]
|==============================================================================================================================
| *CLA* | *INS* | *P1* | *P2* | *Lc* | *Le*
| E0 | 42 | 00 : first transaction data block
80 : subsequent transaction data block | 00 | var | var
|==============================================================================================================================
'Input data (first block)'
[width="80%"]
|==============================================================================================================================
| *Description* | *Length*
| Input index to lookup (big endian) | 4
| Transaction data | var
|==============================================================================================================================
'Input data (next block)'
[width="80%"]
|==============================================================================================================================
| *Description* | *Length*
| Transaction data | var
|==============================================================================================================================
'Output data (non last block)'
None
'Output data (last block)'
[width="80%"]
|==============================================================================================================================
| *Description* | *Length*
| Trusted Input | 56
|==============================================================================================================================
=== UNTRUSTED HASH TRANSACTION INPUT START
==== Description
This command is used to compose an opaque SHA-256 hash for a new transaction.
This transaction can be verified by the user on screen
The transaction data to be provided should be encoded using bitcoin standard raw transaction encoded as follows :
- A 1 byte flag is added before each input in the transaction - the following flags are valid
- 0x01 if the input is passed as a Trusted Input, previously computed by the dongle. In this case, each input outpoint is replaced by the Trusted Input length (1 byte) and the Trusted Input data
- 0x00 if the input is passed as a non Trusted Input (passing the original 36 bytes prevout). Non Trusted Inputs will generate a specific warning on screen as fees cannot be computed in that case
- 0x02 if the input is passed as a Segregated Witness Input, defined as the concatenation of the original 36 bytes prevout and the original 8 bytes little endian amount associated to this input. When using this mode, all transaction inputs shall be passed as Segregated Witness Inputs, and the signature mechanism defined for version 0 witness program in BIP 143 (https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki) will be used.
- The input scripts shall be prepared by the host for the transaction signing process as per bitcoin rules : the current input script being signed shall be the previous output script (or the redeeming script when consuming a P2SH output, or the scriptCode when consuming a BIP 143 output), and other input script shall be null.
- The encoded transaction data shall be provided up to (and not including) the number of outputs.
- Scripts can be sent over several APDUs. Other individual transaction elements split over different APDUs will be rejected. 64 bits varints are rejected.
- When using Segregated Witness Inputs, the signing mechanism differs slightly :
* The transaction shall be processed first with all inputs having a null script length (to be done twice if the dongle has been powercycled to retrieve the authorization code)
* Then each input to sign shall be processed as part of a pseudo transaction with a single input and no outputs.
==== Coding
'Command'
[width="80%"]
|==============================================================================================================================
| *CLA* | *INS* | *P1* | *P2* | *Lc* | *Le*
| E0 | 44 | 00 : first transaction data block
80 : subsequent transaction data block |
00 : start signing a new transaction
02 : start signing a new transaction containing Segregated Witness Inputs
80 : continue signing another input of the current transaction | var | var
|==============================================================================================================================
'Input data'
[width="80%"]
|==============================================================================================================================
| *Description* | *Length*
| Transaction data | var
|==============================================================================================================================
'Output data'
None
=== UNTRUSTED HASH SIGN
==== Description
This command is used to sign a given secure hash using a private key (after re-hashing it following the standard Bitcoin signing process) to finalize a transaction input signing process.
This command will be rejected if the transaction signing state is not consistent or if a user validation is required and the provided user validation code is not correct.
==== Coding
'Command'
[width="80%"]
|==============================================================================================================================
| *CLA* | *INS* | *P1* | *P2* | *Lc* | *Le*
| E0 | 48 | 00 | 00 | var | var
|==============================================================================================================================
'Input data'
[width="80%"]
|==============================================================================================================================
| *Description* | *Length*
| Number of BIP 32 derivations to perform (max 10) | 1
| First derivation index for the private key to use (big endian) | 4
| ... | 4
| Last derivation index for the private key to use (big endian) | 4
| RFU (0x00) | 1
| Lock Time (big endian) | 4
| SigHashType | 1
|==============================================================================================================================
'Output data'
[width="80%"]
|==============================================================================================================================
| *Description* | *Length*
| Signed hash, as ASN-1 encoded R & S components. Mask first byte with 0xFE | var
| SigHashType | 1
|==============================================================================================================================
=== UNTRUSTED HASH TRANSACTION INPUT FINALIZE FULL
==== Description
This command is used to compose an opaque SHA-256 hash for the transaction outputs
This command is rejected if all inputs advertised at the beginning of the transaction have not been processed first.
Only standard output scripts are accepted :
* Pay-to-PubkeyHash (OP_DUP OP_HASH160 [pubKeyHash] OP_EQUALVERIFY OP_CHECKSIG)
* Pay-to-Script-Hash (OP_HASH160 [script hash] OP_EQUAL)
* A single maximum 80 bytes OP_RETURN with a null value
* A P2WPKH (00 [20 bytes]) or P2WSH (00 [30 bytes]) version 0 witness program
==== Coding
'Command'
[width="80%"]
|==============================================================================================================================
| *CLA* | *INS* | *P1* | *P2* | *Lc* | *Le*
| E0 | 4A | 00 : more input data to be sent
80 : last input data block to be sent
FF : BIP 32 path specified for the change address
| 00 | var | var
|==============================================================================================================================
'Input data (first block, no providing a BIP 32 path)'
[width="80%"]
|==============================================================================================================================
| *Description* | *Length*
| Start of output data, containing the number of outputs encoded as a Bitcoin varint | var
|==============================================================================================================================
'Input data (providing a BIP 32 path)'
[width="80%"]
|==============================================================================================================================
| *Description* | *Length*
| Number of BIP 32 derivations to perform (max 10) | 1
| First derivation index for the private key to use (big endian) | 4
| ... | 4
| Last derivation index for the private key to use (big endian) | 4
|==============================================================================================================================
'Input data (optional next blocks)'
[width="80%"]
|==============================================================================================================================
| *Description* | *Length*
| Output data continued | var
|==============================================================================================================================
'Output data (providing a BIP 32 path)'
None
'Output data (not last block)'
[width="80%"]
|==============================================================================================================================
| *Description* | *Length*
| RFU (00) | 1
|==============================================================================================================================
'Output data (last block)'
[width="80%"]
|==============================================================================================================================
| *Description* | *Length*
| RFU (00) | 1
| Transaction user validation flag
0x00 : no user validation requested
| 1
|==============================================================================================================================
=== SIGN MESSAGE
==== Description
This command is used to sign message using a private key.
The signature is performed as follows :
- The data to sign is the magic "\x18Bitcoin Signed Message:\n" - followed by the length of the message to sign on 1 byte (if requested) followed by the binary content of the message
- The signature is performed on a double SHA-256 hash of the data to sign using the selected private key
The signature is returned using the standard ASN-1 encoding. To convert it to the proprietary Bitcoin-QT format, the host has to :
- Get the parity of the first byte (sequence) : P
- Add 27 to P if the public key is not compressed, otherwise add 31 to P
- Return the Base64 encoded version of P || r || s
If the low end word of one component of the BIP 32 derivation path includes 0xB11D or 0xB11E the message is immediately signed without confirmation (typically used for BitID).
==== Coding
'Command'
[width="80%"]
|==============================================================================================================================
| *CLA* | *INS* | *P1* | *P2* | *Lc* | *Le*
| E0 | 4E | 00 : prepare message
80 : sign message|
01 : when preparing, first part of the message
80 : when preparing, next part of the message
| var | var
|==============================================================================================================================
'Input data in prepare mode (first block)'
[width="80%"]
|==============================================================================================================================
| *Description* | *Length*
| Number of BIP 32 derivations to perform (max 10) | 1
| First derivation index of the private key to use (big endian) | 4
| ... | 4
| Last derivation index of the private key to use (big endian) | 4
| Message length (big endian, coded on 1 byte for legacy calls) | 2
| Message data | var
|==============================================================================================================================
'Input data in prepare mode (next blocks)'
[width="80%"]
|==============================================================================================================================
| *Description* | *Length*
| Message data | var
|==============================================================================================================================
'Input data in sign mode'
[width="80%"]
|==============================================================================================================================
| *Description* | *Length*
| User validation code length (or 00 in server mode) | 1
| User validation code | var
|==============================================================================================================================
'Output data in prepare mode (not last block)'
[width="80%"]
|==============================================================================================================================
| *Description* | *Length*
| RFU (00) | 1
|==============================================================================================================================
'Output data in prepare mode (last block)'
[width="80%"]
|==============================================================================================================================
| *Description* | *Length*
| RFU (00) | 1
| Transaction user validation flag
0x00 : no user validation requested
| 1
|==============================================================================================================================
'Output data in sign mode'
[width="80%"]
|==============================================================================================================================
| *Description* | *Length*
| ASN-1 encoded message signature with Y parity indicated in the first (sequence) byte | variable
|==============================================================================================================================
== Test and utility APDUs
=== GET RANDOM
==== Description
This command returns random bytes from the dongle hardware random number generator
==== Coding
'Command'
[width="80%"]
|==============================================================================================================================
| *CLA* | *INS* | *P1* | *P2* | *Lc* | *Le*
| E0 | C0 | 00 | 00 | 00 | variable
|==============================================================================================================================
'Input data'
None
'Output data'
[width="80%"]
|==============================================================================================================================
| *Description* | *Length*
| Random bytes | variable
|==============================================================================================================================
'Availability'
This function is always available.
=== GET FIRMWARE VERSION
==== Description
This command returns the firmware version of the dongle and additional features supported
==== Coding
'Command'
[width="80%"]
|==============================================================================================================================
| *CLA* | *INS* | *P1* | *P2* | *Lc* | *Le*
| E0 | C4 | 00 | 00 | 00 | 07
|==============================================================================================================================
'Input data'
None
'Output data'
[width="80%"]
|==============================================================================================================================
| *Description* | *Length*
| Features flag
0x01 : public keys are compressed (otherwise not compressed)
0x02 : implementation running with screen + buttons handled by the Secure Element
0x04 : implementation running with screen + buttons handled externally
0x08 : NFC transport and payment extensions supported
0x10 : BLE transport and low power extensions supported
0x20 : implementation running on a Trusted Execution Environment
| 01
| Architecture | 01
| Firmware major version | 01
| Firmware minor version | 01
| Firmware patch version | 01
| Loader ID major version (if applicable) | 01
| Loader ID minor version (if applicable) | 01
|==============================================================================================================================
'Availability'
This function is always available.
== Transport protocol
=== General transport description
Ledger APDUs requests and responses are encapsulated using a flexible protocol allowing to fragment large payloads over different underlying transport mechanisms.
The common transport header is defined as follows :
[width="80%"]
|==============================================================================================================================
| *Description* | *Length*
| Communication channel ID (big endian) | 2
| Command tag | 1
| Packet sequence index (big endian) | 2
| Payload | var
|==============================================================================================================================
The Communication channel ID allows commands multiplexing over the same physical link. It is not used for the time being, and should be set to 0101 to avoid compatibility issues with implementations ignoring a leading 00 byte.
The Command tag describes the message content. Use TAG_APDU (0x05) for standard APDU payloads, or TAG_PING (0x02) for a simple link test.
The Packet sequence index describes the current sequence for fragmented payloads. The first fragment index is 0x00.
=== APDU Command payload encoding
APDU Command payloads are encoded as follows :
[width="80%"]
|==============================================================================================================================
| *Description* | *Length*
| APDU length (big endian) | 2
| APDU CLA | 1
| APDU INS | 1
| APDU P1 | 1
| APDU P2 | 1
| APDU length | 1
| Optional APDU data | var
|==============================================================================================================================
APDU payload is encoded according to the APDU case
[width="80%"]
|=======================================================================================
| Case Number | *Lc* | *Le* | Case description
| 1 | 0 | 0 | No data in either direction - L is set to 00
| 2 | 0 | !0 | Input Data present, no Output Data - L is set to Lc
| 3 | !0 | 0 | Output Data present, no Input Data - L is set to Le
| 4 | !0 | !0 | Both Input and Output Data are present - L is set to Lc
|=======================================================================================
=== APDU Response payload encoding
APDU Response payloads are encoded as follows :
[width="80%"]
|==============================================================================================================================
| *Description* | *Length*
| APDU response length (big endian) | 2
| APDU response data and Status Word | var
|==============================================================================================================================
=== USB mapping
Messages are exchanged with the dongle over HID endpoints over interrupt transfers, with each chunk being 64 bytes long. The HID Report ID is ignored.
== Status Words
The following standard Status Words are returned for all APDUs - some specific Status Words can be used for specific commands and are mentioned in the command description.
'Status Words'
[width="80%"]
|===============================================================================================
| *SW* | *Description*
| 6700 | Incorrect length
| 6982 | Security status not satisfied (Bitcoin dongle is locked or invalid access rights)
| 6A80 | Invalid data
| 6A82 | File not found
| 6B00 | Incorrect parameter P1 or P2
| 6Fxx | Technical problem (Internal error, please report)
| 9000 | Normal ending of the command
|================================================================================================
== Data structures
The format of the data structures is provided for interoperability and validation purposes. A typical user will not need to manipulate them directly.
=== Encoded trusted input
An encoded trusted input is stored internally as follow. The signature is the last block of a Triple DES CBC encryption of the previous data by the trusted input encryption key.
[width="80%"]
|==============================================================================================================================
| *Description* | *Length*
| Magic version (*32*) | 1
| Flags
RFU
| 1
| Nonce | 2
| Associated transaction hash | 32
| Index in associated transaction (little endian) | 4
| Associated amount (little endian) | 8
| Signature | 8
|==============================================================================================================================

BIN
glyphs/blue_badge_pivx.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 344 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 362 B

BIN
glyphs/nanos_badge_pivx.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -24,7 +24,7 @@
#include "btchip_filesystem_tx.h"
#define MAX_OUTPUT_TO_CHECK 200
#define MAX_COIN_ID 10
#define MAX_COIN_ID 12
#define MAX_SHORT_COIN_ID 5
#define MAGIC_TRUSTED_INPUT 0x32

View File

@ -24,9 +24,12 @@
#define OUTPUT_SCRIPT_P2SH_PRE_LENGTH 3
#define OUTPUT_SCRIPT_P2SH_POST_LENGTH 1
#define OUTPUT_SCRIPT_NATIVE_WITNESS_PROGRAM_OFFSET 3
unsigned char btchip_output_script_is_regular(unsigned char *buffer);
unsigned char btchip_output_script_is_p2sh(unsigned char *buffer);
unsigned char btchip_output_script_is_op_return(unsigned char *buffer);
unsigned char btchip_output_script_is_native_witness(unsigned char *buffer);
void btchip_sleep16(unsigned short delay);
void btchip_sleep32(unsigned long int delayEach, unsigned long int delayRepeat);

BIN
nanos_app_pivx.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
nanos_app_vertcoin.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
nanos_app_viacoin.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -20,6 +20,8 @@
#include "btchip_bagl_extensions.h"
#include "segwit_addr.h"
#ifdef HAVE_U2F
#include "u2f_service.h"
@ -34,6 +36,10 @@ void u2f_proxy_response(u2f_service_t *service, unsigned int tx);
#define P1_NO_DISPLAY 0x00
#define P1_DISPLAY 0x01
#define P2_LEGACY 0x00
#define P2_SEGWIT 0x01
#define P2_NATIVE_SEGWIT 0x02
unsigned short btchip_apdu_get_wallet_public_key() {
unsigned char keyLength;
unsigned char uncompressedPublicKeys =
@ -41,10 +47,25 @@ unsigned short btchip_apdu_get_wallet_public_key() {
unsigned char keyPath[MAX_BIP32_PATH_LENGTH];
unsigned char chainCode[32];
bool display = (G_io_apdu_buffer[ISO_OFFSET_P1] == P1_DISPLAY);
bool segwit = (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_SEGWIT);
bool nativeSegwit = (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NATIVE_SEGWIT);
if (((G_io_apdu_buffer[ISO_OFFSET_P1] != P1_NO_DISPLAY) &&
(G_io_apdu_buffer[ISO_OFFSET_P1] != P1_DISPLAY)) ||
(G_io_apdu_buffer[ISO_OFFSET_P2] != 0x00)) {
switch (G_io_apdu_buffer[ISO_OFFSET_P1]) {
case P1_NO_DISPLAY:
case P1_DISPLAY:
break;
default:
return BTCHIP_SW_INCORRECT_P1_P2;
}
switch (G_io_apdu_buffer[ISO_OFFSET_P2]) {
case P2_LEGACY:
case P2_SEGWIT:
#ifdef NATIVE_SEGWIT_PREFIX
case P2_NATIVE_SEGWIT:
#endif
break;
default:
return BTCHIP_SW_INCORRECT_P1_P2;
}
@ -81,13 +102,36 @@ unsigned short btchip_apdu_get_wallet_public_key() {
os_memmove(G_io_apdu_buffer + 1, btchip_public_key_D.W,
sizeof(btchip_public_key_D.W));
keyLength = btchip_public_key_to_encoded_base58(
G_io_apdu_buffer + 1, // IN
keyLength, // INLEN
G_io_apdu_buffer + 67, // OUT
150, // MAXOUTLEN
btchip_context_D.payToAddressVersion, 0);
if (!(segwit || nativeSegwit)) {
keyLength = btchip_public_key_to_encoded_base58(
G_io_apdu_buffer + 1, // IN
keyLength, // INLEN
G_io_apdu_buffer + 67, // OUT
150, // MAXOUTLEN
btchip_context_D.payToAddressVersion, 0);
} else {
uint8_t tmp[22];
tmp[0] = 0x00;
tmp[1] = 0x14;
btchip_public_key_hash160(G_io_apdu_buffer + 1, // IN
keyLength, // INLEN
tmp + 2 // OUT
);
if (!nativeSegwit) {
keyLength = btchip_public_key_to_encoded_base58(
tmp, // IN
22, // INLEN
G_io_apdu_buffer + 67, // OUT
150, // MAXOUTLEN
btchip_context_D.payToScriptHashVersion, 0);
} else {
#ifdef NATIVE_SEGWIT_PREFIX
keyLength =
segwit_addr_encode((char *)(G_io_apdu_buffer + 67),
NATIVE_SEGWIT_PREFIX, 0, tmp + 2, 20);
#endif
}
}
G_io_apdu_buffer[66] = keyLength;
L_DEBUG_APP(("Length %d\n", keyLength));
if (!uncompressedPublicKeys) {

View File

@ -53,7 +53,8 @@ static void btchip_apdu_hash_input_finalize_full_reset(void) {
static bool check_output_displayable() {
bool displayable = true;
unsigned char amount[8], isOpReturn, isP2sh, j, nullAmount = 1;
unsigned char amount[8], isOpReturn, isP2sh, isNativeSegwit, j,
nullAmount = 1;
for (j = 0; j < 8; j++) {
if (btchip_context_D.currentOutput[j] != 0) {
nullAmount = 0;
@ -68,18 +69,43 @@ static bool check_output_displayable() {
isOpReturn =
btchip_output_script_is_op_return(btchip_context_D.currentOutput + 8);
isP2sh = btchip_output_script_is_p2sh(btchip_context_D.currentOutput + 8);
isNativeSegwit = btchip_output_script_is_native_witness(
btchip_context_D.currentOutput + 8);
if (!btchip_output_script_is_regular(btchip_context_D.currentOutput + 8) &&
!isP2sh && !(nullAmount && isOpReturn)) {
PRINTF("Error : Unrecognized input script");
THROW(EXCEPTION);
}
if (btchip_context_D.tmpCtx.output.changeInitialized && !isOpReturn) {
bool changeFound = false;
unsigned char addressOffset =
(isP2sh ? OUTPUT_SCRIPT_P2SH_PRE_LENGTH
: OUTPUT_SCRIPT_REGULAR_PRE_LENGTH);
if (os_memcmp(btchip_context_D.currentOutput + 8 + addressOffset,
(isNativeSegwit ? OUTPUT_SCRIPT_NATIVE_WITNESS_PROGRAM_OFFSET
: isP2sh ? OUTPUT_SCRIPT_P2SH_PRE_LENGTH
: OUTPUT_SCRIPT_REGULAR_PRE_LENGTH);
if (!isP2sh &&
os_memcmp(btchip_context_D.currentOutput + 8 + addressOffset,
btchip_context_D.tmpCtx.output.changeAddress + 1,
20) == 0) {
changeFound = true;
} else if (isP2sh && btchip_context_D.usingSegwit) {
unsigned char changeSegwit[22];
changeSegwit[0] = 0x00;
changeSegwit[1] = 0x14;
os_memmove(changeSegwit + 2,
btchip_context_D.tmpCtx.output.changeAddress + 1, 20);
btchip_public_key_hash160(changeSegwit, 22, changeSegwit);
if (os_memcmp(btchip_context_D.currentOutput + 8 + addressOffset,
changeSegwit, 20) == 0) {
#ifdef HAVE_SEGWIT_CHANGE_SUPPORT
changeFound = true;
#else
// Attempt to avoid fatal failures on Bitcoin Cash
PRINTF("Error : Non spendable Segwit change");
THROW(EXCEPTION);
#endif
}
}
if (changeFound) {
if (btchip_context_D.changeOutputFound) {
PRINTF("Error : Multiple change output found");
THROW(EXCEPTION);

View File

@ -28,7 +28,20 @@ const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE[] = {
0x17, 0xA9, 0x14}; // script length, OP_HASH160, address length
const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2SH_POST[] = {0x87}; // OP_EQUAL
#ifdef NATIVE_SEGWIT_PREFIX
const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE[] = {0x16, 0x00, 0x14};
const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE[] = {0x22, 0x00, 0x20};
#endif
unsigned char btchip_output_script_is_regular(unsigned char *buffer) {
#ifdef NATIVE_SEGWIT_PREFIX
if ((os_memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE,
sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE)) == 0) ||
(os_memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE,
sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE)) == 0)) {
return 1;
}
#endif
if ((os_memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_PRE,
sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE)) == 0) &&
(os_memcmp(buffer + sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE) + 20,
@ -50,6 +63,18 @@ unsigned char btchip_output_script_is_p2sh(unsigned char *buffer) {
return 0;
}
unsigned char btchip_output_script_is_native_witness(unsigned char *buffer) {
#ifdef NATIVE_SEGWIT_PREFIX
if ((os_memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE,
sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE)) == 0) ||
(os_memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE,
sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE)) == 0)) {
return 1;
}
#endif
return 0;
}
unsigned char btchip_output_script_is_op_return(unsigned char *buffer) {
return (buffer[1] == 0x6A);
}
@ -261,7 +286,12 @@ void btchip_signverify_finalhash(void WIDE *keyContext, unsigned char sign,
if (sign) {
cx_ecdsa_sign((cx_ecfp_private_key_t WIDE *)keyContext,
CX_LAST | (rfc6979 ? CX_RND_RFC6979 : CX_RND_TRNG),
CX_SHA256, in, inlen, out);
CX_SHA256, in, inlen, out
#if CX_APILEVEL >= 8
,
NULL
#endif
);
} else {
cx_ecdsa_verify((cx_ecfp_public_key_t WIDE *)keyContext, CX_LAST,
CX_SHA256, in, inlen, out, outlen);

View File

@ -190,8 +190,9 @@ void transaction_parse(unsigned char parseMode) {
NULL);
cx_hash(&btchip_context_D
.transactionHashAuthorization.header,
0, (unsigned char WIDE *)&btchip_context_D
.segwit.cache,
0,
(unsigned char WIDE *)&btchip_context_D
.segwit.cache,
sizeof(btchip_context_D.segwit.cache),
NULL);
}

View File

@ -25,6 +25,8 @@
#include "btchip_bagl_extensions.h"
#include "segwit_addr.h"
#include "glyphs.h"
#define __NAME3(a, b, c) a##b##c
@ -85,7 +87,7 @@ union {
// char addressSummary[40]; // beginning of the output address ... end
// of
char fullAddress[36]; // the address
char fullAddress[43]; // the address
char fullAmount[20]; // full amount
char feesAmount[20]; // fees
} tmp;
@ -2216,22 +2218,27 @@ error:
uint8_t prepare_single_output() {
// TODO : special display for OP_RETURN
unsigned char amount[8];
char tmp[40];
char tmp[80];
unsigned int offset = 0;
unsigned char versionSize;
int addressOffset;
unsigned char address[22];
unsigned short version;
unsigned short textSize;
unsigned char nativeSegwit;
btchip_swap_bytes(amount, btchip_context_D.currentOutput + offset, 8);
offset += 8;
nativeSegwit = btchip_output_script_is_native_witness(
btchip_context_D.currentOutput + offset);
if (btchip_output_script_is_op_return(btchip_context_D.currentOutput +
offset)) {
os_memmove(vars.tmp.fullAddress, "OP_RETURN", 9);
vars.tmp.fullAddress[10] = '\0';
vars.tmp.fullAmount[0] = '\0';
return 1;
} else if (nativeSegwit) {
addressOffset = offset + OUTPUT_SCRIPT_NATIVE_WITNESS_PROGRAM_OFFSET;
} else if (btchip_output_script_is_regular(btchip_context_D.currentOutput +
offset)) {
addressOffset = offset + 4;
@ -2240,22 +2247,32 @@ uint8_t prepare_single_output() {
addressOffset = offset + 3;
version = btchip_context_D.payToScriptHashVersion;
}
if (version > 255) {
versionSize = 2;
address[0] = (version >> 8);
address[1] = version;
} else {
versionSize = 1;
address[0] = version;
}
os_memmove(address + versionSize,
btchip_context_D.currentOutput + addressOffset, 20);
if (!nativeSegwit) {
if (version > 255) {
versionSize = 2;
address[0] = (version >> 8);
address[1] = version;
} else {
versionSize = 1;
address[0] = version;
}
os_memmove(address + versionSize,
btchip_context_D.currentOutput + addressOffset, 20);
// Prepare address
textSize = btchip_public_key_to_encoded_base58(address, 20 + versionSize,
(unsigned char *)tmp,
sizeof(tmp), version, 1);
tmp[textSize] = '\0';
// Prepare address
textSize = btchip_public_key_to_encoded_base58(
address, 20 + versionSize, (unsigned char *)tmp, sizeof(tmp),
version, 1);
tmp[textSize] = '\0';
}
#ifdef NATIVE_SEGWIT_PREFIX
else {
textSize = segwit_addr_encode(
tmp, NATIVE_SEGWIT_PREFIX, 0,
btchip_context_D.currentOutput + addressOffset,
btchip_context_D.currentOutput[addressOffset - 1]);
}
#endif
strcpy(vars.tmp.fullAddress, tmp);
@ -2280,7 +2297,7 @@ uint8_t prepare_full_output(uint8_t checkOnly) {
int i;
unsigned int currentPos = 0;
unsigned char amount[8], totalOutputAmount[8], fees[8];
char tmp[40];
char tmp[80];
unsigned char outputPos = 0, changeFound = 0;
if (btchip_context_D.transactionContext.relaxed &&
!btchip_context_D.transactionContext.consumeP2SH) {
@ -2310,7 +2327,7 @@ uint8_t prepare_full_output(uint8_t checkOnly) {
for (i = 0; i < numberOutputs; i++) {
unsigned char nullAmount = 1;
unsigned int j;
unsigned char isOpReturn, isP2sh;
unsigned char isOpReturn, isP2sh, isNativeSegwit;
for (j = 0; j < 8; j++) {
if (btchip_context_D.currentOutput[offset + j] != 0) {
nullAmount = 0;
@ -2324,6 +2341,8 @@ uint8_t prepare_full_output(uint8_t checkOnly) {
btchip_context_D.currentOutput + offset);
isP2sh = btchip_output_script_is_p2sh(btchip_context_D.currentOutput +
offset);
isNativeSegwit = btchip_output_script_is_native_witness(
btchip_context_D.currentOutput + offset);
if (!btchip_output_script_is_regular(btchip_context_D.currentOutput +
offset) &&
!isP2sh && !(nullAmount && isOpReturn)) {
@ -2334,8 +2353,9 @@ uint8_t prepare_full_output(uint8_t checkOnly) {
}
if (btchip_context_D.tmpCtx.output.changeInitialized && !isOpReturn) {
unsigned char addressOffset =
(isP2sh ? OUTPUT_SCRIPT_P2SH_PRE_LENGTH
: OUTPUT_SCRIPT_REGULAR_PRE_LENGTH);
(isNativeSegwit ? OUTPUT_SCRIPT_NATIVE_WITNESS_PROGRAM_OFFSET
: isP2sh ? OUTPUT_SCRIPT_P2SH_PRE_LENGTH
: OUTPUT_SCRIPT_REGULAR_PRE_LENGTH);
if (os_memcmp(btchip_context_D.currentOutput + offset +
addressOffset,
btchip_context_D.tmpCtx.output.changeAddress + 1,
@ -2380,34 +2400,54 @@ uint8_t prepare_full_output(uint8_t checkOnly) {
int addressOffset;
unsigned char address[22];
unsigned short version;
unsigned char isNativeSegwit;
isNativeSegwit = btchip_output_script_is_native_witness(
btchip_context_D.currentOutput + offset);
btchip_swap_bytes(amount,
btchip_context_D.currentOutput + offset, 8);
offset += 8;
if (btchip_output_script_is_regular(
btchip_context_D.currentOutput + offset)) {
addressOffset = offset + 4;
version = btchip_context_D.payToAddressVersion;
} else {
addressOffset = offset + 3;
version = btchip_context_D.payToScriptHashVersion;
if (!isNativeSegwit) {
if (btchip_output_script_is_regular(
btchip_context_D.currentOutput + offset)) {
addressOffset = offset + 4;
version = btchip_context_D.payToAddressVersion;
} else {
addressOffset = offset + 3;
version = btchip_context_D.payToScriptHashVersion;
}
if (version > 255) {
versionSize = 2;
address[0] = (version >> 8);
address[1] = version;
} else {
versionSize = 1;
address[0] = version;
}
os_memmove(address + versionSize,
btchip_context_D.currentOutput + addressOffset,
20);
}
if (version > 255) {
versionSize = 2;
address[0] = (version >> 8);
address[1] = version;
} else {
versionSize = 1;
address[0] = version;
}
os_memmove(address + versionSize,
btchip_context_D.currentOutput + addressOffset, 20);
if (currentPos == outputPos) {
unsigned short textSize;
// Prepare address
textSize = btchip_public_key_to_encoded_base58(
address, 20 + versionSize, (unsigned char *)tmp,
sizeof(tmp), version, 1);
tmp[textSize] = '\0';
if (!isNativeSegwit) {
// Prepare address
textSize = btchip_public_key_to_encoded_base58(
address, 20 + versionSize, (unsigned char *)tmp,
sizeof(tmp), version, 1);
tmp[textSize] = '\0';
}
#ifdef NATIVE_SEGWIT_PREFIX
else {
textSize = segwit_addr_encode(
tmp, NATIVE_SEGWIT_PREFIX, 0,
btchip_context_D.currentOutput + offset +
OUTPUT_SCRIPT_NATIVE_WITNESS_PROGRAM_OFFSET,
btchip_context_D.currentOutput
[offset +
OUTPUT_SCRIPT_NATIVE_WITNESS_PROGRAM_OFFSET -
1]);
}
#endif
strcpy(vars.tmp.fullAddress, tmp);

208
src/segwit_addr.c Normal file
View File

@ -0,0 +1,208 @@
/* Copyright (c) 2017 Pieter Wuille
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifdef NATIVE_SEGWIT_PREFIX
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "segwit_addr.h"
uint32_t bech32_polymod_step(uint32_t pre) {
uint8_t b = pre >> 25;
return ((pre & 0x1FFFFFF) << 5) ^ (-((b >> 0) & 1) & 0x3b6a57b2UL) ^
(-((b >> 1) & 1) & 0x26508e6dUL) ^ (-((b >> 2) & 1) & 0x1ea119faUL) ^
(-((b >> 3) & 1) & 0x3d4233ddUL) ^ (-((b >> 4) & 1) & 0x2a1462b3UL);
}
static const char *charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
static const int8_t charset_rev[128] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 15, -1, 10, 17, 21, 20, 26, 30, 7,
5, -1, -1, -1, -1, -1, -1, -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22,
31, 27, 19, -1, 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1,
-1, -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, 1, 0,
3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1};
int bech32_encode(char *output, const char *hrp, const uint8_t *data,
size_t data_len) {
uint32_t chk = 1;
size_t i = 0;
while (hrp[i] != 0) {
if (hrp[i] >= 'A' && hrp[i] <= 'Z')
return 0;
if (!(hrp[i] >> 5))
return 0;
chk = bech32_polymod_step(chk) ^ (hrp[i] >> 5);
++i;
}
if (i + 7 + data_len > 90)
return 0;
chk = bech32_polymod_step(chk);
while (*hrp != 0) {
chk = bech32_polymod_step(chk) ^ (*hrp & 0x1f);
*(output++) = *(hrp++);
}
*(output++) = '1';
for (i = 0; i < data_len; ++i) {
if (*data >> 5)
return 0;
chk = bech32_polymod_step(chk) ^ (*data);
*(output++) = charset[*(data++)];
}
for (i = 0; i < 6; ++i) {
chk = bech32_polymod_step(chk);
}
chk ^= 1;
for (i = 0; i < 6; ++i) {
*(output++) = charset[(chk >> ((5 - i) * 5)) & 0x1f];
}
*output = 0;
return 1;
}
int bech32_decode(char *hrp, uint8_t *data, size_t *data_len,
const char *input) {
uint32_t chk = 1;
size_t i;
size_t input_len = strlen(input);
size_t hrp_len;
int have_lower = 0, have_upper = 0;
if (input_len < 8 || input_len > 90) {
return 0;
}
*data_len = 0;
while (*data_len < input_len && input[(input_len - 1) - *data_len] != '1') {
++(*data_len);
}
hrp_len = input_len - (1 + *data_len);
if (hrp_len < 1 || *data_len < 6) {
return 0;
}
*(data_len) -= 6;
for (i = 0; i < hrp_len; ++i) {
int ch = input[i];
if (ch < 33 || ch > 126) {
return 0;
}
if (ch >= 'a' && ch <= 'z') {
have_lower = 1;
} else if (ch >= 'A' && ch <= 'Z') {
have_upper = 1;
ch = (ch - 'A') + 'a';
}
hrp[i] = ch;
chk = bech32_polymod_step(chk) ^ (ch >> 5);
}
hrp[i] = 0;
chk = bech32_polymod_step(chk);
for (i = 0; i < hrp_len; ++i) {
chk = bech32_polymod_step(chk) ^ (input[i] & 0x1f);
}
++i;
while (i < input_len) {
int v = (input[i] & 0x80) ? -1 : charset_rev[(int)input[i]];
if (input[i] >= 'a' && input[i] <= 'z')
have_lower = 1;
if (input[i] >= 'A' && input[i] <= 'Z')
have_upper = 1;
if (v == -1) {
return 0;
}
chk = bech32_polymod_step(chk) ^ v;
if (i + 6 < input_len) {
data[i - (1 + hrp_len)] = v;
}
++i;
}
if (have_lower && have_upper) {
return 0;
}
return chk == 1;
}
static int convert_bits(uint8_t *out, size_t *outlen, int outbits,
const uint8_t *in, size_t inlen, int inbits, int pad) {
uint32_t val = 0;
int bits = 0;
uint32_t maxv = (((uint32_t)1) << outbits) - 1;
while (inlen--) {
val = (val << inbits) | *(in++);
bits += inbits;
while (bits >= outbits) {
bits -= outbits;
out[(*outlen)++] = (val >> bits) & maxv;
}
}
if (pad) {
if (bits) {
out[(*outlen)++] = (val << (outbits - bits)) & maxv;
}
} else if (((val << (outbits - bits)) & maxv) || bits >= inbits) {
return 0;
}
return 1;
}
int segwit_addr_encode(char *output, const char *hrp, int witver,
const uint8_t *witprog, size_t witprog_len) {
uint8_t data[65];
size_t datalen = 0;
if (witver > 16)
return 0;
if (witver == 0 && witprog_len != 20 && witprog_len != 32)
return 0;
if (witprog_len < 2 || witprog_len > 40)
return 0;
data[0] = witver;
convert_bits(data + 1, &datalen, 5, witprog, witprog_len, 8, 1);
++datalen;
return bech32_encode(output, hrp, data, datalen);
}
int segwit_addr_decode(int *witver, uint8_t *witdata, size_t *witdata_len,
const char *hrp, const char *addr) {
uint8_t data[84];
char hrp_actual[84];
size_t data_len;
if (!bech32_decode(hrp_actual, data, &data_len, addr))
return 0;
if (data_len == 0 || data_len > 65)
return 0;
if (strncmp(hrp, hrp_actual, 84) != 0)
return 0;
if (data[0] > 16)
return 0;
*witdata_len = 0;
if (!convert_bits(witdata, witdata_len, 8, data + 1, data_len - 1, 5, 0))
return 0;
if (*witdata_len < 2 || *witdata_len > 40)
return 0;
if (data[0] == 0 && *witdata_len != 20 && *witdata_len != 32)
return 0;
*witver = data[0];
return 1;
}
#endif

84
src/segwit_addr.h Normal file
View File

@ -0,0 +1,84 @@
/* Copyright (c) 2017 Pieter Wuille
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef _SEGWIT_ADDR_H_
#define _SEGWIT_ADDR_H_ 1
#include <stdint.h>
/** Encode a SegWit address
*
* Out: output: Pointer to a buffer of size 73 + strlen(hrp) that will be
* updated to contain the null-terminated address.
* In: hrp: Pointer to the null-terminated human readable part to use
* (chain/network specific).
* ver: Version of the witness program (between 0 and 16 inclusive).
* prog: Data bytes for the witness program (between 2 and 40 bytes).
* prog_len: Number of data bytes in prog.
* Returns 1 if successful.
*/
int segwit_addr_encode(char *output, const char *hrp, int ver,
const uint8_t *prog, size_t prog_len);
/** Decode a SegWit address
*
* Out: ver: Pointer to an int that will be updated to contain the witness
* program version (between 0 and 16 inclusive).
* prog: Pointer to a buffer of size 40 that will be updated to
* contain the witness program bytes.
* prog_len: Pointer to a size_t that will be updated to contain the
* length
* of bytes in prog.
* hrp: Pointer to the null-terminated human readable part that is
* expected (chain/network specific).
* addr: Pointer to the null-terminated address.
* Returns 1 if successful.
*/
int segwit_addr_decode(int *ver, uint8_t *prog, size_t *prog_len,
const char *hrp, const char *addr);
/** Encode a Bech32 string
*
* Out: output: Pointer to a buffer of size strlen(hrp) + data_len + 8 that
* will be updated to contain the null-terminated Bech32 string.
* In: hrp : Pointer to the null-terminated human readable part.
* data : Pointer to an array of 5-bit values.
* data_len: Length of the data array.
* Returns 1 if successful.
*/
int bech32_encode(char *output, const char *hrp, const uint8_t *data,
size_t data_len);
/** Decode a Bech32 string
*
* Out: hrp: Pointer to a buffer of size strlen(input) - 6. Will be
* updated to contain the null-terminated human readable part.
* data: Pointer to a buffer of size strlen(input) - 8 that will
* hold the encoded 5-bit data values.
* data_len: Pointer to a size_t that will be updated to be the number
* of entries in data.
* In: input: Pointer to a null-terminated Bech32 string.
* Returns 1 if succesful.
*/
int bech32_decode(char *hrp, uint8_t *data, size_t *data_len,
const char *input);
#endif

View File

@ -96,11 +96,6 @@
* @{
*/
#if 0
/* Private functions ---------------------------------------------------------*/
static void IntToUnicode (uint32_t value , uint8_t *pbuf , uint8_t len);
static void Get_SerialNum(void);
#endif
/**
* @}
@ -123,13 +118,13 @@ static void Get_SerialNum(void);
#define USBD_PID 0xf1d1
#else
#define USBD_VID 0x2C97
#if TARGET_ID == 0x31000002 // blue
#if defined(TARGET_BLUE) // blue
#define USBD_PID 0x0000
const uint8_t const USBD_PRODUCT_FS_STRING[] = {
4 * 2 + 2, USB_DESC_TYPE_STRING, 'B', 0, 'l', 0, 'u', 0, 'e', 0,
};
#elif TARGET_ID == 0x31100002 // nano s
#elif defined(TARGET_NANOS) // nano s
#define USBD_PID 0x0001
const uint8_t const USBD_PRODUCT_FS_STRING[] = {
6 * 2 + 2, USB_DESC_TYPE_STRING,
@ -140,7 +135,7 @@ const uint8_t const USBD_PRODUCT_FS_STRING[] = {
' ', 0,
'S', 0,
};
#elif TARGET_ID == 0x31200002 // aramis
#elif defined(TARGET_ARAMIS) // aramis
#define USBD_PID 0x0002
const uint8_t const USBD_PRODUCT_FS_STRING[] = {
6 * 2 + 2, USB_DESC_TYPE_STRING,
@ -237,8 +232,7 @@ the configuration*/
0x09, /*bLength: HID Descriptor size*/
HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/
0x11, /*bHIDUSTOM_HID: HID Class Spec release number*/
0x01,
0x00, /*bCountryCode: Hardware target country*/
0x01, 0x00, /*bCountryCode: Hardware target country*/
0x01, /*bNumDescriptors: Number of HID class descriptors to follow*/
0x22, /*bDescriptorType*/
sizeof(
@ -252,8 +246,7 @@ the configuration*/
HID_EPIN_ADDR, /*bEndpointAddress: Endpoint Address (IN)*/
0x03, /*bmAttributes: Interrupt endpoint*/
HID_EPIN_SIZE, /*wMaxPacketSize: 2 Byte max */
0x00,
0x01, /*bInterval: Polling Interval (20 ms)*/
0x00, 0x01, /*bInterval: Polling Interval (20 ms)*/
/* 34 */
0x07, /* bLength: Endpoint Descriptor size */
@ -271,7 +264,8 @@ __ALIGN_BEGIN const uint8_t const USBD_HID_Desc[] __ALIGN_END = {
0x09, /*bLength: HID Descriptor size*/
HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/
0x11, /*bHIDUSTOM_HID: HID Class Spec release number*/
0x01, 0x00, /*bCountryCode: Hardware target country*/
0x01,
0x00, /*bCountryCode: Hardware target country*/
0x01, /*bNumDescriptors: Number of HID class descriptors to follow*/
0x22, /*bDescriptorType*/
sizeof(
@ -502,13 +496,21 @@ static const USBD_DescriptorsTypeDef const HID_Desc = {
};
static const USBD_ClassTypeDef const USBD_HID = {
USBD_HID_Init, USBD_HID_DeInit, USBD_HID_Setup, NULL, /*EP0_TxSent*/
NULL, /*EP0_RxReady*/ /* STATUS STAGE IN */
NULL, /*DataIn*/
USBD_HID_DataOut_impl, /*DataOut*/
NULL, /*SOF */
NULL, NULL, USBD_HID_GetCfgDesc_impl, USBD_HID_GetCfgDesc_impl,
USBD_HID_GetCfgDesc_impl, USBD_HID_GetDeviceQualifierDesc_impl,
USBD_HID_Init,
USBD_HID_DeInit,
USBD_HID_Setup,
NULL, /*EP0_TxSent*/
NULL,
/*EP0_RxReady*/ /* STATUS STAGE IN */
NULL, /*DataIn*/
USBD_HID_DataOut_impl, /*DataOut*/
NULL, /*SOF */
NULL,
NULL,
USBD_HID_GetCfgDesc_impl,
USBD_HID_GetCfgDesc_impl,
USBD_HID_GetCfgDesc_impl,
USBD_HID_GetDeviceQualifierDesc_impl,
};
void USB_power_U2F(unsigned char enabled, unsigned char fido) {

View File

@ -1,11 +1,10 @@
#ifndef USBD_HID_IMPL_H
#define USBD_HID_IMPL_H
#define HID_EPIN_ADDR 0x82
#define HID_EPIN_SIZE 0x40
#define HID_EPIN_ADDR 0x82
#define HID_EPIN_SIZE 0x40
#define HID_EPOUT_ADDR 0x02
#define HID_EPOUT_SIZE 0x40
#define HID_EPOUT_ADDR 0x02
#define HID_EPOUT_SIZE 0x40
#endif // USBD_HID_IMPL_H