tychovrahe/T3W1/devkit1_with_ble_crypto2b
tychovrahe 1 year ago
parent 6fc8d67f39
commit 64675f36f4

2
core/.gitignore vendored

@ -11,3 +11,5 @@ mypy_report
/CMakeLists.txt
/cmake-build-debug/
tools/gdb_scripts/*.log
/embed/ble_bootloader/jlink.jdebug.user
/embed/ble_firmware/jlink.jdebug.user

@ -5,6 +5,8 @@ MAKE = make -j $(JOBS)
SCONS = scons -Q -j $(JOBS)
BUILD_DIR = build
BLE_BOOTLOADER_BUILD_DIR = $(BUILD_DIR)/ble_bootloader
BLE_FIRMWARE_BUILD_DIR = $(BUILD_DIR)/ble_firmware
BOARDLOADER_BUILD_DIR = $(BUILD_DIR)/boardloader
BOOTLOADER_BUILD_DIR = $(BUILD_DIR)/bootloader
BOOTLOADER_CI_BUILD_DIR = $(BUILD_DIR)/bootloader_ci
@ -172,6 +174,13 @@ build: build_boardloader build_bootloader build_firmware build_prodtest build_un
build_embed: build_boardloader build_bootloader build_firmware # build boardloader, bootloader, firmware
build_ble_bootloader: ## build ble_bootloader
$(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" CMAKELISTS="$(CMAKELISTS)" $(BLE_BOOTLOADER_BUILD_DIR)/ble_bootloader.bin
build_ble_firmware: ## build ble_firmware
$(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" CMAKELISTS="$(CMAKELISTS)" $(BLE_FIRMWARE_BUILD_DIR)/ble_firmware.bin
build_boardloader: ## build boardloader
$(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" \
CMAKELISTS="$(CMAKELISTS)" $(BOARDLOADER_BUILD_DIR)/boardloader.bin
@ -224,9 +233,16 @@ build_cross: ## build mpy-cross port
## clean commands:
clean: clean_boardloader clean_bootloader clean_bootloader_emu clean_bootloader_ci clean_prodtest clean_reflash clean_firmware clean_unix clean_cross ## clean all
clean: clean_ble_bootloader clean_ble_firmware clean_boardloader clean_bootloader clean_bootloader_emu clean_bootloader_ci clean_prodtest clean_reflash clean_firmware clean_unix clean_cross ## clean all
rm -f ".sconsign.dblite"
clean_ble_bootloader: ## clean ble_bootloader build
rm -rf $(BLE_BOOTLOADER_BUILD_DIR)
clean_ble_firmware: ## clean ble_bootloader build
rm -rf $(BLE_FIRMWARE_BUILD_DIR)
clean_boardloader: ## clean boardloader build
rm -rf $(BOARDLOADER_BUILD_DIR)
@ -258,6 +274,24 @@ clean_cross: ## clean mpy-cross build
flash: flash_boardloader flash_bootloader flash_firmware ## flash everything using OpenOCD
flash_ble: flash_ble_bootloader flash_softdevice flash_ble_firmware
flash_ble_bootloader:
@echo Flashing: $(BLE_BOOTLOADER_BUILD_DIR)/ble_bootloader.hex
nrfjprog -f nrf52 --program $(BLE_BOOTLOADER_BUILD_DIR)/ble_bootloader.hex --sectorerase
flash_ble_firmware:
@echo Flashing: $(BLE_FIRMWARE_BUILD_DIR)/ble_firmware_merged.hex
nrfjprog -f nrf52 --program $(BLE_FIRMWARE_BUILD_DIR)/ble_firmware_merged.hex --sectorerase
flash_ble_bl_settings:
@echo Flashing: $(BLE_BOOTLOADER_BUILD_DIR)/settings.hex
nrfjprog -f nrf52 --program $(BLE_BOOTLOADER_BUILD_DIR)/settings.hex --sectorerase
flash_softdevice:
@echo Flashing: s140_nrf52_7.2.0_softdevice.hex
nrfjprog -f nrf52 --program embed/sdk/nrf52/components/softdevice/s140/hex/s140_nrf52_7.2.0_softdevice.hex --sectorerase
flash_boardloader: $(BOARDLOADER_BUILD_DIR)/boardloader.bin ## flash boardloader using OpenOCD
$(OPENOCD) -c "init; reset halt; flash write_image erase $< $(BOARDLOADER_START); exit"
@ -282,6 +316,9 @@ flash_combine: $(PRODTEST_BUILD_DIR)/combined.bin ## flash combined using OpenOC
flash_erase: ## erase all sectors in flash bank 0
$(OPENOCD) -c "init; reset halt; flash info 0; flash erase_sector 0 0 last; flash erase_check 0; exit"
flash_erase_ble:
nrfjprog -f nrf52 --eraseall
flash_read_storage: ## read storage sectors from flash
$(OPENOCD) -c "init; flash read_bank 0 storage1.data 0x10000 65536; flash read_bank 0 storage2.data 0x110000 65536; exit"
@ -310,6 +347,10 @@ openocd: ## start openocd which connects to the device
openocd_reset: ## cause a system reset using OpenOCD
$(OPENOCD) -c "init; reset; exit"
# nrfjprog debug commands:
nrfjprog_reset:
nrfjprog -f nrf52 --reset
GDB = arm-none-eabi-gdb --nx -ex 'set remotetimeout unlimited' -ex 'set confirm off' -ex 'target remote 127.0.0.1:3333' -ex 'monitor reset halt'
gdb_boardloader: $(BOARDLOADER_BUILD_DIR)/boardloader.elf ## start remote gdb session to openocd with boardloader symbols

@ -0,0 +1,341 @@
# pylint: disable=E0602
import os
import tools
TREZOR_MODEL = ARGUMENTS.get('TREZOR_MODEL', 'T')
CMAKELISTS = int(ARGUMENTS.get('CMAKELISTS', 0))
if TREZOR_MODEL in ('1', ):
# skip boardloader build
env = Environment()
def build_ble_bootloader(target,source,env):
print(f'BLE BOOTLOADER: nothing to build for Model {TREZOR_MODEL}')
program_bin = env.Command(
target='ble_bootloader.bin',
source=None,
action=build_ble_bootloader
)
Return()
CCFLAGS_MOD = ''
CPPPATH_MOD = []
CPPDEFINES_MOD = []
SOURCE_MOD = []
CCFLAGS_MOD += '-Wno-sequence-point '
if int(ARGUMENTS.get('PRODUCTION', 0)) == 0:
# Build for monitor debug mode and RTT.
DEBUG = True
else:
DEBUG = False
# C flags common to all targets
CPPDEFINES_MOD += [
'CONFIG_GPIO_AS_PINRESET',
'FLOAT_ABI_HARD',
'NRF52833_XXAA',
('NRF_DFU_SETTINGS_VERSION','2'),
'MBR_PRESENT',
'SVC_INTERFACE_CALL_AS_NORMAL_FUNCTION',
('__HEAP_SIZE','0'),
('uECC_ENABLE_VLI_API', '0'),
('uECC_OPTIMIZATION_LEVEL', '3'),
('uECC_SQUARE_FUNC', '0'),
('uECC_SUPPORT_COMPRESSED_POINT', '0'),
('uECC_VLI_NATIVE_LITTLE_ENDIAN', '1'),
]
CPPPATH_MOD += [
]
CPPDEFINES_MOD += [
]
SOURCE_MOD += [
]
CPPPATH_MOD += [
'embed/sdk/nrf52/modules/nrfx/drivers/include',
'embed/sdk/nrf52/components/libraries/crypto/backend/micro_ecc',
'embed/sdk/nrf52/components/libraries/memobj',
'embed/sdk/nrf52/components/libraries/crc32',
'embed/sdk/nrf52/components/libraries/sha256',
'embed/sdk/nrf52/components/libraries/experimental_section_vars',
'embed/sdk/nrf52/components/libraries/mem_manager',
'embed/sdk/nrf52/components/libraries/fstorage',
'embed/sdk/nrf52/components/libraries/util',
'embed/sdk/nrf52/modules/nrfx',
'embed/sdk/nrf52/external/nrf_oberon/include',
'embed/sdk/nrf52/components/libraries/crypto/backend/oberon',
'embed/sdk/nrf52/components/libraries/crypto/backend/cifra',
'embed/sdk/nrf52/components/libraries/atomic',
'embed/sdk/nrf52/integration/nrfx',
'embed/sdk/nrf52/components/libraries/crypto/backend/cc310_bl',
'embed/sdk/nrf52/components/drivers_nrf/nrf_soc_nosd',
'embed/sdk/nrf52/components/libraries/log/src',
'embed/sdk/nrf52/components/libraries/bootloader/dfu',
'embed/sdk/nrf52/components/libraries/bootloader/serial_dfu',
'embed/sdk/nrf52/external/nrf_cc310_bl/include',
'embed/sdk/nrf52/external/segger_rtt',
'embed/sdk/nrf52/components/libraries/delay',
'embed/sdk/nrf52/integration/nrfx/legacy',
'embed/sdk/nrf52/modules/nrfx/hal',
'embed/sdk/nrf52/components/libraries/crypto/backend/nrf_hw',
'embed/sdk/nrf52/components/libraries/log',
'embed/sdk/nrf52/external/nrf_oberon',
'embed/sdk/nrf52/components/libraries/strerror',
'embed/sdk/nrf52/components/libraries/crypto/backend/mbedtls',
'embed/sdk/nrf52/components/libraries/crypto/backend/cc310',
'embed/sdk/nrf52/components/libraries/bootloader',
'embed/sdk/nrf52/components/softdevice/mbr/headers',
'embed/sdk/nrf52/components/libraries/crypto',
'embed/sdk/nrf52/components/libraries/crypto/backend/optiga',
'embed/sdk/nrf52/components/libraries/scheduler',
'embed/sdk/nrf52/components/libraries/slip',
'embed/sdk/nrf52/external/fprintf',
'embed/sdk/nrf52/components/toolchain/cmsis/include',
'embed/sdk/nrf52/components/libraries/balloc',
'embed/sdk/nrf52/components/libraries/stack_info',
'embed/sdk/nrf52/components/libraries/crypto/backend/nrf_sw',
'embed/sdk/nrf52/modules/nrfx/mdk',
'embed/sdk/nrf52/external/nrf_cc310/include',
'embed/sdk/nrf52/external/nano-pb',
'embed/sdk/nrf52/components/libraries/queue',
'embed/sdk/nrf52/components/libraries/mutex',
'embed/sdk/nrf52/components/libraries/ringbuf',
'embed/trezorhal/boards',
]
SOURCE_MOD += [
]
SOURCE_NRFHAL_AS = [
'embed/sdk/nrf52/modules/nrfx/mdk/gcc_startup_nrf52833.S',
]
SOURCE_NRFHAL = [
'embed/sdk/nrf52/components/libraries/log/src/nrf_log_frontend.c',
'embed/sdk/nrf52/components/libraries/log/src/nrf_log_str_formatter.c',
'embed/sdk/nrf52/modules/nrfx/mdk/system_nrf52833.c',
'embed/sdk/nrf52/components/libraries/util/app_error_weak.c',
'embed/sdk/nrf52/components/libraries/scheduler/app_scheduler.c',
'embed/sdk/nrf52/components/libraries/util/app_util_platform.c',
'embed/sdk/nrf52/components/libraries/crc32/crc32.c',
'embed/sdk/nrf52/components/libraries/sha256/sha256.c',
'embed/sdk/nrf52/components/libraries/mem_manager/mem_manager.c',
'embed/sdk/nrf52/components/libraries/util/nrf_assert.c',
'embed/sdk/nrf52/components/libraries/atomic/nrf_atomic.c',
'embed/sdk/nrf52/components/libraries/balloc/nrf_balloc.c',
'embed/sdk/nrf52/external/fprintf/nrf_fprintf.c',
'embed/sdk/nrf52/external/fprintf/nrf_fprintf_format.c',
'embed/sdk/nrf52/components/libraries/fstorage/nrf_fstorage.c',
'embed/sdk/nrf52/components/libraries/fstorage/nrf_fstorage_nvmc.c',
'embed/sdk/nrf52/components/libraries/memobj/nrf_memobj.c',
'embed/sdk/nrf52/components/libraries/queue/nrf_queue.c',
'embed/sdk/nrf52/components/libraries/ringbuf/nrf_ringbuf.c',
'embed/sdk/nrf52/components/libraries/strerror/nrf_strerror.c',
'embed/sdk/nrf52/components/libraries/slip/slip.c',
'embed/sdk/nrf52/integration/nrfx/legacy/nrf_drv_uart.c',
'embed/sdk/nrf52/components/drivers_nrf/nrf_soc_nosd/nrf_nvic.c',
'embed/sdk/nrf52/modules/nrfx/hal/nrf_nvmc.c',
'embed/sdk/nrf52/components/drivers_nrf/nrf_soc_nosd/nrf_soc.c',
'embed/sdk/nrf52/modules/nrfx/soc/nrfx_atomic.c',
'embed/sdk/nrf52/modules/nrfx/drivers/src/prs/nrfx_prs.c',
'embed/sdk/nrf52/modules/nrfx/drivers/src/nrfx_uart.c',
'embed/sdk/nrf52/modules/nrfx/drivers/src/nrfx_uarte.c',
'embed/sdk/nrf52/components/libraries/crypto/nrf_crypto_ecc.c',
'embed/sdk/nrf52/components/libraries/crypto/nrf_crypto_ecdsa.c',
'embed/sdk/nrf52/components/libraries/crypto/nrf_crypto_hash.c',
'embed/sdk/nrf52/components/libraries/crypto/nrf_crypto_init.c',
'embed/sdk/nrf52/components/libraries/crypto/nrf_crypto_shared.c',
'embed/sdk/nrf52/components/libraries/bootloader/nrf_bootloader_app_start.c',
'embed/sdk/nrf52/components/libraries/bootloader/nrf_bootloader_app_start_final.c',
'embed/sdk/nrf52/components/libraries/bootloader/nrf_bootloader_dfu_timers.c',
'embed/sdk/nrf52/components/libraries/bootloader/nrf_bootloader_fw_activation.c',
'embed/sdk/nrf52/components/libraries/bootloader/nrf_bootloader_info.c',
'embed/sdk/nrf52/components/libraries/bootloader/nrf_bootloader_wdt.c',
'embed/sdk/nrf52/external/nano-pb/pb_common.c',
'embed/sdk/nrf52/external/nano-pb/pb_decode.c',
'embed/sdk/nrf52/components/libraries/bootloader/dfu/dfu-cc.pb.c',
'embed/sdk/nrf52/components/libraries/bootloader/dfu/nrf_dfu.c',
'embed/sdk/nrf52/components/libraries/bootloader/dfu/nrf_dfu_flash.c',
'embed/sdk/nrf52/components/libraries/bootloader/dfu/nrf_dfu_handling_error.c',
'embed/sdk/nrf52/components/libraries/bootloader/dfu/nrf_dfu_mbr.c',
'embed/sdk/nrf52/components/libraries/bootloader/dfu/nrf_dfu_req_handler.c',
'embed/sdk/nrf52/components/libraries/bootloader/dfu/nrf_dfu_settings.c',
'embed/sdk/nrf52/components/libraries/bootloader/dfu/nrf_dfu_transport.c',
'embed/sdk/nrf52/components/libraries/bootloader/dfu/nrf_dfu_utils.c',
'embed/sdk/nrf52/components/libraries/bootloader/dfu/nrf_dfu_validation.c',
'embed/sdk/nrf52/components/libraries/bootloader/dfu/nrf_dfu_ver_validation.c',
'embed/sdk/nrf52/components/libraries/bootloader/serial_dfu/nrf_dfu_serial.c',
'embed/sdk/nrf52/components/libraries/crypto/backend/micro_ecc/micro_ecc_backend_ecc.c',
'embed/sdk/nrf52/components/libraries/crypto/backend/micro_ecc/micro_ecc_backend_ecdh.c',
'embed/sdk/nrf52/components/libraries/crypto/backend/micro_ecc/micro_ecc_backend_ecdsa.c',
'embed/sdk/nrf52/components/libraries/crypto/backend/nrf_sw/nrf_sw_backend_hash.c',
]
SOURCE_BLE_BOOTLOADER = [
'embed/ble_bootloader/main.c',
'embed/ble_bootloader/uecc/uECC.c',
'embed/ble_bootloader/dfu_public_key.c',
# originally embed/sdk/nrf52/components/libraries/bootloader/serial_dfu/nrf_dfu_serial_uart.c',
'embed/ble_bootloader/nrf_dfu_serial_uart.c',
'embed/ble_bootloader/nrf_bootloader.c',
]
if DEBUG:
CPPDEFINES_MOD += [
'DEBUG',
'DEBUG_NRF',
'NRF_DFU_DEBUG_VERSION',
'MMD'
]
SOURCE_BLE_BOOTLOADER += [
'embed/segger/SEGGER_MMD/JLINK_MONITOR.c',
'embed/segger/SEGGER_MMD/JLINK_MONITOR_ISR_SES.S'
]
SOURCE_NRFHAL += [
'embed/sdk/nrf52/components/libraries/log/src/nrf_log_backend_rtt.c',
'embed/sdk/nrf52/components/libraries/log/src/nrf_log_backend_serial.c',
'embed/sdk/nrf52/components/libraries/log/src/nrf_log_backend_uart.c',
'embed/sdk/nrf52/components/libraries/log/src/nrf_log_default_backends.c',
'embed/sdk/nrf52/external/segger_rtt/SEGGER_RTT.c',
'embed/sdk/nrf52/external/segger_rtt/SEGGER_RTT_Syscalls_GCC.c',
'embed/sdk/nrf52/external/segger_rtt/SEGGER_RTT_printf.c',
]
CPPPATH_MOD += [
'embed/segger/SEGGER_MMD'
]
env = Environment(ENV=os.environ, CFLAGS='%s -DPRODUCTION=%s' % (ARGUMENTS.get('CFLAGS', ''), ARGUMENTS.get('PRODUCTION', '0')))
env.Replace(
CP='cp',
AS='arm-none-eabi-as',
AR='arm-none-eabi-ar',
CC='arm-none-eabi-gcc',
LINK='arm-none-eabi-gcc',
SIZE='arm-none-eabi-size',
STRIP='arm-none-eabi-strip',
OBJCOPY='arm-none-eabi-objcopy',
PYTHON='python',
MAKECMAKELISTS='$PYTHON tools/make_cmakelists.py', )
env.Replace(
TREZOR_MODEL=TREZOR_MODEL, )
CPU_ASFLAGS = '-mthumb -mabi=aapcs -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16'
CPU_CCFLAGS = '-mthumb -mabi=aapcs -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 '
env.Replace(
COPT=env.get('ENV').get('OPTIMIZE', '-Og'),
CCFLAGS='$COPT '
'-g3 '
'-std=c99 -Wall -Werror -Wdouble-promotion -Wpointer-arith -Wno-missing-braces -Wno-unused-function '
'-fdata-sections -ffunction-sections '
'-fno-strict-aliasing '
'-fno-builtin '
'-fshort-enums '
+ CPU_CCFLAGS + CCFLAGS_MOD,
LINKFLAGS='-Lembed/sdk/nrf52/modules/nrfx/mdk -T embed/ble_bootloader/memory.ld -Wl,--gc-sections --specs=nano.specs -Wl,-Map=build/ble_bootloader/ble_bootloader.map -Wl,--warn-common -Wl,--print-memory-usage',
CPPPATH=[
'embed/ble_bootloader',
'embed/ble_bootloader/uecc',
'embed/sdk/nrf52',
] + CPPPATH_MOD,
CPPDEFINES=[
'BLE_BOOTLOADER',
'TREZOR_MODEL_'+TREZOR_MODEL,
] + CPPDEFINES_MOD,
ASFLAGS=CPU_ASFLAGS,
ASPPFLAGS='$CFLAGS $CCFLAGS', )
#
# Program objects
#
obj_program = []
obj_program += env.Object(source=SOURCE_BLE_BOOTLOADER)
obj_program += env.Object(source=SOURCE_NRFHAL_AS, COPT='-O0')
obj_program += env.Object(source=SOURCE_NRFHAL)
obj_program += env.Object(source=SOURCE_MOD)
env.Replace(
ALLSOURCES=SOURCE_NRFHAL_AS + SOURCE_MOD + SOURCE_BLE_BOOTLOADER + SOURCE_NRFHAL,
ALLDEFS=tools.get_defs_for_cmake(env['CPPDEFINES']))
cmake_gen = env.Command(
target='CMakeLists.txt',
source='',
action='$MAKECMAKELISTS --sources $ALLSOURCES --dirs $CPPPATH --defs $ALLDEFS',
)
LIB_FILES = [
'embed/sdk/nrf52/external/nrf_oberon/lib/cortex-m4/hard-float/liboberon_3.0.8.a',
'embed/sdk/nrf52/external/nrf_cc310_bl/lib/cortex-m4/hard-float/libnrf_cc310_bl_0.9.13.a',
]
program_elf = env.Command(
target='ble_bootloader.elf',
source=obj_program,
action=
'$LINK -o $TARGET $CCFLAGS $CFLAGS $LINKFLAGS $SOURCES ' + ' '.join(LIB_FILES) + ' -lc -lnosys -lm',
)
BINARY_NAME = f"build/ble_bootloader/ble_bootloader-{tools.get_model_identifier(TREZOR_MODEL)}"
BINARY_NAME += "-" + tools.get_version('embed/ble_bootloader/version.h')
BINARY_NAME += "-" + tools.get_git_revision_short_hash()
BINARY_NAME += "-dirty" if tools.get_git_modified() else ""
BINARY_NAME += ".bin"
if CMAKELISTS != 0:
env.Depends(program_elf, cmake_gen)
program_hex = env.Command(
target='ble_bootloader.hex',
source=program_elf,
action='$OBJCOPY -O ihex $SOURCE $TARGET',
)
program_bin = env.Command(
target='ble_bootloader.bin',
source=program_elf,
action=[
'$OBJCOPY -O binary $SOURCE $TARGET',
'$CP $TARGET ' + BINARY_NAME,
],
)
program_settings = env.Command(
target='settings.hex',
source=None,
action='$CP ./embed/ble_bootloader/settings.hex $TARGET',
)
env.Depends(program_bin, program_hex)
env.Depends(program_bin, program_settings)

@ -0,0 +1,495 @@
# pylint: disable=E0602
import os
import tools
TREZOR_MODEL = ARGUMENTS.get('TREZOR_MODEL', 'T')
CMAKELISTS = int(ARGUMENTS.get('CMAKELISTS', 0))
if TREZOR_MODEL in ('1', ):
# skip boardloader build
env = Environment()
def build_ble_firmware(target,source,env):
print(f'BLE FIRMWARE: nothing to build for Model {TREZOR_MODEL}')
program_bin = env.Command(
target='ble_firmware.bin',
source=None,
action=build_ble_firmware
)
Return()
CCFLAGS_MOD = ''
CPPPATH_MOD = []
CPPDEFINES_MOD = []
SOURCE_MOD = []
CCFLAGS_MOD += '-Wno-sequence-point '
if int(ARGUMENTS.get('PRODUCTION', 0)) == 0:
# Build for monitor debug mode.
MMD = True
else:
MMD = False
# C flags common to all targets
CPPDEFINES_MOD += [
'CONFIG_GPIO_AS_PINRESET',
'FLOAT_ABI_HARD',
'NRF52833_XXAA',
'SOFTDEVICE_PRESENT',
('NRF_SD_BLE_API_VERSION', '7'),
'APP_TIMER_V2',
'APP_TIMER_V2_RTC1_ENABLED',
'S140',
('__HEAP_SIZE','8192'),
('__STACK_SIZE','8192'),
('uECC_ENABLE_VLI_API', '0'),
('uECC_OPTIMIZATION_LEVEL', '3'),
('uECC_SQUARE_FUNC', '0'),
('uECC_SUPPORT_COMPRESSED_POINT', '0'),
('uECC_VLI_NATIVE_LITTLE_ENDIAN', '1'),
]
CPPPATH_MOD += [
]
CPPDEFINES_MOD += [
]
SOURCE_MOD += [
]
CPPPATH_MOD += [
'embed/sdk/nrf52/components/nfc/ndef/generic/message',
'embed/sdk/nrf52/components/nfc/t2t_lib',
'embed/sdk/nrf52/components/nfc/t4t_parser/hl_detection_procedure',
'embed/sdk/nrf52/components/ble/ble_services/ble_ancs_c',
'embed/sdk/nrf52/components/ble/ble_services/ble_ias_c',
'embed/sdk/nrf52/components/libraries/pwm',
'embed/sdk/nrf52/components/libraries/usbd/class/cdc/acm',
'embed/sdk/nrf52/components/libraries/usbd/class/hid/generic',
'embed/sdk/nrf52/components/libraries/usbd/class/msc',
'embed/sdk/nrf52/components/libraries/usbd/class/hid',
'embed/sdk/nrf52/modules/nrfx/hal',
'embed/sdk/nrf52/components/nfc/ndef/conn_hand_parser/le_oob_rec_parser',
'embed/sdk/nrf52/components/libraries/log',
'embed/sdk/nrf52/components/ble/ble_services/ble_gls',
'embed/sdk/nrf52/components/libraries/fstorage',
'embed/sdk/nrf52/components/nfc/ndef/text',
'embed/sdk/nrf52/components/libraries/mutex',
'embed/sdk/nrf52/components/libraries/gfx',
'embed/sdk/nrf52/components/libraries/bootloader/ble_dfu',
'embed/sdk/nrf52/components/nfc/ndef/connection_handover/common',
'embed/sdk/nrf52/components/libraries/fifo',
'embed/sdk/nrf52/components/nfc/ndef/generic/record',
'embed/sdk/nrf52/components/nfc/t4t_parser/cc_file',
'embed/sdk/nrf52/components/ble/ble_advertising',
'embed/sdk/nrf52/external/utf_converter',
'embed/sdk/nrf52/components/ble/ble_services/ble_bas_c',
'embed/sdk/nrf52/modules/nrfx/drivers/include',
'embed/sdk/nrf52/components/libraries/experimental_task_manager',
'embed/sdk/nrf52/components/ble/ble_services/ble_hrs_c',
'embed/sdk/nrf52/components/softdevice/s140/headers/nrf52',
'embed/sdk/nrf52/components/nfc/ndef/connection_handover/le_oob_rec',
'embed/sdk/nrf52/components/libraries/queue',
'embed/sdk/nrf52/components/libraries/pwr_mgmt',
'embed/sdk/nrf52/components/ble/ble_dtm',
'embed/sdk/nrf52/components/toolchain/cmsis/include',
'embed/sdk/nrf52/components/ble/ble_services/ble_rscs_c',
'embed/sdk/nrf52/components/ble/common',
'embed/sdk/nrf52/components/ble/ble_services/ble_lls',
'embed/sdk/nrf52/components/nfc/platform',
'embed/sdk/nrf52/components/nfc/ndef/connection_handover/ac_rec',
'embed/sdk/nrf52/components/ble/ble_services/ble_bas',
'embed/sdk/nrf52/components/libraries/mpu',
'embed/sdk/nrf52/components/libraries/experimental_section_vars',
'embed/sdk/nrf52/components/ble/ble_services/ble_ans_c',
'embed/sdk/nrf52/components/libraries/slip',
'embed/sdk/nrf52/components/libraries/delay',
'embed/sdk/nrf52/components/libraries/csense_drv',
'embed/sdk/nrf52/components/libraries/memobj',
'embed/sdk/nrf52/components/ble/ble_services/ble_nus_c',
'embed/sdk/nrf52/components/softdevice/common',
'embed/sdk/nrf52/components/ble/ble_services/ble_ias',
'embed/sdk/nrf52/components/libraries/usbd/class/hid/mouse',
'embed/sdk/nrf52/components/libraries/low_power_pwm',
'embed/sdk/nrf52/components/nfc/ndef/conn_hand_parser/ble_oob_advdata_parser',
'embed/sdk/nrf52/components/ble/ble_services/ble_dfu',
'embed/sdk/nrf52/external/fprintf',
'embed/sdk/nrf52/components/libraries/svc',
'embed/sdk/nrf52/components/libraries/atomic',
'embed/sdk/nrf52/components',
'embed/sdk/nrf52/components/libraries/scheduler',
'embed/sdk/nrf52/components/libraries/cli',
'embed/sdk/nrf52/components/ble/ble_services/ble_lbs',
'embed/sdk/nrf52/components/ble/ble_services/ble_hts',
'embed/sdk/nrf52/components/ble/ble_services/ble_cts_c',
'embed/sdk/nrf52/components/libraries/crc16',
'embed/sdk/nrf52/components/nfc/t4t_parser/apdu',
'embed/sdk/nrf52/components/libraries/util',
'embed/sdk/nrf52/components/libraries/usbd/class/cdc',
'embed/sdk/nrf52/components/libraries/csense',
'embed/sdk/nrf52/components/libraries/balloc',
'embed/sdk/nrf52/components/libraries/ecc',
'embed/sdk/nrf52/components/libraries/hardfault',
'embed/sdk/nrf52/components/ble/ble_services/ble_cscs',
'embed/sdk/nrf52/components/libraries/uart',
'embed/sdk/nrf52/components/libraries/hci',
'embed/sdk/nrf52/components/libraries/usbd/class/hid/kbd',
'embed/sdk/nrf52/components/libraries/timer',
'embed/sdk/nrf52/components/libraries/queue',
'embed/sdk/nrf52/components/softdevice/s140/headers',
'embed/sdk/nrf52/integration/nrfx',
'embed/sdk/nrf52/components/nfc/t4t_parser/tlv',
'embed/sdk/nrf52/components/libraries/sortlist',
'embed/sdk/nrf52/components/libraries/spi_mngr',
'embed/sdk/nrf52/components/libraries/led_softblink',
'embed/sdk/nrf52/components/nfc/ndef/conn_hand_parser',
'embed/sdk/nrf52/components/libraries/sdcard',
'embed/sdk/nrf52/components/nfc/ndef/parser/record',
'embed/sdk/nrf52/modules/nrfx/mdk',
'embed/sdk/nrf52/components/ble/ble_link_ctx_manager',
'embed/sdk/nrf52/components/ble/ble_services/ble_nus',
'embed/sdk/nrf52/components/libraries/twi_mngr',
'embed/sdk/nrf52/components/ble/ble_services/ble_hids',
'embed/sdk/nrf52/components/libraries/strerror',
'embed/sdk/nrf52/components/libraries/crc32',
'embed/sdk/nrf52/components/nfc/ndef/connection_handover/ble_oob_advdata',
'embed/sdk/nrf52/components/nfc/t2t_parser',
'embed/sdk/nrf52/components/nfc/ndef/connection_handover/ble_pair_msg',
'embed/sdk/nrf52/components/libraries/usbd/class/audio',
'embed/sdk/nrf52/components/nfc/t4t_lib',
'embed/sdk/nrf52/components/ble/peer_manager',
'embed/sdk/nrf52/components/libraries/mem_manager',
'embed/sdk/nrf52/components/libraries/ringbuf',
'embed/sdk/nrf52/components/ble/ble_services/ble_tps',
'embed/sdk/nrf52/components/nfc/ndef/parser/message',
'embed/sdk/nrf52/components/ble/ble_services/ble_dis',
'embed/sdk/nrf52/components/nfc/ndef/uri',
'embed/sdk/nrf52/components/ble/nrf_ble_gatt',
'embed/sdk/nrf52/components/ble/nrf_ble_qwr',
'embed/sdk/nrf52/components/libraries/gpiote',
'embed/sdk/nrf52/components/libraries/button',
'embed/sdk/nrf52/modules/nrfx',
'embed/sdk/nrf52/components/libraries/twi_sensor',
'embed/sdk/nrf52/integration/nrfx/legacy',
'embed/sdk/nrf52/components/libraries/usbd',
'embed/sdk/nrf52/components/nfc/ndef/connection_handover/ep_oob_rec',
'embed/sdk/nrf52/external/segger_rtt',
'embed/sdk/nrf52/components/libraries/atomic_fifo',
'embed/sdk/nrf52/components/ble/ble_services/ble_lbs_c',
'embed/sdk/nrf52/components/nfc/ndef/connection_handover/ble_pair_lib',
'embed/sdk/nrf52/components/libraries/crypto',
'embed/sdk/nrf52/components/libraries/crypto/backend/cc310',
'embed/sdk/nrf52/components/libraries/crypto/backend/cc310_bl',
'embed/sdk/nrf52/components/libraries/crypto/backend/micro_ecc',
'embed/sdk/nrf52/components/libraries/crypto/backend/mbedtls',
'embed/sdk/nrf52/components/libraries/crypto/backend/oberon',
'embed/sdk/nrf52/components/libraries/crypto/backend/optiga',
'embed/sdk/nrf52/components/libraries/crypto/backend/nrf_sw',
'embed/sdk/nrf52/components/libraries/crypto/backend/nrf_hw',
'embed/sdk/nrf52/components/libraries/crypto/backend/cifra',
'embed/sdk/nrf52/components/ble/ble_racp',
'embed/sdk/nrf52/components/libraries/fds',
'embed/sdk/nrf52/components/nfc/ndef/launchapp',
'embed/sdk/nrf52/components/libraries/atomic_flags',
'embed/sdk/nrf52/components/ble/ble_services/ble_hrs',
'embed/sdk/nrf52/components/ble/ble_services/ble_rscs',
'embed/sdk/nrf52/components/nfc/ndef/connection_handover/hs_rec',
'embed/sdk/nrf52/components/nfc/ndef/conn_hand_parser/ac_rec_parser',
'embed/sdk/nrf52/components/libraries/stack_guard',
'embed/sdk/nrf52/components/libraries/stack_info',
'embed/sdk/nrf52/components/libraries/log/src',
'embed/sdk/nrf52/external/mbedtls/include',
'embed',
'embed/trezorhal/boards',
]
SOURCE_MOD += [
]
SOURCE_NRFHAL_AS = [
'embed/sdk/nrf52/modules/nrfx/mdk/gcc_startup_nrf52833.S',
]
SOURCE_NRFHAL = [
'embed/sdk/nrf52/components/libraries/log/src/nrf_log_frontend.c',
'embed/sdk/nrf52/components/libraries/log/src/nrf_log_str_formatter.c',
'embed/sdk/nrf52/components/libraries/button/app_button.c',
'embed/sdk/nrf52/components/libraries/util/app_error.c',
'embed/sdk/nrf52/components/libraries/util/app_error_handler_gcc.c',
'embed/sdk/nrf52/components/libraries/util/app_error_weak.c',
'embed/sdk/nrf52/components/libraries/fifo/app_fifo.c',
'embed/sdk/nrf52/components/libraries/scheduler/app_scheduler.c',
'embed/sdk/nrf52/components/libraries/timer/app_timer2.c',
'embed/sdk/nrf52/components/libraries/uart/app_uart_fifo.c',
'embed/sdk/nrf52/components/libraries/util/app_util_platform.c',
'embed/sdk/nrf52/components/libraries/timer/drv_rtc.c',
'embed/sdk/nrf52/components/libraries/hardfault/hardfault_implementation.c',
'embed/sdk/nrf52/components/libraries/util/nrf_assert.c',
'embed/sdk/nrf52/components/libraries/atomic_fifo/nrf_atfifo.c',
'embed/sdk/nrf52/components/libraries/atomic_flags/nrf_atflags.c',
'embed/sdk/nrf52/components/libraries/atomic/nrf_atomic.c',
'embed/sdk/nrf52/components/libraries/balloc/nrf_balloc.c',
'embed/sdk/nrf52/external/fprintf/nrf_fprintf.c',
'embed/sdk/nrf52/external/fprintf/nrf_fprintf_format.c',
'embed/sdk/nrf52/components/libraries/memobj/nrf_memobj.c',
'embed/sdk/nrf52/components/libraries/pwr_mgmt/nrf_pwr_mgmt.c',
'embed/sdk/nrf52/components/libraries/ringbuf/nrf_ringbuf.c',
'embed/sdk/nrf52/components/libraries/experimental_section_vars/nrf_section_iter.c',
'embed/sdk/nrf52/components/libraries/sortlist/nrf_sortlist.c',
'embed/sdk/nrf52/components/libraries/strerror/nrf_strerror.c',
'embed/sdk/nrf52/components/libraries/uart/retarget.c',
'embed/sdk/nrf52/components/libraries/queue/nrf_queue.c',
'embed/sdk/nrf52/modules/nrfx/mdk/system_nrf52833.c',
'embed/sdk/nrf52/integration/nrfx/legacy/nrf_drv_clock.c',
'embed/sdk/nrf52/integration/nrfx/legacy/nrf_drv_uart.c',
'embed/sdk/nrf52/integration/nrfx/legacy/nrf_drv_spi.c',
'embed/sdk/nrf52/integration/nrfx/legacy/nrf_drv_rng.c',
'embed/sdk/nrf52/modules/nrfx/soc/nrfx_atomic.c',
'embed/sdk/nrf52/modules/nrfx/drivers/src/nrfx_clock.c',
'embed/sdk/nrf52/modules/nrfx/drivers/src/nrfx_gpiote.c',
'embed/sdk/nrf52/modules/nrfx/drivers/src/prs/nrfx_prs.c',
'embed/sdk/nrf52/modules/nrfx/drivers/src/nrfx_uart.c',
'embed/sdk/nrf52/modules/nrfx/drivers/src/nrfx_uarte.c',
'embed/sdk/nrf52/modules/nrfx/drivers/src/nrfx_rng.c',
'embed/sdk/nrf52/modules/nrfx/drivers/src/nrfx_spi.c',
'embed/sdk/nrf52/modules/nrfx/drivers/src/nrfx_spim.c',
'embed/sdk/nrf52/components/ble/common/ble_advdata.c',
'embed/sdk/nrf52/components/ble/ble_advertising/ble_advertising.c',
'embed/sdk/nrf52/components/ble/common/ble_conn_params.c',
'embed/sdk/nrf52/components/ble/common/ble_conn_state.c',
'embed/sdk/nrf52/components/ble/ble_link_ctx_manager/ble_link_ctx_manager.c',
'embed/sdk/nrf52/components/ble/common/ble_srv_common.c',
'embed/sdk/nrf52/components/ble/nrf_ble_gatt/nrf_ble_gatt.c',
'embed/sdk/nrf52/components/ble/nrf_ble_qwr/nrf_ble_qwr.c',
'embed/sdk/nrf52/external/utf_converter/utf.c',
'embed/sdk/nrf52/components/softdevice/common/nrf_sdh.c',
'embed/sdk/nrf52/components/softdevice/common/nrf_sdh_ble.c',
'embed/sdk/nrf52/components/softdevice/common/nrf_sdh_soc.c',
'embed/sdk/nrf52/components/ble/peer_manager/gatt_cache_manager.c',
'embed/sdk/nrf52/components/ble/peer_manager/gatts_cache_manager.c',
'embed/sdk/nrf52/components/ble/peer_manager/id_manager.c',
'embed/sdk/nrf52/components/ble/peer_manager/peer_data_storage.c',
'embed/sdk/nrf52/components/ble/peer_manager/peer_database.c',
'embed/sdk/nrf52/components/ble/peer_manager/peer_id.c',
'embed/sdk/nrf52/components/ble/peer_manager/peer_manager.c',
'embed/sdk/nrf52/components/ble/peer_manager/peer_manager_handler.c',
'embed/sdk/nrf52/components/ble/peer_manager/pm_buffer.c',
'embed/sdk/nrf52/components/ble/peer_manager/nrf_ble_lesc.c',
'embed/sdk/nrf52/components/libraries/fds/fds.c',
'embed/sdk/nrf52/components/ble/peer_manager/security_manager.c',
'embed/sdk/nrf52/components/ble/peer_manager/security_dispatcher.c',
'embed/sdk/nrf52/components/libraries/fstorage/nrf_fstorage.c',
'embed/sdk/nrf52/components/libraries/fstorage/nrf_fstorage_sd.c',
'embed/sdk/nrf52/components/ble/ble_services/ble_dis/ble_dis.c',
'embed/sdk/nrf52/components/libraries/crypto/backend/micro_ecc/micro_ecc_backend_ecc.c',
'embed/sdk/nrf52/components/libraries/crypto/backend/micro_ecc/micro_ecc_backend_ecdh.c',
'embed/sdk/nrf52/components/libraries/crypto/backend/micro_ecc/micro_ecc_backend_ecdsa.c',
'embed/sdk/nrf52/components/libraries/crypto/backend/nrf_hw/nrf_hw_backend_rng_mbedtls.c',
'embed/sdk/nrf52/components/libraries/crypto/nrf_crypto_ecc.c',
'embed/sdk/nrf52/components/libraries/crypto/nrf_crypto_ecdsa.c',
'embed/sdk/nrf52/components/libraries/crypto/nrf_crypto_ecdh.c',
'embed/sdk/nrf52/components/libraries/crypto/nrf_crypto_hash.c',
'embed/sdk/nrf52/components/libraries/crypto/nrf_crypto_init.c',
'embed/sdk/nrf52/components/libraries/crypto/nrf_crypto_shared.c',
'embed/sdk/nrf52/components/libraries/crypto/nrf_crypto_rng.c',
'embed/sdk/nrf52/external/mbedtls/library/ctr_drbg.c',
'embed/sdk/nrf52/external/mbedtls/library/aes.c',
'embed/sdk/nrf52/external/mbedtls/library/platform.c',
'embed/sdk/nrf52/external/mbedtls/library/platform_util.c',
]
SOURCE_NANOPB = [
'vendor/nanopb/pb_common.c',
'vendor/nanopb/pb_decode.c',
'vendor/nanopb/pb_encode.c',
]
SOURCE_BLE_FIRMWARE = [
'embed/ble_firmware/main.c',
'embed/ble_firmware/ble_nus.c',
'embed/ble_firmware/int_comm.c',
'embed/ble_firmware/dis.c',
'embed/ble_firmware/pm.c',
'embed/ble_firmware/power.c',
'embed/ble_firmware/advertising.c',
'embed/ble_firmware/connection.c',
'embed/bootloader/protob/messages.pb.c',
'embed/lib/protob_helpers.c',
'embed/ble_bootloader/uecc/uECC.c',
]
if MMD:
CPPDEFINES_MOD += [
'DEBUG',
'DEBUG_NRF',
'MMD'
]
SOURCE_BLE_FIRMWARE += [
'embed/segger/SEGGER_MMD/JLINK_MONITOR.c',
'embed/segger/SEGGER_MMD/JLINK_MONITOR_ISR_SES.S'
]
SOURCE_NRFHAL += [
'embed/sdk/nrf52/components/libraries/log/src/nrf_log_backend_rtt.c',
'embed/sdk/nrf52/components/libraries/log/src/nrf_log_backend_serial.c',
'embed/sdk/nrf52/components/libraries/log/src/nrf_log_backend_uart.c',
'embed/sdk/nrf52/components/libraries/log/src/nrf_log_default_backends.c',
'embed/sdk/nrf52/external/segger_rtt/SEGGER_RTT.c',
'embed/sdk/nrf52/external/segger_rtt/SEGGER_RTT_Syscalls_GCC.c',
'embed/sdk/nrf52/external/segger_rtt/SEGGER_RTT_printf.c',
]
CPPPATH_MOD += [
'embed/segger/SEGGER_MMD'
]
env = Environment(ENV=os.environ, CFLAGS='%s -DPRODUCTION=%s' % (ARGUMENTS.get('CFLAGS', ''), ARGUMENTS.get('PRODUCTION', '0')))
env.Replace(
CP='cp',
AS='arm-none-eabi-as',
AR='arm-none-eabi-ar',
CC='arm-none-eabi-gcc',
LINK='arm-none-eabi-gcc',
SIZE='arm-none-eabi-size',
STRIP='arm-none-eabi-strip',
OBJCOPY='arm-none-eabi-objcopy',
PYTHON='python',
MAKECMAKELISTS='$PYTHON tools/make_cmakelists.py', )
env.Replace(
TREZOR_MODEL=TREZOR_MODEL, )
CPU_ASFLAGS = '-mthumb -mabi=aapcs -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16'
CPU_CCFLAGS = '-mthumb -mabi=aapcs -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 '
env.Replace(
COPT=env.get('ENV').get('OPTIMIZE', '-Og'),
CCFLAGS='$COPT '
'-g3 '
'-std=c99 -Wall -Werror -Wdouble-promotion -Wpointer-arith -Wno-missing-braces -Wno-unused-function '
'-fdata-sections -ffunction-sections '
'-fno-strict-aliasing '
'-fno-builtin '
'-fshort-enums '
+ CPU_CCFLAGS + CCFLAGS_MOD,
LINKFLAGS='-Lembed/sdk/nrf52/modules/nrfx/mdk -T embed/ble_firmware/memory.ld -Wl,--gc-sections --specs=nano.specs -Wl,-Map=build/ble_firmware/ble_firmware.map -Wl,--warn-common -Wl,--print-memory-usage',
CPPPATH=[
'embed/ble_firmware',
'embed/bootloader/protob',
'embed/sdk/nrf52',
'embed/lib',
'vendor/nanopb',
'embed/ble_bootloader/uecc',
] + CPPPATH_MOD,
CPPDEFINES=[
'BLE_FIRMWARE',
'TREZOR_MODEL_'+TREZOR_MODEL,
] + CPPDEFINES_MOD,
ASFLAGS=CPU_ASFLAGS,
ASPPFLAGS='$CFLAGS $CCFLAGS', )
#
# Program objects
#
obj_program = []
obj_program += env.Object(source=SOURCE_BLE_FIRMWARE)
obj_program += env.Object(source=SOURCE_NRFHAL_AS, COPT='-O0')
obj_program += env.Object(source=SOURCE_NRFHAL)
obj_program += env.Object(source=SOURCE_NANOPB)
obj_program += env.Object(source=SOURCE_MOD)
env.Replace(
ALLSOURCES=SOURCE_NRFHAL_AS + SOURCE_MOD + SOURCE_BLE_FIRMWARE + SOURCE_NRFHAL,
ALLDEFS=tools.get_defs_for_cmake(env['CPPDEFINES']))
cmake_gen = env.Command(
target='CMakeLists.txt',
source='',
action='$MAKECMAKELISTS --sources $ALLSOURCES --dirs $CPPPATH --defs $ALLDEFS',
)
LIB_FILES = [
]
program_elf = env.Command(
target='ble_firmware.elf',
source=obj_program,
action=
'$LINK -o $TARGET $CCFLAGS $CFLAGS $LINKFLAGS $SOURCES ' + ' '.join(LIB_FILES) + ' -lc -lnosys -lm',
)
BINARY_NAME = f"build/ble_firmware/ble_firmware-{tools.get_model_identifier(TREZOR_MODEL)}"
BINARY_NAME += "-" + tools.get_version('embed/ble_firmware/version.h')
BINARY_NAME += "-" + tools.get_git_revision_short_hash()
BINARY_NAME += "-dirty" if tools.get_git_modified() else ""
BINARY_NAME += ".bin"
if CMAKELISTS != 0:
env.Depends(program_elf, cmake_gen)
program_hex = env.Command(
target='ble_firmware.hex',
source=program_elf,
action='$OBJCOPY -O ihex $SOURCE $TARGET',
)
program_pkg = env.Command(
target='ble_firmware.zip',
source=program_hex,
action=[
f'nrfutil pkg generate --hw-version 52 --sd-req=0x100 --application $SOURCE --app-boot-validation VALIDATE_ECDSA_P256_SHA256 --key-file ./embed/ble_bootloader/priv.pem $TARGET --application-version-string {tools.get_version("embed/ble_firmware/version.h")}'
],
)
settings = env.Command(
target='settings.hex',
source=program_hex,
action=f'nrfutil settings generate --family NRF52 --application $SOURCE --app-boot-validation VALIDATE_ECDSA_P256_SHA256 --application-version-string {tools.get_version("embed/ble_firmware/version.h")} --bootloader-version {tools.get_version_int("embed/ble_bootloader/version.h")} --bl-settings-version 2 --sd-boot-validation VALIDATE_ECDSA_P256_SHA256 --softdevice ./embed/sdk/nrf52/components/softdevice/s140/hex/s140_nrf52_7.2.0_softdevice.hex --key-file ./embed/ble_bootloader/priv.pem $TARGET',
)
program_merge = env.Command(
target='ble_firmware_merged.hex',
source=[program_hex, settings],
action='mergehex -m $SOURCES -o $TARGET',
)
program_bin = env.Command(
target='ble_firmware.bin',
source=program_elf,
action=[
'$OBJCOPY -O binary $SOURCE $TARGET',
'$CP $TARGET ' + BINARY_NAME,
],
)
env.Depends(program_bin, program_hex)
env.Depends(program_pkg, program_hex)
env.Depends(settings, program_hex)
env.Depends(program_bin, program_pkg)
env.Depends(program_merge, settings)
env.Depends(program_merge, program_hex)
env.Depends(program_bin, program_merge)

@ -1,5 +1,7 @@
# pylint: disable=E0602
SConscript('SConscript.ble_bootloader', variant_dir='build/ble_bootloader', duplicate=False)
SConscript('SConscript.ble_firmware', variant_dir='build/ble_firmware', duplicate=False)
SConscript('SConscript.boardloader', variant_dir='build/boardloader', duplicate=False)
SConscript('SConscript.bootloader', variant_dir='build/bootloader', duplicate=False)
SConscript('SConscript.bootloader_ci', variant_dir='build/bootloader_ci', duplicate=False)

@ -0,0 +1,16 @@
/* This file was automatically generated by nrfutil on 2023-01-23 (YY-MM-DD) at
* 16:58:55 */
#include "compiler_abstraction.h"
#include "stdint.h"
/** @brief Public key used to verify DFU images */
__ALIGN(4)
const uint8_t pk[64] = {
0x7e, 0x2f, 0x54, 0x41, 0xb7, 0x3f, 0x0c, 0xc8, 0xa8, 0x8f, 0x29,
0x1a, 0x91, 0x3c, 0x9f, 0x70, 0x7e, 0xc6, 0x6f, 0x69, 0x51, 0x14,
0xa6, 0x04, 0xeb, 0x0b, 0x23, 0x61, 0xf0, 0x22, 0xa4, 0xf4, 0xad,
0x73, 0x9b, 0xfa, 0x48, 0x2e, 0x1a, 0x90, 0xf6, 0x59, 0x28, 0x4c,
0x73, 0x49, 0x64, 0xc5, 0x18, 0xd3, 0xb3, 0xb2, 0x1a, 0x60, 0xf0,
0x79, 0xe8, 0x2c, 0x0a, 0x7c, 0x04, 0x84, 0xcd, 0xd6};

@ -0,0 +1,332 @@
/*********************************************************************
* (c) SEGGER Microcontroller GmbH *
* The Embedded Experts *
* www.segger.com *
**********************************************************************
File : /home/mbruna/CLionProjects/trezor-model_r/core/embed/ble_bootloader/jlink.jdebug
Created : 6 Feb 2023 15:54
Ozone Version : V3.28c
*/
/*********************************************************************
*
* OnProjectLoad
*
* Function description
* Project load routine. Required.
*
**********************************************************************
*/
void OnProjectLoad (void) {
//
// Dialog-generated settings
//
Project.AddPathSubstitute (".", "$(ProjectDir)");
Project.AddPathSubstitute (".", "$(ProjectDir)");
Project.SetDevice ("Cortex-M4");
Project.SetHostIF ("USB", "");
Project.SetTargetIF ("SWD");
Project.SetTIFSpeed ("20 MHz");
Project.AddSvdFile ("$(InstallDir)/Config/CPU/Cortex-M4F.svd");
//
// User settings
//
File.Open ("../../build/ble_bootloader/ble_bootloader.elf");
}
/*********************************************************************
*
* OnStartupComplete
*
* Function description
* Called when program execution has reached/passed
* the startup completion point. Optional.
*
**********************************************************************
*/
//void OnStartupComplete (void) {
//}
/*********************************************************************
*
* TargetReset
*
* Function description
* Replaces the default target device reset routine. Optional.
*
* Notes
* This example demonstrates the usage when
* debugging an application in RAM on a Cortex-M target device.
*
**********************************************************************
*/
//void TargetReset (void) {
//
// unsigned int SP;
// unsigned int PC;
// unsigned int VectorTableAddr;
//
// VectorTableAddr = Elf.GetBaseAddr();
// //
// // Set up initial stack pointer
// //
// if (VectorTableAddr != 0xFFFFFFFF) {
// SP = Target.ReadU32(VectorTableAddr);
// Target.SetReg("SP", SP);
// }
// //
// // Set up entry point PC
// //
// PC = Elf.GetEntryPointPC();
//
// if (PC != 0xFFFFFFFF) {
// Target.SetReg("PC", PC);
// } else if (VectorTableAddr != 0xFFFFFFFF) {
// PC = Target.ReadU32(VectorTableAddr + 4);
// Target.SetReg("PC", PC);
// } else {
// Util.Error("Project file error: failed to set entry point PC", 1);
// }
//}
/*********************************************************************
*
* BeforeTargetReset
*
* Function description
* Event handler routine. Optional.
*
**********************************************************************
*/
//void BeforeTargetReset (void) {
//}
/*********************************************************************
*
* AfterTargetReset
*
* Function description
* Event handler routine. Optional.
* The default implementation initializes SP and PC to reset values.
**
**********************************************************************
*/
void AfterTargetReset (void) {
_SetupTarget();
}
/*********************************************************************
*
* DebugStart
*
* Function description
* Replaces the default debug session startup routine. Optional.
*
**********************************************************************
*/
//void DebugStart (void) {
//}
/*********************************************************************
*
* TargetConnect
*
* Function description
* Replaces the default target IF connection routine. Optional.
*
**********************************************************************
*/
//void TargetConnect (void) {
//}
/*********************************************************************
*
* BeforeTargetConnect
*
* Function description
* Event handler routine. Optional.
*
**********************************************************************
*/
void BeforeTargetConnect (void) {
Project.SetJLinkScript("./MMDScript.JLinkScript");
}
/*********************************************************************
*
* AfterTargetConnect
*
* Function description
* Event handler routine. Optional.
*
**********************************************************************
*/
//void AfterTargetConnect (void) {
//}
/*********************************************************************
*
* TargetDownload
*
* Function description
* Replaces the default program download routine. Optional.
*
**********************************************************************
*/
//void TargetDownload (void) {
//}
/*********************************************************************
*
* BeforeTargetDownload
*
* Function description
* Event handler routine. Optional.
*
**********************************************************************
*/
//void BeforeTargetDownload (void) {
//}
/*********************************************************************
*
* AfterTargetDownload
*
* Function description
* Event handler routine. Optional.
* The default implementation initializes SP and PC to reset values.
*
**********************************************************************
*/
void AfterTargetDownload (void) {
_SetupTarget();
}
/*********************************************************************
*
* BeforeTargetDisconnect
*
* Function description
* Event handler routine. Optional.
*
**********************************************************************
*/
//void BeforeTargetDisconnect (void) {
//}
/*********************************************************************
*
* AfterTargetDisconnect
*
* Function description
* Event handler routine. Optional.
*
**********************************************************************
*/
//void AfterTargetDisconnect (void) {
//}
/*********************************************************************
*
* AfterTargetHalt
*
* Function description
* Event handler routine. Optional.
*
**********************************************************************
*/
//void AfterTargetHalt (void) {
//}
/*********************************************************************
*
* BeforeTargetResume
*
* Function description
* Event handler routine. Optional.
*
**********************************************************************
*/
//void BeforeTargetResume (void) {
//}
/*********************************************************************
*
* OnSnapshotLoad
*
* Function description
* Called upon loading a snapshot. Optional.
*
* Additional information
* This function is used to restore the target state in cases
* where values cannot simply be written to the target.
* Typical use: GPIO clock needs to be enabled, before
* GPIO is configured.
*
**********************************************************************
*/
//void OnSnapshotLoad (void) {
//}
/*********************************************************************
*
* OnSnapshotSave
*
* Function description
* Called upon saving a snapshot. Optional.
*
* Additional information
* This function is usually used to save values of the target
* state which can either not be trivially read,
* or need to be restored in a specific way or order.
* Typically use: Memory Mapped Registers,
* such as PLL and GPIO configuration.
*
**********************************************************************
*/
//void OnSnapshotSave (void) {
//}
/*********************************************************************
*
* OnError
*
* Function description
* Called when an error ocurred. Optional.
*
**********************************************************************
*/
//void OnError (void) {
//}
/*********************************************************************
*
* AfterProjectLoad
*
* Function description
* After Project load routine. Optional.
*
**********************************************************************
*/
//void AfterProjectLoad (void) {
//}
/*********************************************************************
*
* _SetupTarget
*
* Function description
* Setup the target.
* Called by AfterTargetReset() and AfterTargetDownload().
*
* Auto-generated function. May be overridden by Ozone.
*
**********************************************************************
*/
void _SetupTarget(void) {
//
// this function is intentionally empty because both inital PC and
// initial SP were chosen not to be set
//
}

@ -0,0 +1,169 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be
* reverse engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
/** @file
*
* @defgroup bootloader_secure_ble main.c
* @{
* @ingroup dfu_bootloader_api
* @brief Bootloader project main file for secure DFU.
*
*/
#include <stdint.h>
#include "app_error.h"
#include "app_error_weak.h"
#include "nrf_bootloader.h"
#include "nrf_bootloader_app_start.h"
#include "nrf_bootloader_dfu_timers.h"
#include "nrf_bootloader_info.h"
#include "nrf_delay.h"
#include "nrf_dfu.h"
#include "nrf_gpio.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "nrf_mbr.h"
#include "trezor_t3w1_d1_NRF.h"
static void on_error(void) {
NRF_LOG_FINAL_FLUSH();
#if NRF_MODULE_ENABLED(NRF_LOG_BACKEND_RTT)
// To allow the buffer to be flushed by the host.
nrf_delay_ms(100);
#endif
#ifdef NRF_DFU_DEBUG_VERSION
NRF_BREAKPOINT_COND;
#endif
NVIC_SystemReset();
}
void app_error_handler(uint32_t error_code, uint32_t line_num,
const uint8_t* p_file_name) {
NRF_LOG_ERROR("%s:%d, %d", p_file_name, line_num, error_code);
on_error();
}
void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info) {
NRF_LOG_ERROR("Received a fault! id: 0x%08x, pc: 0x%08x, info: 0x%08x", id,
pc, info);
on_error();
}
void app_error_handler_bare(uint32_t error_code) {
NRF_LOG_ERROR("Received an error: 0x%08x!", error_code);
on_error();
}
/**
* @brief Function notifies certain events in DFU process.
*/
static void dfu_observer(nrf_dfu_evt_type_t evt_type) {
switch (evt_type) {
case NRF_DFU_EVT_DFU_FAILED:
case NRF_DFU_EVT_DFU_ABORTED:
case NRF_DFU_EVT_DFU_INITIALIZED:
// bsp_board_init(BSP_INIT_LEDS);
// bsp_board_led_on(BSP_BOARD_LED_0);
// bsp_board_led_on(BSP_BOARD_LED_1);
// bsp_board_led_off(BSP_BOARD_LED_2);
break;
case NRF_DFU_EVT_TRANSPORT_ACTIVATED:
// bsp_board_led_off(BSP_BOARD_LED_1);
// bsp_board_led_on(BSP_BOARD_LED_2);
break;
case NRF_DFU_EVT_DFU_STARTED:
break;
default:
break;
}
}
uint32_t nrf_dfu_init_user(void) {
// signalize DFU mode
nrf_gpio_pin_set(GPIO_1_PIN);
return NRF_SUCCESS;
}
/**@brief Function for application main entry. */
int main(void) {
NRF_APPROTECT->DISABLE = APPROTECT_DISABLE_DISABLE_SwDisable;
uint32_t ret_val;
// Apply priority for monitor mode interrupt
NVIC_SetPriority(DebugMonitor_IRQn, _PRIO_SD_LOW);
// Must happen before flash protection is applied, since it edits a protected
// page.
nrf_bootloader_mbr_addrs_populate();
// Protect MBR and bootloader code from being overwritten.
ret_val = nrf_bootloader_flash_protect(0, MBR_SIZE);
APP_ERROR_CHECK(ret_val);
ret_val =
nrf_bootloader_flash_protect(BOOTLOADER_START_ADDR, BOOTLOADER_SIZE);
APP_ERROR_CHECK(ret_val);
nrf_gpio_cfg_output(GPIO_1_PIN);
nrf_gpio_cfg_output(GPIO_2_PIN);
nrf_gpio_pin_clear(GPIO_1_PIN);
nrf_gpio_pin_clear(GPIO_2_PIN);
(void)NRF_LOG_INIT(nrf_bootloader_dfu_timer_counter_get);
NRF_LOG_DEFAULT_BACKENDS_INIT();
NRF_LOG_INFO("Inside main");
ret_val = nrf_bootloader_init(dfu_observer);
APP_ERROR_CHECK(ret_val);
NRF_LOG_FLUSH();
NRF_LOG_ERROR("After main, should never be reached.");
NRF_LOG_FLUSH();
APP_ERROR_CHECK_BOOL(false);
}
/**
* @}
*/

@ -0,0 +1,156 @@
/* Linker script to configure memory regions. */
SEARCH_DIR(.)
GROUP(-lgcc -lc -lnosys)
MEMORY
{
FLASH (rx) : ORIGIN = 0x70000, LENGTH = 0xe000
RAM (rwx) : ORIGIN = 0x20002ae8, LENGTH = 0x1d518
uicr_bootloader_start_address (r) : ORIGIN = 0x10001014, LENGTH = 0x4
bootloader_settings_page (r) : ORIGIN = 0x0007F000, LENGTH = 0x1000
uicr_mbr_params_page (r) : ORIGIN = 0x10001018, LENGTH = 0x4
mbr_params_page (r) : ORIGIN = 0x0007E000, LENGTH = 0x1000
}
SECTIONS
{
. = ALIGN(4);
.uicr_bootloader_start_address :
{
PROVIDE(__start_uicr_bootloader_start_address = .);
KEEP(*(SORT(.uicr_bootloader_start_address*)))
PROVIDE(__stop_uicr_bootloader_start_address = .);
} > uicr_bootloader_start_address
. = ALIGN(4);
.bootloader_settings_page(NOLOAD) :
{
PROVIDE(__start_bootloader_settings_page = .);
KEEP(*(SORT(.bootloader_settings_page*)))
PROVIDE(__stop_bootloader_settings_page = .);
} > bootloader_settings_page
. = ALIGN(4);
.uicr_mbr_params_page :
{
PROVIDE(__start_uicr_mbr_params_page = .);
KEEP(*(SORT(.uicr_mbr_params_page*)))
PROVIDE(__stop_uicr_mbr_params_page = .);
} > uicr_mbr_params_page
. = ALIGN(4);
.mbr_params_page(NOLOAD) :
{
PROVIDE(__start_mbr_params_page = .);
KEEP(*(SORT(.mbr_params_page*)))
PROVIDE(__stop_mbr_params_page = .);
} > mbr_params_page
}
SECTIONS
{
. = ALIGN(4);
.mem_section_dummy_ram :
{
}
.log_dynamic_data :
{
PROVIDE(__start_log_dynamic_data = .);
KEEP(*(SORT(.log_dynamic_data*)))
PROVIDE(__stop_log_dynamic_data = .);
} > RAM
.log_filter_data :
{
PROVIDE(__start_log_filter_data = .);
KEEP(*(SORT(.log_filter_data*)))
PROVIDE(__stop_log_filter_data = .);
} > RAM
.fs_data :
{
PROVIDE(__start_fs_data = .);
KEEP(*(.fs_data))
PROVIDE(__stop_fs_data = .);
} > RAM
} INSERT AFTER .data;
SECTIONS
{
.mem_section_dummy_rom :
{
}
.crypto_data :
{
PROVIDE(__start_crypto_data = .);
KEEP(*(SORT(.crypto_data*)))
PROVIDE(__stop_crypto_data = .);
} > FLASH
.nrf_queue :
{
PROVIDE(__start_nrf_queue = .);
KEEP(*(.nrf_queue))
PROVIDE(__stop_nrf_queue = .);
} > FLASH
.dfu_trans :
{
PROVIDE(__start_dfu_trans = .);
KEEP(*(SORT(.dfu_trans*)))
PROVIDE(__stop_dfu_trans = .);
} > FLASH
.svc_data :
{
PROVIDE(__start_svc_data = .);
KEEP(*(.svc_data))
PROVIDE(__stop_svc_data = .);
} > FLASH
.log_const_data :
{
PROVIDE(__start_log_const_data = .);
KEEP(*(SORT(.log_const_data*)))
PROVIDE(__stop_log_const_data = .);
} > FLASH
.nrf_balloc :
{
PROVIDE(__start_nrf_balloc = .);
KEEP(*(.nrf_balloc))
PROVIDE(__stop_nrf_balloc = .);
} > FLASH
.sdh_ble_observers :
{
PROVIDE(__start_sdh_ble_observers = .);
KEEP(*(SORT(.sdh_ble_observers*)))
PROVIDE(__stop_sdh_ble_observers = .);
} > FLASH
.log_backends :
{
PROVIDE(__start_log_backends = .);
KEEP(*(SORT(.log_backends*)))
PROVIDE(__stop_log_backends = .);
} > FLASH
.sdh_req_observers :
{
PROVIDE(__start_sdh_req_observers = .);
KEEP(*(SORT(.sdh_req_observers*)))
PROVIDE(__stop_sdh_req_observers = .);
} > FLASH
.sdh_state_observers :
{
PROVIDE(__start_sdh_state_observers = .);
KEEP(*(SORT(.sdh_state_observers*)))
PROVIDE(__stop_sdh_state_observers = .);
} > FLASH
.sdh_stack_observers :
{
PROVIDE(__start_sdh_stack_observers = .);
KEEP(*(SORT(.sdh_stack_observers*)))
PROVIDE(__stop_sdh_stack_observers = .);
} > FLASH
.sdh_soc_observers :
{
PROVIDE(__start_sdh_soc_observers = .);
KEEP(*(SORT(.sdh_soc_observers*)))
PROVIDE(__stop_sdh_soc_observers = .);
} > FLASH
} INSERT AFTER .text
INCLUDE "nrf_common.ld"

@ -0,0 +1,475 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be
* reverse engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "nrf_bootloader.h"
#include "app_scheduler.h"
#include "compiler_abstraction.h"
#include "nordic_common.h"
#include "nrf.h"
#include "nrf_bootloader_app_start.h"
#include "nrf_bootloader_dfu_timers.h"
#include "nrf_bootloader_fw_activation.h"
#include "nrf_bootloader_info.h"
#include "nrf_bootloader_wdt.h"
#include "nrf_delay.h"
#include "nrf_dfu.h"
#include "nrf_dfu_settings.h"
#include "nrf_dfu_utils.h"
#include "nrf_dfu_validation.h"
#include "nrf_error.h"
#include "nrf_gpio.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_power.h"
#include "sdk_config.h"
static nrf_dfu_observer_t
m_user_observer; //<! Observer callback set by the user.
static volatile bool m_flash_write_done;
#define SCHED_QUEUE_SIZE \
32 /**< Maximum number of events in the scheduler queue. */
#define SCHED_EVENT_DATA_SIZE \
NRF_DFU_SCHED_EVENT_DATA_SIZE /**< Maximum app_scheduler event size. */
#if !(defined(NRF_BL_DFU_ENTER_METHOD_BUTTON) && \
defined(NRF_BL_DFU_ENTER_METHOD_PINRESET) && \
defined(NRF_BL_DFU_ENTER_METHOD_GPREGRET) && \
defined(NRF_BL_DFU_ENTER_METHOD_BUTTONLESS) && \
defined(NRF_BL_RESET_DELAY_MS) && defined(NRF_BL_DEBUG_PORT_DISABLE))
#error Configuration file is missing flags. Update sdk_config.h.
#endif
STATIC_ASSERT((NRF_BL_DFU_INACTIVITY_TIMEOUT_MS >= 100) ||
(NRF_BL_DFU_INACTIVITY_TIMEOUT_MS == 0),
"NRF_BL_DFU_INACTIVITY_TIMEOUT_MS must be 100 ms or more, or 0 "
"to indicate that it is disabled.");
#if defined(NRF_LOG_BACKEND_FLASH_START_PAGE)
STATIC_ASSERT(NRF_LOG_BACKEND_FLASH_START_PAGE != 0,
"If nrf_log flash backend is used it cannot use space after code "
"because it would collide with settings page.");
#endif
/**@brief Weak implemenation of nrf_dfu_init
*
* @note This function will be overridden if nrf_dfu.c is
* compiled and linked with the project
*/
#if (__LINT__ != 1)
__WEAK uint32_t nrf_dfu_init(nrf_dfu_observer_t observer) {
NRF_LOG_DEBUG("in weak nrf_dfu_init");
return NRF_SUCCESS;
}
#endif
/**@brief Weak implementation of nrf_dfu_init
*
* @note This function must be overridden in application if
* user-specific initialization is needed.
*/
__WEAK uint32_t nrf_dfu_init_user(void) {
NRF_LOG_DEBUG("in weak nrf_dfu_init_user");
return NRF_SUCCESS;
}
static void flash_write_callback(void* p_context) {
UNUSED_PARAMETER(p_context);
m_flash_write_done = true;
}
static void do_reset(void* p_context) {
UNUSED_PARAMETER(p_context);
NRF_LOG_FINAL_FLUSH();
nrf_delay_ms(NRF_BL_RESET_DELAY_MS);
NVIC_SystemReset();
}
static void bootloader_reset(bool do_backup) {
NRF_LOG_DEBUG("Resetting bootloader.");
if (do_backup) {
m_flash_write_done = false;
nrf_dfu_settings_backup(do_reset);
} else {
do_reset(NULL);
}
}
static void inactivity_timeout(void) {
NRF_LOG_INFO("Inactivity timeout.");
bootloader_reset(true);
}
/**@brief Function for handling DFU events.
*/
static void dfu_observer(nrf_dfu_evt_type_t evt_type) {
switch (evt_type) {
case NRF_DFU_EVT_DFU_STARTED:
case NRF_DFU_EVT_OBJECT_RECEIVED:
nrf_bootloader_dfu_inactivity_timer_restart(
NRF_BOOTLOADER_MS_TO_TICKS(NRF_BL_DFU_INACTIVITY_TIMEOUT_MS),
inactivity_timeout);
break;
case NRF_DFU_EVT_DFU_COMPLETED:
case NRF_DFU_EVT_DFU_ABORTED:
bootloader_reset(true);
break;
case NRF_DFU_EVT_TRANSPORT_DEACTIVATED:
// Reset the internal state of the DFU settings to the last stored state.
nrf_dfu_settings_reinit();
break;
default:
break;
}
if (m_user_observer) {
m_user_observer(evt_type);
}
}
/**@brief Function for initializing the event scheduler.
*/
static void scheduler_init(void) {
APP_SCHED_INIT(SCHED_EVENT_DATA_SIZE, SCHED_QUEUE_SIZE);
}
/**@brief Suspend the CPU until an interrupt occurs.
*/
static void wait_for_event(void) {
#if defined(BLE_STACK_SUPPORT_REQD) || defined(ANT_STACK_SUPPORT_REQD)
(void)sd_app_evt_wait();
#else
// Wait for an event.
__WFE();
// Clear the internal event register.
__SEV();
__WFE();
#endif
}
/**@brief Continually sleep and process tasks whenever woken.
*/
static void loop_forever(void) {
while (true) {
// feed the watchdog if enabled.
nrf_bootloader_wdt_feed();
app_sched_execute();
if (!NRF_LOG_PROCESS()) {
wait_for_event();
}
}
}
#if NRF_BL_DFU_ENTER_METHOD_BUTTON
//#ifndef BUTTON_PULL
// #error NRF_BL_DFU_ENTER_METHOD_BUTTON is enabled but not buttons seem to
// be available on the board.
//#endif
/**@brief Function for initializing button used to enter DFU mode.
*/
static void dfu_enter_button_init(void) {
nrf_gpio_cfg_sense_input(NRF_BL_DFU_ENTER_METHOD_BUTTON_PIN,
NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_LOW);
}
#endif
static bool crc_on_valid_app_required(void) {
bool ret = true;
if (NRF_BL_APP_CRC_CHECK_SKIPPED_ON_SYSTEMOFF_RESET &&
(nrf_power_resetreas_get() & NRF_POWER_RESETREAS_OFF_MASK)) {
nrf_power_resetreas_clear(NRF_POWER_RESETREAS_OFF_MASK);
ret = false;
} else if (NRF_BL_APP_CRC_CHECK_SKIPPED_ON_GPREGRET2 &&
((nrf_power_gpregret2_get() & BOOTLOADER_DFU_SKIP_CRC_MASK) ==
BOOTLOADER_DFU_SKIP_CRC)) {
nrf_power_gpregret2_set(nrf_power_gpregret2_get() &
~BOOTLOADER_DFU_SKIP_CRC);
ret = false;
} else {
}
return ret;
}
static bool boot_validate(boot_validation_t const* p_validation,
uint32_t data_addr, uint32_t data_len, bool do_crc) {
if (!do_crc && (p_validation->type == VALIDATE_CRC)) {
return true;
}
return nrf_dfu_validation_boot_validate(p_validation, data_addr, data_len);
}
/** @brief Function for checking if the main application is valid.
*
* @details This function checks if there is a valid application
* located at Bank 0.
*
* @param[in] do_crc Perform CRC check on application. Only CRC checks
can be skipped. For other boot validation types,
this parameter is ignored.
*
* @retval true If a valid application has been detected.
* @retval false If there is no valid application.
*/
static bool app_is_valid(bool do_crc) {
if (s_dfu_settings.bank_0.bank_code != NRF_DFU_BANK_VALID_APP) {
NRF_LOG_INFO("Boot validation failed. No valid app to boot.");
return false;
} else if (NRF_BL_APP_SIGNATURE_CHECK_REQUIRED &&
(s_dfu_settings.boot_validation_app.type !=
VALIDATE_ECDSA_P256_SHA256)) {
NRF_LOG_WARNING(
"Boot validation failed. The boot validation of the app must be a "
"signature check.");
return false;
} else if (SD_PRESENT &&
!boot_validate(&s_dfu_settings.boot_validation_softdevice,
MBR_SIZE, s_dfu_settings.sd_size, do_crc)) {
NRF_LOG_WARNING(
"Boot validation failed. SoftDevice is present but invalid.");
return false;
} else if (!boot_validate(&s_dfu_settings.boot_validation_app,
nrf_dfu_bank0_start_addr(),
s_dfu_settings.bank_0.image_size, do_crc)) {
NRF_LOG_WARNING("Boot validation failed. App is invalid.");
return false;
}
// The bootloader itself is not checked, since a self-check of this kind gives
// little to no benefit compared to the cost incurred on each bootup.
NRF_LOG_DEBUG("App is valid");
return true;
}
/**@brief Function for clearing all DFU enter flags that
* preserve state during reset.
*
* @details This is used to make sure that each of these flags
* is checked only once after reset.
*/
static void dfu_enter_flags_clear(void) {
if (NRF_BL_DFU_ENTER_METHOD_PINRESET &&
(NRF_POWER->RESETREAS & POWER_RESETREAS_RESETPIN_Msk)) {
// Clear RESETPIN flag.
NRF_POWER->RESETREAS |= POWER_RESETREAS_RESETPIN_Msk;
}
if (NRF_BL_DFU_ENTER_METHOD_GPREGRET &&
((nrf_power_gpregret_get() & BOOTLOADER_DFU_START_MASK) ==
BOOTLOADER_DFU_START)) {
// Clear DFU mark in GPREGRET register.
nrf_power_gpregret_set(nrf_power_gpregret_get() & ~BOOTLOADER_DFU_START);
}
if (NRF_BL_DFU_ENTER_METHOD_BUTTONLESS &&
(s_dfu_settings.enter_buttonless_dfu == 1)) {
// Clear DFU flag in flash settings.
s_dfu_settings.enter_buttonless_dfu = 0;
APP_ERROR_CHECK(nrf_dfu_settings_write(NULL));
}
}
/**@brief Function for checking whether to enter DFU mode or not.
*/
static bool dfu_enter_check(void) {
if (!app_is_valid(crc_on_valid_app_required())) {
NRF_LOG_DEBUG("DFU mode because app is not valid.");
return true;
}
if (NRF_BL_DFU_ENTER_METHOD_BUTTON &&
(nrf_gpio_pin_read(NRF_BL_DFU_ENTER_METHOD_BUTTON_PIN) == 1)) {
NRF_LOG_DEBUG("DFU mode requested via button.");
return true;
}
if (NRF_BL_DFU_ENTER_METHOD_PINRESET &&
(NRF_POWER->RESETREAS & POWER_RESETREAS_RESETPIN_Msk)) {
NRF_LOG_DEBUG("DFU mode requested via pin-reset.");
return true;
}
if (NRF_BL_DFU_ENTER_METHOD_GPREGRET &&
((nrf_power_gpregret_get() & BOOTLOADER_DFU_START_MASK) ==
BOOTLOADER_DFU_START)) {
NRF_LOG_DEBUG("DFU mode requested via GPREGRET.");
return true;
}
if (NRF_BL_DFU_ENTER_METHOD_BUTTONLESS &&
(s_dfu_settings.enter_buttonless_dfu == 1)) {
NRF_LOG_DEBUG("DFU mode requested via bootloader settings.");
return true;
}
return false;
}
#if NRF_BL_DFU_ALLOW_UPDATE_FROM_APP
static void postvalidate(void) {
NRF_LOG_INFO("Postvalidating update after reset.");
nrf_dfu_validation_init();
if (nrf_dfu_validation_init_cmd_present()) {
uint32_t firmware_start_addr;
uint32_t firmware_size;
// Execute a previously received init packed. Subsequent executes will have
// no effect.
if (nrf_dfu_validation_init_cmd_execute(
&firmware_start_addr, &firmware_size) == NRF_DFU_RES_CODE_SUCCESS) {
if (nrf_dfu_validation_prevalidate() == NRF_DFU_RES_CODE_SUCCESS) {
if (nrf_dfu_validation_activation_prepare(firmware_start_addr,
firmware_size) ==
NRF_DFU_RES_CODE_SUCCESS) {
NRF_LOG_INFO("Postvalidation successful.");
}
}
}
}
s_dfu_settings.bank_current = NRF_DFU_CURRENT_BANK_0;
UNUSED_RETURN_VALUE(nrf_dfu_settings_write_and_backup(flash_write_callback));
}
#endif
ret_code_t nrf_bootloader_init(nrf_dfu_observer_t observer) {
NRF_LOG_DEBUG("In nrf_bootloader_init");
ret_code_t ret_val;
nrf_bootloader_fw_activation_result_t activation_result;
uint32_t initial_timeout;
bool dfu_enter = false;
m_user_observer = observer;
if (NRF_BL_DEBUG_PORT_DISABLE) {
nrf_bootloader_debug_port_disable();
}
#if NRF_BL_DFU_ENTER_METHOD_BUTTON
dfu_enter_button_init();
#endif
ret_val = nrf_dfu_settings_init(false);
if (ret_val != NRF_SUCCESS) {
return NRF_ERROR_INTERNAL;
}
#if NRF_BL_DFU_ALLOW_UPDATE_FROM_APP
// Postvalidate if DFU has signaled that update is ready.
if (s_dfu_settings.bank_current == NRF_DFU_CURRENT_BANK_1) {
postvalidate();
}
#endif
// Check if an update needs to be activated and activate it.
activation_result = nrf_bootloader_fw_activate();
switch (activation_result) {
case ACTIVATION_NONE:
initial_timeout =
NRF_BOOTLOADER_MS_TO_TICKS(NRF_BL_DFU_INACTIVITY_TIMEOUT_MS);
dfu_enter = dfu_enter_check();
break;
case ACTIVATION_SUCCESS_EXPECT_ADDITIONAL_UPDATE:
initial_timeout =
NRF_BOOTLOADER_MS_TO_TICKS(NRF_BL_DFU_CONTINUATION_TIMEOUT_MS);
dfu_enter = true;
break;
case ACTIVATION_SUCCESS:
bootloader_reset(true);
NRF_LOG_ERROR("Unreachable");
return NRF_ERROR_INTERNAL; // Should not reach this.
case ACTIVATION_ERROR:
default:
return NRF_ERROR_INTERNAL;
}
if (dfu_enter) {
nrf_bootloader_wdt_init();
scheduler_init();
dfu_enter_flags_clear();
// Call user-defined init function if implemented
ret_val = nrf_dfu_init_user();
if (ret_val != NRF_SUCCESS) {
return NRF_ERROR_INTERNAL;
}
nrf_bootloader_dfu_inactivity_timer_restart(initial_timeout,
inactivity_timeout);
ret_val = nrf_dfu_init(dfu_observer);
if (ret_val != NRF_SUCCESS) {
return NRF_ERROR_INTERNAL;
}
NRF_LOG_DEBUG("Enter main loop");
loop_forever(); // This function will never return.
NRF_LOG_ERROR("Unreachable");
} else {
// Erase additional data like peer data or advertisement name
ret_val = nrf_dfu_settings_additional_erase();
if (ret_val != NRF_SUCCESS) {
return NRF_ERROR_INTERNAL;
}
m_flash_write_done = false;
nrf_dfu_settings_backup(flash_write_callback);
ASSERT(m_flash_write_done);
nrf_bootloader_app_start();
NRF_LOG_ERROR("Unreachable");
}
// Should not be reached.
return NRF_ERROR_INTERNAL;
}

@ -0,0 +1,63 @@
/**
* Copyright (c) 2019 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be
* reverse engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NRF_CRYPTO_ALLOCATOR_H__
#define NRF_CRYPTO_ALLOCATOR_H__
#include "nrf_assert.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Crypto library in bootloader case does not use dynamic allocation */
#define NRF_CRYPTO_ALLOC(size) \
NULL; \
ASSERT(0)
#define NRF_CRYPTO_ALLOC_ON_STACK(size) \
NULL; \
ASSERT(0)
#define NRF_CRYPTO_FREE(ptr) (void)ptr;
#ifdef __cplusplus
}
#endif
#endif /* NRF_CRYPTO_ALLOCATOR_H__ */

@ -0,0 +1,276 @@
// clang-format off
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "nrf_dfu_serial.h"
#include <string.h>
#include "trezor_t3w1_d1_NRF.h"
#include "nrf_gpio.h"
#include "nordic_common.h"
#include "app_util_platform.h"
#include "nrf_dfu_transport.h"
#include "nrf_dfu_req_handler.h"
#include "slip.h"
#include "nrf_balloc.h"
#include "nrf_drv_uart.h"
#define NRF_LOG_MODULE_NAME nrf_dfu_serial_uart
#include "nrf_log.h"
NRF_LOG_MODULE_REGISTER();
/**@file
*
* @defgroup nrf_dfu_serial_uart DFU Serial UART transport
* @ingroup nrf_dfu
* @brief Device Firmware Update (DFU) transport layer using UART.
*/
#define NRF_SERIAL_OPCODE_SIZE (sizeof(uint8_t))
#define NRF_UART_MAX_RESPONSE_SIZE_SLIP (2 * NRF_SERIAL_MAX_RESPONSE_SIZE + 1)
#define RX_BUF_SIZE (64) //to get 64bytes payload
#define OPCODE_OFFSET (sizeof(uint32_t) - NRF_SERIAL_OPCODE_SIZE)
#define DATA_OFFSET (OPCODE_OFFSET + NRF_SERIAL_OPCODE_SIZE)
#define UART_SLIP_MTU (2 * (RX_BUF_SIZE + 1) + 1)
#define BALLOC_BUF_SIZE ((CEIL_DIV((RX_BUF_SIZE+OPCODE_SIZE),sizeof(uint32_t))*sizeof(uint32_t)))
NRF_BALLOC_DEF(m_payload_pool, (UART_SLIP_MTU + 1), NRF_DFU_SERIAL_UART_RX_BUFFERS);
static nrf_drv_uart_t m_uart = NRF_DRV_UART_INSTANCE(0);
static uint8_t m_rx_byte;
static nrf_dfu_serial_t m_serial;
static slip_t m_slip;
static uint8_t m_rsp_buf[NRF_UART_MAX_RESPONSE_SIZE_SLIP];
static bool m_active;
static bool m_waiting_for_buffers = false;
static nrf_dfu_observer_t m_observer;
static uint32_t uart_dfu_transport_init(nrf_dfu_observer_t observer);
static uint32_t uart_dfu_transport_close(nrf_dfu_transport_t const * p_exception);
DFU_TRANSPORT_REGISTER(nrf_dfu_transport_t const uart_dfu_transport) =
{
.init_func = uart_dfu_transport_init,
.close_func = uart_dfu_transport_close,
};
static void payload_free(void * p_buf)
{
uint8_t * p_buf_root = (uint8_t *)p_buf - DATA_OFFSET; //pointer is shifted to point to data
nrf_balloc_free(&m_payload_pool, p_buf_root);
uint8_t utilization = m_payload_pool.p_stack_limit - m_payload_pool.p_cb->p_stack_pointer;
if (m_waiting_for_buffers && utilization < NRF_DFU_SERIAL_UART_RX_BUFFERS - 2) {
NRF_LOG_INFO("Buffer utilization: %d, resuming.", utilization);
nrf_gpio_pin_set(RTS_PIN_NUMBER);
nrf_gpio_cfg_output(RTS_PIN_NUMBER);
m_uart.uarte.p_reg->PSEL.RTS = RTS_PIN_NUMBER;
m_waiting_for_buffers = false;
}
}
static ret_code_t rsp_send(uint8_t const * p_data, uint32_t length)
{
uint32_t slip_len;
(void) slip_encode(m_rsp_buf, (uint8_t *)p_data, length, &slip_len);
return nrf_drv_uart_tx(&m_uart, m_rsp_buf, slip_len);
}
static __INLINE void on_rx_complete(nrf_dfu_serial_t * p_transport, uint8_t * p_data, uint8_t len)
{
ret_code_t ret_code = NRF_ERROR_TIMEOUT;
// Check if there is byte to process. Zero length transfer means that RXTO occured.
if (len)
{
ret_code = slip_decode_add_byte(&m_slip, p_data[0]);
}
(void) nrf_drv_uart_rx(&m_uart, &m_rx_byte, 1);
if (ret_code == NRF_SUCCESS)
{
nrf_dfu_serial_on_packet_received(p_transport,
(uint8_t const *)m_slip.p_buffer,
m_slip.current_index);
uint8_t * p_rx_buf = nrf_balloc_alloc(&m_payload_pool);
uint8_t utilization = m_payload_pool.p_stack_limit - m_payload_pool.p_cb->p_stack_pointer;
if (!m_waiting_for_buffers && utilization >= NRF_DFU_SERIAL_UART_RX_BUFFERS - 2) {
NRF_LOG_INFO("Buffer utilization: %d, waiting.", utilization);
m_uart.uarte.p_reg->PSEL.RTS = NRF_UART_PSEL_DISCONNECTED;
nrf_gpio_cfg_output(RTS_PIN_NUMBER);
nrf_gpio_pin_set(RTS_PIN_NUMBER);
m_waiting_for_buffers = true;
}
if (p_rx_buf == NULL)
{
NRF_LOG_ERROR("Failed to allocate buffer");
return;
}
NRF_LOG_INFO("Allocated buffer %x", p_rx_buf);
// reset the slip decoding
m_slip.p_buffer = &p_rx_buf[OPCODE_OFFSET];
m_slip.current_index = 0;
m_slip.state = SLIP_STATE_DECODING;
}
}
static void uart_event_handler(nrf_drv_uart_event_t * p_event, void * p_context)
{
switch (p_event->type)
{
case NRF_DRV_UART_EVT_RX_DONE:
on_rx_complete((nrf_dfu_serial_t*)p_context,
p_event->data.rxtx.p_data,
p_event->data.rxtx.bytes);
break;
case NRF_DRV_UART_EVT_ERROR:
APP_ERROR_HANDLER(p_event->data.error.error_mask);
break;
default:
// No action.
break;
}
}
static uint32_t uart_dfu_transport_init(nrf_dfu_observer_t observer)
{
uint32_t err_code = NRF_SUCCESS;
if (m_active)
{
return err_code;
}
NRF_LOG_DEBUG("serial_dfu_transport_init()");
m_observer = observer;
err_code = nrf_balloc_init(&m_payload_pool);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
uint8_t * p_rx_buf = nrf_balloc_alloc(&m_payload_pool);
m_slip.p_buffer = &p_rx_buf[OPCODE_OFFSET];
m_slip.current_index = 0;
m_slip.buffer_len = UART_SLIP_MTU;
m_slip.state = SLIP_STATE_DECODING;
m_serial.rsp_func = rsp_send;
m_serial.payload_free_func = payload_free;
m_serial.mtu = UART_SLIP_MTU;
m_serial.p_rsp_buf = &m_rsp_buf[NRF_UART_MAX_RESPONSE_SIZE_SLIP -
NRF_SERIAL_MAX_RESPONSE_SIZE];
m_serial.p_low_level_transport = &uart_dfu_transport;
nrf_drv_uart_config_t uart_config = NRF_DRV_UART_DEFAULT_CONFIG;
uart_config.pseltxd = TX_PIN_NUMBER;
uart_config.pselrxd = RX_PIN_NUMBER;
uart_config.pselcts = CTS_PIN_NUMBER;
uart_config.pselrts = RTS_PIN_NUMBER;
uart_config.hwfc = NRF_UART_HWFC_ENABLED;
uart_config.p_context = &m_serial;
nrf_gpio_cfg(
RTS_PIN_NUMBER,
NRF_GPIO_PIN_DIR_OUTPUT,
NRF_GPIO_PIN_INPUT_DISCONNECT,
NRF_GPIO_PIN_NOPULL,
NRF_GPIO_PIN_S0S1,
NRF_GPIO_PIN_NOSENSE);
nrf_gpio_pin_write(RTS_PIN_NUMBER, 0);
err_code = nrf_drv_uart_init(&m_uart, &uart_config, uart_event_handler);
if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("Failed initializing uart");
return err_code;
}
err_code = nrf_drv_uart_rx(&m_uart, &m_rx_byte, 1);
if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("Failed initializing rx");
}
NRF_LOG_DEBUG("serial_dfu_transport_init() completed");
m_active = true;
if (m_observer)
{
m_observer(NRF_DFU_EVT_TRANSPORT_ACTIVATED);
}
return err_code;
}
static uint32_t uart_dfu_transport_close(nrf_dfu_transport_t const * p_exception)
{
if ((m_active == true) && (p_exception != &uart_dfu_transport))
{
nrf_drv_uart_uninit(&m_uart);
m_active = false;
}
return NRF_SUCCESS;
}

@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIOSMfopjR9WnpAjLnog4xJG5XRVi5MfXk7bGGuxLanCAoAoGCCqGSM49
AwEHoUQDQgAE9KQi8GEjC+sEphRRaW/GfnCfPJEaKY+oyAw/t0FUL37WzYQEfAos
6HnwYBqys9MYxWRJc0woWfaQGi5I+ptzrQ==
-----END EC PRIVATE KEY-----

File diff suppressed because it is too large Load Diff

@ -0,0 +1,104 @@
:020000040007F3
:10E000005021D2AF0200000000000000000000001C
:10E01000000000000000000080820100C0F8B7B4DA
:10E0200001000000000000000000000000000000EF
:10E030000000000034560200000000000000000054
:10E0400000000000000000000000000000000000D0
:10E0500000000000000000000000000000000000C0
:10E0600000000000000000000000000000000000B0
:10E0700000000000000000000000000000000000A0
:10E080000000000000000000000000000000000090
:10E090000000000000000000000000000000000080
:10E0A0000000000000000000000000000000000070
:10E0B0000000000000000000000000000000000060
:10E0C0000000000000000000000000000000000050
:10E0D0000000000000000000000000000000000040
:10E0E0000000000000000000000000000000000030
:10E0F0000000000000000000000000000000000020
:10E10000000000000000000000000000000000000F
:10E1100000000000000000000000000000000000FF
:10E1200000000000000000000000000000000000EF
:10E1300000000000000000000000000000000000DF
:10E1400000000000000000000000000000000000CF
:10E1500000000000000000000000000000000000BF
:10E1600000000000000000000000000000000000AF
:10E17000000000000000000000000000000000009F
:10E18000000000000000000000000000000000008F
:10E19000000000000000000000000000000000007F
:10E1A000000000000000000000000000000000006F
:10E1B000000000000000000000000000000000005F
:10E1C000000000000000000000000000000000004F
:10E1D000000000000000000000000000000000003F
:10E1E000000000000000000000000000000000002F
:10E1F000000000000000000000000000000000001F
:10E20000000000000000000000000000000000000E
:10E2100000000000000000000000000000000000FE
:10E2200000000000000000000000000000000000EE
:10E2300000000000000000000000000000000000DE
:10E2400000000000000000000000000000000000CE
:10E250000000000000000000000000008AEF67D40A
:10E26000039C5C1C98A20BBD8ABFB9C46939106BB2
:10E27000B47E723565915A51FAC818DE94DD6E8C01
:10E280002BD8C489343239712A38D616C1A9482C02
:10E29000CDA78E5E28F37D0E3AF147DF285C80170C
:10E2A00071035B9F4D32703D914A924FB5B9142076
:10E2B000EE2F84400F8681CD396EC8C55C811676FD
:10E2C000EC52E336EE8EF89DB5B57AAF4C54E69736
:10E2D000A3E5472CD695C51C2E4EB86E56EE19F503
:10E2E00051AE00000000000000000000000000002F
:10E2F000000000000000000000000000000000001E
:10E30000000000000000000000000000000000000D
:10E3100000000000000000000000000000000000FD
:04E32000000000FFFA
:10F000005021D2AF0200000000000000000000000C
:10F01000000000000000000080820100C0F8B7B4CA
:10F0200001000000000000000000000000000000DF
:10F030000000000034560200000000000000000044
:10F0400000000000000000000000000000000000C0
:10F0500000000000000000000000000000000000B0
:10F0600000000000000000000000000000000000A0
:10F070000000000000000000000000000000000090
:10F080000000000000000000000000000000000080
:10F090000000000000000000000000000000000070
:10F0A0000000000000000000000000000000000060
:10F0B0000000000000000000000000000000000050
:10F0C0000000000000000000000000000000000040
:10F0D0000000000000000000000000000000000030
:10F0E0000000000000000000000000000000000020
:10F0F0000000000000000000000000000000000010
:10F1000000000000000000000000000000000000FF
:10F1100000000000000000000000000000000000EF
:10F1200000000000000000000000000000000000DF
:10F1300000000000000000000000000000000000CF
:10F1400000000000000000000000000000000000BF
:10F1500000000000000000000000000000000000AF
:10F16000000000000000000000000000000000009F
:10F17000000000000000000000000000000000008F
:10F18000000000000000000000000000000000007F
:10F19000000000000000000000000000000000006F
:10F1A000000000000000000000000000000000005F
:10F1B000000000000000000000000000000000004F
:10F1C000000000000000000000000000000000003F
:10F1D000000000000000000000000000000000002F
:10F1E000000000000000000000000000000000001F
:10F1F000000000000000000000000000000000000F
:10F2000000000000000000000000000000000000FE
:10F2100000000000000000000000000000000000EE
:10F2200000000000000000000000000000000000DE
:10F2300000000000000000000000000000000000CE
:10F2400000000000000000000000000000000000BE
:10F250000000000000000000000000008AEF67D4FA
:10F26000039C5C1C98A20BBD8ABFB9C46939106BA2
:10F27000B47E723565915A51FAC818DE94DD6E8CF1
:10F280002BD8C489343239712A38D616C1A9482CF2
:10F29000CDA78E5E28F37D0E3AF147DF285C8017FC
:10F2A00071035B9F4D32703D914A924FB5B9142066
:10F2B000EE2F84400F8681CD396EC8C55C811676ED
:10F2C000EC52E336EE8EF89DB5B57AAF4C54E69726
:10F2D000A3E5472CD695C51C2E4EB86E56EE19F5F3
:10F2E00051AE00000000000000000000000000001F
:10F2F000000000000000000000000000000000000E
:10F3000000000000000000000000000000000000FD
:10F3100000000000000000000000000000000000ED
:04F32000000000FFEA
:00000001FF

@ -0,0 +1,11 @@
__build__/
__pycache__
*.pyc
*.pyo
*.pyd
*.pyz
*.egg-info/
*.a
*.o
*.so
.DS_Store

@ -0,0 +1,21 @@
Copyright (c) 2014, Kenneth MacKay
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

@ -0,0 +1,41 @@
micro-ecc
==========
A small and fast ECDH and ECDSA implementation for 8-bit, 32-bit, and 64-bit processors.
The static version of micro-ecc (ie, where the curve was selected at compile-time) can be found in the "static" branch.
Features
--------
* Resistant to known side-channel attacks.
* Written in C, with optional GCC inline assembly for AVR, ARM and Thumb platforms.
* Supports 8, 32, and 64-bit architectures.
* Small code size.
* No dynamic memory allocation.
* Support for 5 standard curves: secp160r1, secp192r1, secp224r1, secp256r1, and secp256k1.
* BSD 2-clause license.
Usage Notes
-----------
### Point Representation ###
Compressed points are represented in the standard format as defined in http://www.secg.org/sec1-v2.pdf; uncompressed points are represented in standard format, but without the `0x04` prefix. All functions except `uECC_decompress()` only accept uncompressed points; use `uECC_compress()` and `uECC_decompress()` to convert between compressed and uncompressed point representations.
Private keys are represented in the standard format.
### Using the Code ###
I recommend just copying (or symlink) the uECC files into your project. Then just `#include "uECC.h"` to use the micro-ecc functions.
For use with Arduino, you can use the Library Manager to download micro-ecc (**Sketch**=>**Include Library**=>**Manage Libraries**). You can then use uECC just like any other Arduino library (uECC should show up in the **Sketch**=>**Import Library** submenu).
See uECC.h for documentation for each function.
### Compilation Notes ###
* Should compile with any C/C++ compiler that supports stdint.h (this includes Visual Studio 2013).
* If you want to change the defaults for any of the uECC compile-time options (such as `uECC_OPTIMIZATION_LEVEL`), you must change them in your Makefile or similar so that uECC.c is compiled with the desired values (ie, compile uECC.c with `-DuECC_OPTIMIZATION_LEVEL=3` or whatever).
* When compiling for a Thumb-1 platform, you must use the `-fomit-frame-pointer` GCC option (this is enabled by default when compiling with `-O1` or higher).
* When compiling for an ARM/Thumb-2 platform with `uECC_OPTIMIZATION_LEVEL` >= 3, you must use the `-fomit-frame-pointer` GCC option (this is enabled by default when compiling with `-O1` or higher).
* When compiling for AVR, you must have optimizations enabled (compile with `-O1` or higher).
* When building for Windows, you will need to link in the `advapi32.lib` system library.

@ -0,0 +1,820 @@
/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */
#ifndef _UECC_ASM_ARM_H_
#define _UECC_ASM_ARM_H_
#if (uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1)
#define uECC_MIN_WORDS 8
#endif
#if uECC_SUPPORTS_secp224r1
#undef uECC_MIN_WORDS
#define uECC_MIN_WORDS 7
#endif
#if uECC_SUPPORTS_secp192r1
#undef uECC_MIN_WORDS
#define uECC_MIN_WORDS 6
#endif
#if uECC_SUPPORTS_secp160r1
#undef uECC_MIN_WORDS
#define uECC_MIN_WORDS 5
#endif
#if (uECC_PLATFORM == uECC_arm_thumb)
#define REG_RW "+&l"
#define REG_WRITE "=&l"
#else
#define REG_RW "+&r"
#define REG_WRITE "=&r"
#endif
#if (uECC_PLATFORM == uECC_arm_thumb || uECC_PLATFORM == uECC_arm_thumb2)
#define REG_RW_LO "+&l"
#define REG_WRITE_LO "=&l"
#else
#define REG_RW_LO "+&r"
#define REG_WRITE_LO "=&r"
#endif
#if (uECC_PLATFORM == uECC_arm_thumb2)
#define RESUME_SYNTAX
#else
#define RESUME_SYNTAX ".syntax divided \n\t"
#endif
#if (uECC_OPTIMIZATION_LEVEL >= 2)
uECC_VLI_API uECC_word_t uECC_vli_add(uECC_word_t *result,
const uECC_word_t *left,
const uECC_word_t *right,
wordcount_t num_words) {
#if (uECC_MAX_WORDS != uECC_MIN_WORDS)
#if (uECC_PLATFORM == uECC_arm_thumb) || (uECC_PLATFORM == uECC_arm_thumb2)
uint32_t jump = (uECC_MAX_WORDS - num_words) * 4 * 2 + 1;
#else /* ARM */
uint32_t jump = (uECC_MAX_WORDS - num_words) * 4 * 4;
#endif
#endif
uint32_t carry;
uint32_t left_word;
uint32_t right_word;
__asm__ volatile (
".syntax unified \n\t"
"movs %[carry], #0 \n\t"
#if (uECC_MAX_WORDS != uECC_MIN_WORDS)
"adr %[left], 1f \n\t"
".align 4 \n\t"
"adds %[jump], %[left] \n\t"
#endif
"ldmia %[lptr]!, {%[left]} \n\t"
"ldmia %[rptr]!, {%[right]} \n\t"
"adds %[left], %[right] \n\t"
"stmia %[dptr]!, {%[left]} \n\t"
#if (uECC_MAX_WORDS != uECC_MIN_WORDS)
"bx %[jump] \n\t"
#endif
"1: \n\t"
REPEAT(DEC(uECC_MAX_WORDS),
"ldmia %[lptr]!, {%[left]} \n\t"
"ldmia %[rptr]!, {%[right]} \n\t"
"adcs %[left], %[right] \n\t"
"stmia %[dptr]!, {%[left]} \n\t")
"adcs %[carry], %[carry] \n\t"
RESUME_SYNTAX
: [dptr] REG_RW_LO (result), [lptr] REG_RW_LO (left), [rptr] REG_RW_LO (right),
#if (uECC_MAX_WORDS != uECC_MIN_WORDS)
[jump] REG_RW_LO (jump),
#endif
[carry] REG_WRITE_LO (carry), [left] REG_WRITE_LO (left_word),
[right] REG_WRITE_LO (right_word)
:
: "cc", "memory"
);
return carry;
}
#define asm_add 1
uECC_VLI_API uECC_word_t uECC_vli_sub(uECC_word_t *result,
const uECC_word_t *left,
const uECC_word_t *right,
wordcount_t num_words) {
#if (uECC_MAX_WORDS != uECC_MIN_WORDS)
#if (uECC_PLATFORM == uECC_arm_thumb) || (uECC_PLATFORM == uECC_arm_thumb2)
uint32_t jump = (uECC_MAX_WORDS - num_words) * 4 * 2 + 1;
#else /* ARM */
uint32_t jump = (uECC_MAX_WORDS - num_words) * 4 * 4;
#endif
#endif
uint32_t carry;
uint32_t left_word;
uint32_t right_word;
__asm__ volatile (
".syntax unified \n\t"
"movs %[carry], #0 \n\t"
#if (uECC_MAX_WORDS != uECC_MIN_WORDS)
"adr %[left], 1f \n\t"
".align 4 \n\t"
"adds %[jump], %[left] \n\t"
#endif
"ldmia %[lptr]!, {%[left]} \n\t"
"ldmia %[rptr]!, {%[right]} \n\t"
"subs %[left], %[right] \n\t"
"stmia %[dptr]!, {%[left]} \n\t"
#if (uECC_MAX_WORDS != uECC_MIN_WORDS)
"bx %[jump] \n\t"
#endif
"1: \n\t"
REPEAT(DEC(uECC_MAX_WORDS),
"ldmia %[lptr]!, {%[left]} \n\t"
"ldmia %[rptr]!, {%[right]} \n\t"
"sbcs %[left], %[right] \n\t"
"stmia %[dptr]!, {%[left]} \n\t")
"adcs %[carry], %[carry] \n\t"
RESUME_SYNTAX
: [dptr] REG_RW_LO (result), [lptr] REG_RW_LO (left), [rptr] REG_RW_LO (right),
#if (uECC_MAX_WORDS != uECC_MIN_WORDS)
[jump] REG_RW_LO (jump),
#endif
[carry] REG_WRITE_LO (carry), [left] REG_WRITE_LO (left_word),
[right] REG_WRITE_LO (right_word)
:
: "cc", "memory"
);
return !carry; /* Note that on ARM, carry flag set means "no borrow" when subtracting
(for some reason...) */
}
#define asm_sub 1
#endif /* (uECC_OPTIMIZATION_LEVEL >= 2) */
#if (uECC_OPTIMIZATION_LEVEL >= 3)
#if (uECC_PLATFORM != uECC_arm_thumb)
#if uECC_ARM_USE_UMAAL
#include "asm_arm_mult_square_umaal.inc"
#else
#include "asm_arm_mult_square.inc"
#endif
#if (uECC_OPTIMIZATION_LEVEL == 3)
uECC_VLI_API void uECC_vli_mult(uint32_t *result,
const uint32_t *left,
const uint32_t *right,
wordcount_t num_words) {
register uint32_t *r0 __asm__("r0") = result;
register const uint32_t *r1 __asm__("r1") = left;
register const uint32_t *r2 __asm__("r2") = right;
register uint32_t r3 __asm__("r3") = num_words;
__asm__ volatile (
".syntax unified \n\t"
#if (uECC_MIN_WORDS == 5)
FAST_MULT_ASM_5
#if (uECC_MAX_WORDS > 5)
FAST_MULT_ASM_5_TO_6
#endif
#if (uECC_MAX_WORDS > 6)
FAST_MULT_ASM_6_TO_7
#endif
#if (uECC_MAX_WORDS > 7)
FAST_MULT_ASM_7_TO_8
#endif
#elif (uECC_MIN_WORDS == 6)
FAST_MULT_ASM_6
#if (uECC_MAX_WORDS > 6)
FAST_MULT_ASM_6_TO_7
#endif
#if (uECC_MAX_WORDS > 7)
FAST_MULT_ASM_7_TO_8
#endif
#elif (uECC_MIN_WORDS == 7)
FAST_MULT_ASM_7
#if (uECC_MAX_WORDS > 7)
FAST_MULT_ASM_7_TO_8
#endif
#elif (uECC_MIN_WORDS == 8)
FAST_MULT_ASM_8
#endif
"1: \n\t"
RESUME_SYNTAX
: "+r" (r0), "+r" (r1), "+r" (r2)
: "r" (r3)
: "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory"
);
}
#define asm_mult 1
#if uECC_SQUARE_FUNC
uECC_VLI_API void uECC_vli_square(uECC_word_t *result,
const uECC_word_t *left,
wordcount_t num_words) {
register uint32_t *r0 __asm__("r0") = result;
register const uint32_t *r1 __asm__("r1") = left;
register uint32_t r2 __asm__("r2") = num_words;
__asm__ volatile (
".syntax unified \n\t"
#if (uECC_MIN_WORDS == 5)
FAST_SQUARE_ASM_5
#if (uECC_MAX_WORDS > 5)
FAST_SQUARE_ASM_5_TO_6
#endif
#if (uECC_MAX_WORDS > 6)
FAST_SQUARE_ASM_6_TO_7
#endif
#if (uECC_MAX_WORDS > 7)
FAST_SQUARE_ASM_7_TO_8
#endif
#elif (uECC_MIN_WORDS == 6)
FAST_SQUARE_ASM_6
#if (uECC_MAX_WORDS > 6)
FAST_SQUARE_ASM_6_TO_7
#endif
#if (uECC_MAX_WORDS > 7)
FAST_SQUARE_ASM_7_TO_8
#endif
#elif (uECC_MIN_WORDS == 7)
FAST_SQUARE_ASM_7
#if (uECC_MAX_WORDS > 7)
FAST_SQUARE_ASM_7_TO_8
#endif
#elif (uECC_MIN_WORDS == 8)
FAST_SQUARE_ASM_8
#endif
"1: \n\t"
RESUME_SYNTAX
: "+r" (r0), "+r" (r1)
: "r" (r2)
: "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory"
);
}
#define asm_square 1
#endif /* uECC_SQUARE_FUNC */
#else /* (uECC_OPTIMIZATION_LEVEL > 3) */
uECC_VLI_API void uECC_vli_mult(uint32_t *result,
const uint32_t *left,
const uint32_t *right,
wordcount_t num_words) {
register uint32_t *r0 __asm__("r0") = result;
register const uint32_t *r1 __asm__("r1") = left;
register const uint32_t *r2 __asm__("r2") = right;
register uint32_t r3 __asm__("r3") = num_words;
#if uECC_SUPPORTS_secp160r1
if (num_words == 5) {
__asm__ volatile (
".syntax unified \n\t"
FAST_MULT_ASM_5
RESUME_SYNTAX
: "+r" (r0), "+r" (r1), "+r" (r2)
: "r" (r3)
: "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory"
);
return;
}
#endif
#if uECC_SUPPORTS_secp192r1
if (num_words == 6) {
__asm__ volatile (
".syntax unified \n\t"
FAST_MULT_ASM_6
RESUME_SYNTAX
: "+r" (r0), "+r" (r1), "+r" (r2)
: "r" (r3)
: "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory"
);
return;
}
#endif
#if uECC_SUPPORTS_secp224r1
if (num_words == 7) {
__asm__ volatile (
".syntax unified \n\t"
FAST_MULT_ASM_7
RESUME_SYNTAX
: "+r" (r0), "+r" (r1), "+r" (r2)
: "r" (r3)
: "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory"
);
return;
}
#endif
#if (uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1)
if (num_words == 8) {
__asm__ volatile (
".syntax unified \n\t"
FAST_MULT_ASM_8
RESUME_SYNTAX
: "+r" (r0), "+r" (r1), "+r" (r2)
: "r" (r3)
: "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory"
);
return;
}
#endif
}
#define asm_mult 1
#if uECC_SQUARE_FUNC
uECC_VLI_API void uECC_vli_square(uECC_word_t *result,
const uECC_word_t *left,
wordcount_t num_words) {
register uint32_t *r0 __asm__("r0") = result;
register const uint32_t *r1 __asm__("r1") = left;
register uint32_t r2 __asm__("r2") = num_words;
#if uECC_SUPPORTS_secp160r1
if (num_words == 5) {
__asm__ volatile (
".syntax unified \n\t"
FAST_SQUARE_ASM_5
RESUME_SYNTAX
: "+r" (r0), "+r" (r1)
: "r" (r2)
: "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory"
);
return;
}
#endif
#if uECC_SUPPORTS_secp192r1
if (num_words == 6) {
__asm__ volatile (
".syntax unified \n\t"
FAST_SQUARE_ASM_6
RESUME_SYNTAX
: "+r" (r0), "+r" (r1)
: "r" (r2)
: "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory"
);
return;
}
#endif
#if uECC_SUPPORTS_secp224r1
if (num_words == 7) {
__asm__ volatile (
".syntax unified \n\t"
FAST_SQUARE_ASM_7
RESUME_SYNTAX
: "+r" (r0), "+r" (r1)
: "r" (r2)
: "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory"
);
return;
}
#endif
#if (uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1)
if (num_words == 8) {
__asm__ volatile (
".syntax unified \n\t"
FAST_SQUARE_ASM_8
RESUME_SYNTAX
: "+r" (r0), "+r" (r1)
: "r" (r2)
: "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory"
);
return;
}
#endif
}
#define asm_square 1
#endif /* uECC_SQUARE_FUNC */
#endif /* (uECC_OPTIMIZATION_LEVEL > 3) */
#endif /* uECC_PLATFORM != uECC_arm_thumb */
#endif /* (uECC_OPTIMIZATION_LEVEL >= 3) */
/* ---- "Small" implementations ---- */
#if !asm_add
uECC_VLI_API uECC_word_t uECC_vli_add(uECC_word_t *result,
const uECC_word_t *left,
const uECC_word_t *right,
wordcount_t num_words) {
uint32_t carry = 0;
uint32_t left_word;
uint32_t right_word;
__asm__ volatile (
".syntax unified \n\t"
"1: \n\t"
"ldmia %[lptr]!, {%[left]} \n\t" /* Load left word. */
"ldmia %[rptr]!, {%[right]} \n\t" /* Load right word. */
"lsrs %[carry], #1 \n\t" /* Set up carry flag (carry = 0 after this). */
"adcs %[left], %[left], %[right] \n\t" /* Add with carry. */
"adcs %[carry], %[carry], %[carry] \n\t" /* Store carry bit. */
"stmia %[dptr]!, {%[left]} \n\t" /* Store result word. */
"subs %[ctr], #1 \n\t" /* Decrement counter. */
"bne 1b \n\t" /* Loop until counter == 0. */
RESUME_SYNTAX
: [dptr] REG_RW (result), [lptr] REG_RW (left), [rptr] REG_RW (right),
[ctr] REG_RW (num_words), [carry] REG_RW (carry),
[left] REG_WRITE (left_word), [right] REG_WRITE (right_word)
:
: "cc", "memory"
);
return carry;
}
#define asm_add 1
#endif
#if !asm_sub
uECC_VLI_API uECC_word_t uECC_vli_sub(uECC_word_t *result,
const uECC_word_t *left,
const uECC_word_t *right,
wordcount_t num_words) {
uint32_t carry = 1; /* carry = 1 initially (means don't borrow) */
uint32_t left_word;
uint32_t right_word;
__asm__ volatile (
".syntax unified \n\t"
"1: \n\t"
"ldmia %[lptr]!, {%[left]} \n\t" /* Load left word. */
"ldmia %[rptr]!, {%[right]} \n\t" /* Load right word. */
"lsrs %[carry], #1 \n\t" /* Set up carry flag (carry = 0 after this). */
"sbcs %[left], %[left], %[right] \n\t" /* Subtract with borrow. */
"adcs %[carry], %[carry], %[carry] \n\t" /* Store carry bit. */
"stmia %[dptr]!, {%[left]} \n\t" /* Store result word. */
"subs %[ctr], #1 \n\t" /* Decrement counter. */
"bne 1b \n\t" /* Loop until counter == 0. */
RESUME_SYNTAX
: [dptr] REG_RW (result), [lptr] REG_RW (left), [rptr] REG_RW (right),
[ctr] REG_RW (num_words), [carry] REG_RW (carry),
[left] REG_WRITE (left_word), [right] REG_WRITE (right_word)
:
: "cc", "memory"
);
return !carry;
}
#define asm_sub 1
#endif
#if !asm_mult
uECC_VLI_API void uECC_vli_mult(uECC_word_t *result,
const uECC_word_t *left,
const uECC_word_t *right,
wordcount_t num_words) {
#if (uECC_PLATFORM != uECC_arm_thumb)
uint32_t c0 = 0;
uint32_t c1 = 0;
uint32_t c2 = 0;
uint32_t k = 0;
uint32_t i;
uint32_t t0, t1;
__asm__ volatile (
".syntax unified \n\t"
"1: \n\t" /* outer loop (k < num_words) */
"movs %[i], #0 \n\t" /* i = 0 */
"b 3f \n\t"
"2: \n\t" /* outer loop (k >= num_words) */
"movs %[i], %[k] \n\t" /* i = k */
"subs %[i], %[last_word] \n\t" /* i = k - (num_words - 1) (times 4) */
"3: \n\t" /* inner loop */
"subs %[t0], %[k], %[i] \n\t" /* t0 = k-i */
"ldr %[t1], [%[right], %[t0]] \n\t" /* t1 = right[k - i] */
"ldr %[t0], [%[left], %[i]] \n\t" /* t0 = left[i] */
"umull %[t0], %[t1], %[t0], %[t1] \n\t" /* (t0, t1) = left[i] * right[k - i] */
"adds %[c0], %[c0], %[t0] \n\t" /* add low word to c0 */
"adcs %[c1], %[c1], %[t1] \n\t" /* add high word to c1, including carry */
"adcs %[c2], %[c2], #0 \n\t" /* add carry to c2 */
"adds %[i], #4 \n\t" /* i += 4 */
"cmp %[i], %[last_word] \n\t" /* i > (num_words - 1) (times 4)? */
"bgt 4f \n\t" /* if so, exit the loop */
"cmp %[i], %[k] \n\t" /* i <= k? */
"ble 3b \n\t" /* if so, continue looping */
"4: \n\t" /* end inner loop */
"str %[c0], [%[result], %[k]] \n\t" /* result[k] = c0 */
"mov %[c0], %[c1] \n\t" /* c0 = c1 */
"mov %[c1], %[c2] \n\t" /* c1 = c2 */
"movs %[c2], #0 \n\t" /* c2 = 0 */
"adds %[k], #4 \n\t" /* k += 4 */
"cmp %[k], %[last_word] \n\t" /* k <= (num_words - 1) (times 4) ? */
"ble 1b \n\t" /* if so, loop back, start with i = 0 */
"cmp %[k], %[last_word], lsl #1 \n\t" /* k <= (num_words * 2 - 2) (times 4) ? */
"ble 2b \n\t" /* if so, loop back, start with i = (k + 1) - num_words */
/* end outer loop */
"str %[c0], [%[result], %[k]] \n\t" /* result[num_words * 2 - 1] = c0 */
RESUME_SYNTAX
: [c0] "+r" (c0), [c1] "+r" (c1), [c2] "+r" (c2),
[k] "+r" (k), [i] "=&r" (i), [t0] "=&r" (t0), [t1] "=&r" (t1)
: [result] "r" (result), [left] "r" (left), [right] "r" (right),
[last_word] "r" ((num_words - 1) * 4)
: "cc", "memory"
);
#else /* Thumb-1 */
uint32_t r4, r5, r6, r7;
__asm__ volatile (
".syntax unified \n\t"
"subs %[r3], #1 \n\t" /* r3 = num_words - 1 */
"lsls %[r3], #2 \n\t" /* r3 = (num_words - 1) * 4 */
"mov r8, %[r3] \n\t" /* r8 = (num_words - 1) * 4 */
"lsls %[r3], #1 \n\t" /* r3 = (num_words - 1) * 8 */
"mov r9, %[r3] \n\t" /* r9 = (num_words - 1) * 8 */
"movs %[r3], #0 \n\t" /* c0 = 0 */
"movs %[r4], #0 \n\t" /* c1 = 0 */
"movs %[r5], #0 \n\t" /* c2 = 0 */
"movs %[r6], #0 \n\t" /* k = 0 */
"push {%[r0]} \n\t" /* keep result on the stack */
"1: \n\t" /* outer loop (k < num_words) */
"movs %[r7], #0 \n\t" /* r7 = i = 0 */
"b 3f \n\t"
"2: \n\t" /* outer loop (k >= num_words) */
"movs %[r7], %[r6] \n\t" /* r7 = k */
"mov %[r0], r8 \n\t" /* r0 = (num_words - 1) * 4 */
"subs %[r7], %[r0] \n\t" /* r7 = i = k - (num_words - 1) (times 4) */
"3: \n\t" /* inner loop */
"mov r10, %[r3] \n\t"
"mov r11, %[r4] \n\t"
"mov r12, %[r5] \n\t"
"mov r14, %[r6] \n\t"
"subs %[r0], %[r6], %[r7] \n\t" /* r0 = k - i */
"ldr %[r4], [%[r2], %[r0]] \n\t" /* r4 = right[k - i] */
"ldr %[r0], [%[r1], %[r7]] \n\t" /* r0 = left[i] */
"lsrs %[r3], %[r0], #16 \n\t" /* r3 = a1 */
"uxth %[r0], %[r0] \n\t" /* r0 = a0 */
"lsrs %[r5], %[r4], #16 \n\t" /* r5 = b1 */
"uxth %[r4], %[r4] \n\t" /* r4 = b0 */
"movs %[r6], %[r3] \n\t" /* r6 = a1 */
"muls %[r6], %[r5], %[r6] \n\t" /* r6 = a1 * b1 */
"muls %[r3], %[r4], %[r3] \n\t" /* r3 = b0 * a1 */
"muls %[r5], %[r0], %[r5] \n\t" /* r5 = a0 * b1 */
"muls %[r0], %[r4], %[r0] \n\t" /* r0 = a0 * b0 */
/* Add middle terms */
"lsls %[r4], %[r3], #16 \n\t"
"lsrs %[r3], %[r3], #16 \n\t"
"adds %[r0], %[r4] \n\t"
"adcs %[r6], %[r3] \n\t"
"lsls %[r4], %[r5], #16 \n\t"
"lsrs %[r5], %[r5], #16 \n\t"
"adds %[r0], %[r4] \n\t"
"adcs %[r6], %[r5] \n\t"
"mov %[r3], r10\n\t"
"mov %[r4], r11\n\t"
"mov %[r5], r12\n\t"
"adds %[r3], %[r0] \n\t" /* add low word to c0 */
"adcs %[r4], %[r6] \n\t" /* add high word to c1, including carry */
"movs %[r0], #0 \n\t" /* r0 = 0 (does not affect carry bit) */
"adcs %[r5], %[r0] \n\t" /* add carry to c2 */
"mov %[r6], r14\n\t" /* r6 = k */
"adds %[r7], #4 \n\t" /* i += 4 */
"cmp %[r7], r8 \n\t" /* i > (num_words - 1) (times 4)? */
"bgt 4f \n\t" /* if so, exit the loop */
"cmp %[r7], %[r6] \n\t" /* i <= k? */
"ble 3b \n\t" /* if so, continue looping */
"4: \n\t" /* end inner loop */
"ldr %[r0], [sp, #0] \n\t" /* r0 = result */
"str %[r3], [%[r0], %[r6]] \n\t" /* result[k] = c0 */
"mov %[r3], %[r4] \n\t" /* c0 = c1 */
"mov %[r4], %[r5] \n\t" /* c1 = c2 */
"movs %[r5], #0 \n\t" /* c2 = 0 */
"adds %[r6], #4 \n\t" /* k += 4 */
"cmp %[r6], r8 \n\t" /* k <= (num_words - 1) (times 4) ? */
"ble 1b \n\t" /* if so, loop back, start with i = 0 */
"cmp %[r6], r9 \n\t" /* k <= (num_words * 2 - 2) (times 4) ? */
"ble 2b \n\t" /* if so, loop back, with i = (k + 1) - num_words */
/* end outer loop */
"str %[r3], [%[r0], %[r6]] \n\t" /* result[num_words * 2 - 1] = c0 */
"pop {%[r0]} \n\t" /* pop result off the stack */
RESUME_SYNTAX
: [r3] "+l" (num_words), [r4] "=&l" (r4),
[r5] "=&l" (r5), [r6] "=&l" (r6), [r7] "=&l" (r7)
: [r0] "l" (result), [r1] "l" (left), [r2] "l" (right)
: "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory"
);
#endif
}
#define asm_mult 1
#endif
#if uECC_SQUARE_FUNC
#if !asm_square
uECC_VLI_API void uECC_vli_square(uECC_word_t *result,
const uECC_word_t *left,
wordcount_t num_words) {
#if (uECC_PLATFORM != uECC_arm_thumb)
uint32_t c0 = 0;
uint32_t c1 = 0;
uint32_t c2 = 0;
uint32_t k = 0;
uint32_t i, tt;
uint32_t t0, t1;
__asm__ volatile (
".syntax unified \n\t"
"1: \n\t" /* outer loop (k < num_words) */
"movs %[i], #0 \n\t" /* i = 0 */
"b 3f \n\t"
"2: \n\t" /* outer loop (k >= num_words) */
"movs %[i], %[k] \n\t" /* i = k */
"subs %[i], %[last_word] \n\t" /* i = k - (num_words - 1) (times 4) */
"3: \n\t" /* inner loop */
"subs %[tt], %[k], %[i] \n\t" /* tt = k-i */
"ldr %[t1], [%[left], %[tt]] \n\t" /* t1 = left[k - i] */
"ldr %[t0], [%[left], %[i]] \n\t" /* t0 = left[i] */
"umull %[t0], %[t1], %[t0], %[t1] \n\t" /* (t0, t1) = left[i] * right[k - i] */
"cmp %[i], %[tt] \n\t" /* (i < k - i) ? */
"bge 4f \n\t" /* if i >= k - i, skip */
"adds %[c0], %[c0], %[t0] \n\t" /* add low word to c0 */
"adcs %[c1], %[c1], %[t1] \n\t" /* add high word to c1, including carry */
"adcs %[c2], %[c2], #0 \n\t" /* add carry to c2 */
"4: \n\t"
"adds %[c0], %[c0], %[t0] \n\t" /* add low word to c0 */
"adcs %[c1], %[c1], %[t1] \n\t" /* add high word to c1, including carry */
"adcs %[c2], %[c2], #0 \n\t" /* add carry to c2 */
"adds %[i], #4 \n\t" /* i += 4 */
"cmp %[i], %[k] \n\t" /* i >= k? */
"bge 5f \n\t" /* if so, exit the loop */
"subs %[tt], %[k], %[i] \n\t" /* tt = k - i */
"cmp %[i], %[tt] \n\t" /* i <= k - i? */
"ble 3b \n\t" /* if so, continue looping */
"5: \n\t" /* end inner loop */
"str %[c0], [%[result], %[k]] \n\t" /* result[k] = c0 */
"mov %[c0], %[c1] \n\t" /* c0 = c1 */
"mov %[c1], %[c2] \n\t" /* c1 = c2 */
"movs %[c2], #0 \n\t" /* c2 = 0 */
"adds %[k], #4 \n\t" /* k += 4 */
"cmp %[k], %[last_word] \n\t" /* k <= (num_words - 1) (times 4) ? */
"ble 1b \n\t" /* if so, loop back, start with i = 0 */
"cmp %[k], %[last_word], lsl #1 \n\t" /* k <= (num_words * 2 - 2) (times 4) ? */
"ble 2b \n\t" /* if so, loop back, start with i = (k + 1) - num_words */
/* end outer loop */
"str %[c0], [%[result], %[k]] \n\t" /* result[num_words * 2 - 1] = c0 */
RESUME_SYNTAX
: [c0] "+r" (c0), [c1] "+r" (c1), [c2] "+r" (c2),
[k] "+r" (k), [i] "=&r" (i), [tt] "=&r" (tt), [t0] "=&r" (t0), [t1] "=&r" (t1)
: [result] "r" (result), [left] "r" (left), [last_word] "r" ((num_words - 1) * 4)
: "cc", "memory"
);
#else
uint32_t r3, r4, r5, r6, r7;
__asm__ volatile (
".syntax unified \n\t"
"subs %[r2], #1 \n\t" /* r2 = num_words - 1 */
"lsls %[r2], #2 \n\t" /* r2 = (num_words - 1) * 4 */
"mov r8, %[r2] \n\t" /* r8 = (num_words - 1) * 4 */
"lsls %[r2], #1 \n\t" /* r2 = (num_words - 1) * 8 */
"mov r9, %[r2] \n\t" /* r9 = (num_words - 1) * 8 */
"movs %[r2], #0 \n\t" /* c0 = 0 */
"movs %[r3], #0 \n\t" /* c1 = 0 */
"movs %[r4], #0 \n\t" /* c2 = 0 */
"movs %[r5], #0 \n\t" /* k = 0 */
"push {%[r0]} \n\t" /* keep result on the stack */
"1: \n\t" /* outer loop (k < num_words) */
"movs %[r6], #0 \n\t" /* r6 = i = 0 */
"b 3f \n\t"
"2: \n\t" /* outer loop (k >= num_words) */
"movs %[r6], %[r5] \n\t" /* r6 = k */
"mov %[r0], r8 \n\t" /* r0 = (num_words - 1) * 4 */
"subs %[r6], %[r0] \n\t" /* r6 = i = k - (num_words - 1) (times 4) */
"3: \n\t" /* inner loop */
"mov r10, %[r2] \n\t"
"mov r11, %[r3] \n\t"
"mov r12, %[r4] \n\t"
"mov r14, %[r5] \n\t"
"subs %[r7], %[r5], %[r6] \n\t" /* r7 = k - i */
"ldr %[r3], [%[r1], %[r7]] \n\t" /* r3 = left[k - i] */
"ldr %[r0], [%[r1], %[r6]] \n\t" /* r0 = left[i] */
"lsrs %[r2], %[r0], #16 \n\t" /* r2 = a1 */
"uxth %[r0], %[r0] \n\t" /* r0 = a0 */
"lsrs %[r4], %[r3], #16 \n\t" /* r4 = b1 */
"uxth %[r3], %[r3] \n\t" /* r3 = b0 */
"movs %[r5], %[r2] \n\t" /* r5 = a1 */
"muls %[r5], %[r4], %[r5] \n\t" /* r5 = a1 * b1 */
"muls %[r2], %[r3], %[r2] \n\t" /* r2 = b0 * a1 */
"muls %[r4], %[r0], %[r4] \n\t" /* r4 = a0 * b1 */
"muls %[r0], %[r3], %[r0] \n\t" /* r0 = a0 * b0 */
/* Add middle terms */
"lsls %[r3], %[r2], #16 \n\t"
"lsrs %[r2], %[r2], #16 \n\t"
"adds %[r0], %[r3] \n\t"
"adcs %[r5], %[r2] \n\t"
"lsls %[r3], %[r4], #16 \n\t"
"lsrs %[r4], %[r4], #16 \n\t"
"adds %[r0], %[r3] \n\t"
"adcs %[r5], %[r4] \n\t"
/* Add to acc, doubling if necessary */
"mov %[r2], r10\n\t"
"mov %[r3], r11\n\t"
"mov %[r4], r12\n\t"
"cmp %[r6], %[r7] \n\t" /* (i < k - i) ? */
"bge 4f \n\t" /* if i >= k - i, skip */
"movs %[r7], #0 \n\t" /* r7 = 0 */
"adds %[r2], %[r0] \n\t" /* add low word to c0 */
"adcs %[r3], %[r5] \n\t" /* add high word to c1, including carry */
"adcs %[r4], %[r7] \n\t" /* add carry to c2 */
"4: \n\t"
"movs %[r7], #0 \n\t" /* r7 = 0 */
"adds %[r2], %[r0] \n\t" /* add low word to c0 */
"adcs %[r3], %[r5] \n\t" /* add high word to c1, including carry */
"adcs %[r4], %[r7] \n\t" /* add carry to c2 */
"mov %[r5], r14\n\t" /* r5 = k */
"adds %[r6], #4 \n\t" /* i += 4 */
"cmp %[r6], %[r5] \n\t" /* i >= k? */
"bge 5f \n\t" /* if so, exit the loop */
"subs %[r7], %[r5], %[r6] \n\t" /* r7 = k - i */
"cmp %[r6], %[r7] \n\t" /* i <= k - i? */
"ble 3b \n\t" /* if so, continue looping */
"5: \n\t" /* end inner loop */
"ldr %[r0], [sp, #0] \n\t" /* r0 = result */
"str %[r2], [%[r0], %[r5]] \n\t" /* result[k] = c0 */
"mov %[r2], %[r3] \n\t" /* c0 = c1 */
"mov %[r3], %[r4] \n\t" /* c1 = c2 */
"movs %[r4], #0 \n\t" /* c2 = 0 */
"adds %[r5], #4 \n\t" /* k += 4 */
"cmp %[r5], r8 \n\t" /* k <= (num_words - 1) (times 4) ? */
"ble 1b \n\t" /* if so, loop back, start with i = 0 */
"cmp %[r5], r9 \n\t" /* k <= (num_words * 2 - 2) (times 4) ? */
"ble 2b \n\t" /* if so, loop back, with i = (k + 1) - num_words */
/* end outer loop */
"str %[r2], [%[r0], %[r5]] \n\t" /* result[num_words * 2 - 1] = c0 */
"pop {%[r0]} \n\t" /* pop result off the stack */
RESUME_SYNTAX
: [r2] "+l" (num_words), [r3] "=&l" (r3), [r4] "=&l" (r4),
[r5] "=&l" (r5), [r6] "=&l" (r6), [r7] "=&l" (r7)
: [r0] "l" (result), [r1] "l" (left)
: "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory"
);
#endif
}
#define asm_square 1
#endif
#endif /* uECC_SQUARE_FUNC */
#endif /* _UECC_ASM_ARM_H_ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,132 @@
import os
c, link, asm, utils = emk.module("c", "link", "asm", "utils")
default_compile_flags = ["-fvisibility=hidden", "-Wall", "-Wextra", "-Wshadow", "-Werror", "-Wno-missing-field-initializers", "-Wno-unused-parameter", \
"-Wno-comment", "-Wno-unused", "-Wno-unknown-pragmas"]
default_link_flags = []
opt_flags = {"dbg":["-g"], "std":["-O2"], "max":["-O3"], "small":["-Os"]}
opt_link_flags = {"dbg":[], "std":[], "max":[], "small":[]}
c_flags = ["-std=c99"]
cxx_flags = ["-std=c++11", "-Wno-reorder", "-fno-rtti", "-fno-exceptions"]
c_link_flags = []
cxx_link_flags = ["-fno-rtti", "-fno-exceptions"]
if "root" in emk.options:
root = emk.options["root"]
else:
root = "/"
def setup_build_dir():
build_arch = None
if "arch" in emk.options:
build_arch = emk.options["arch"]
elif not emk.cleaning:
build_arch = "osx"
emk.options["arch"] = build_arch
opt_level = None
if "opt" in emk.options:
level = emk.options["opt"]
if level in opt_flags:
opt_level = level
else:
emk.log.warning("Unknown optimization level '%s'" % (level))
elif not emk.cleaning:
opt_level = "dbg"
emk.options["opt"] = opt_level
dirs = ["__build__"]
if build_arch:
dirs.append(build_arch)
if opt_level:
dirs.append(opt_level)
emk.build_dir = os.path.join(*dirs)
def setup_osx():
global c
global link
flags = [("-arch", "x86_64"), "-fno-common", "-Wnewline-eof"]
c.flags.extend(flags)
c.cxx.flags += ["-stdlib=libc++"]
link.cxx.flags += ["-stdlib=libc++"]
link_flags = [("-arch", "x86_64")]
link.local_flags.extend(link_flags)
def setup_avr():
global c
global link
c.compiler = c.GccCompiler(root + "Projects/avr-tools/bin/avr-")
c.flags += ["-mmcu=atmega256rfr2", "-ffunction-sections", "-fdata-sections"]
link.linker = link.GccLinker(root + "Projects/avr-tools/bin/avr-")
link.flags += ["-mmcu=atmega256rfr2", "-mrelax", "-Wl,--gc-sections"]
link.strip = True
def setup_arm_thumb():
global c
global link
global asm
global utils
asm.assembler = asm.GccAssembler(root + "cross/arm_cortex/bin/arm-none-eabi-")
c.compiler = c.GccCompiler(root + "cross/arm_cortex/bin/arm-none-eabi-")
link.linker = link.GccLinker(root + "cross/arm_cortex/bin/arm-none-eabi-")
c.flags.extend(["-mcpu=cortex-m0", "-mthumb", "-ffunction-sections", "-fdata-sections", "-fno-builtin-fprintf", "-fno-builtin-printf"])
c.defines["LPC11XX"] = 1
link.local_flags.extend(["-mcpu=cortex-m0", "-mthumb", "-nostartfiles", "-nostdlib", "-Wl,--gc-sections"])
link.local_flags.extend(["-Tflash.lds", "-L" + root + "Projects/lpc11xx/core", root + "Projects/lpc11xx/core/" + emk.build_dir + "/board_cstartup.o"])
link.local_syslibs += ["gcc"]
link.depdirs += [root + "Projects/lpc11xx/stdlib"]
def do_objcopy(produces, requires):
utils.call(root + "cross/arm_cortex/bin/arm-none-eabi-objcopy", "-O", "binary", requires[0], produces[0])
def handle_exe(path):
emk.depend(path, root + "Projects/lpc11xx/core/" + emk.build_dir + "/board_cstartup.o")
emk.rule(do_objcopy, path + ".bin", path, cwd_safe=True, ex_safe=True)
emk.autobuild(path + ".bin")
link.exe_funcs.append(handle_exe)
link.strip = True
emk.recurse(root + "Projects/lpc11xx/core")
def setup_linux_rpi():
global c
global link
c.compiler = c.GccCompiler("/Volumes/xtools/arm-none-linux-gnueabi/bin/arm-none-linux-gnueabi-")
link.linker = link.GccLinker("/Volumes/xtools/arm-none-linux-gnueabi/bin/arm-none-linux-gnueabi-")
c.flags.extend(["-fomit-frame-pointer"])
setup_build_dir()
setup_funcs = {"osx":setup_osx, "avr":setup_avr, "arm_thumb":setup_arm_thumb, "rpi": setup_linux_rpi}
if not emk.cleaning:
build_arch = emk.options["arch"]
opt_level = emk.options["opt"]
c.flags.extend(default_compile_flags)
c.flags.extend(opt_flags[opt_level])
c.c.flags.extend(c_flags)
c.cxx.flags.extend(cxx_flags)
link.local_flags.extend(default_link_flags)
link.local_flags.extend(opt_link_flags[opt_level])
link.c.local_flags.extend(c_link_flags)
link.cxx.local_flags.extend(cxx_link_flags)
c.include_dirs.append("$:proj:$")
if build_arch in setup_funcs:
setup_funcs[build_arch]()
else:
raise emk.BuildError("Unknown target arch '%s'" % (build_arch))
c.defines["TARGET_ARCH_" + build_arch.upper()] = 1

@ -0,0 +1,3 @@
c, link = emk.module("c", "link")
emk.subdir("test")

@ -0,0 +1,80 @@
#include <uECC.h>
static int RNG(uint8_t *dest, unsigned size) {
// Use the least-significant bits from the ADC for an unconnected pin (or connected to a source of
// random noise). This can take a long time to generate random data if the result of analogRead(0)
// doesn't change very frequently.
while (size) {
uint8_t val = 0;
for (unsigned i = 0; i < 8; ++i) {
int init = analogRead(0);
int count = 0;
while (analogRead(0) == init) {
++count;
}
if (count == 0) {
val = (val << 1) | (init & 0x01);
} else {
val = (val << 1) | (count & 0x01);
}
}
*dest = val;
++dest;
--size;
}
// NOTE: it would be a good idea to hash the resulting random data using SHA-256 or similar.
return 1;
}
void setup() {
Serial.begin(115200);
Serial.print("Testing ecc\n");
uECC_set_rng(&RNG);
}
void loop() {
const struct uECC_Curve_t * curve = uECC_secp160r1();
uint8_t private1[21];
uint8_t private2[21];
uint8_t public1[40];
uint8_t public2[40];
uint8_t secret1[20];
uint8_t secret2[20];
unsigned long a = millis();
uECC_make_key(public1, private1, curve);
unsigned long b = millis();
Serial.print("Made key 1 in "); Serial.println(b-a);
a = millis();
uECC_make_key(public2, private2, curve);
b = millis();
Serial.print("Made key 2 in "); Serial.println(b-a);
a = millis();
int r = uECC_shared_secret(public2, private1, secret1, curve);
b = millis();
Serial.print("Shared secret 1 in "); Serial.println(b-a);
if (!r) {
Serial.print("shared_secret() failed (1)\n");
return;
}
a = millis();
r = uECC_shared_secret(public1, private2, secret2, curve);
b = millis();
Serial.print("Shared secret 2 in "); Serial.println(b-a);
if (!r) {
Serial.print("shared_secret() failed (2)\n");
return;
}
if (memcmp(secret1, secret2, 20) != 0) {
Serial.print("Shared secrets are not identical!\n");
} else {
Serial.print("Shared secrets are identical\n");
}
}

@ -0,0 +1,9 @@
name=micro-ecc
version=1.0.0
author=Kenneth MacKay
maintainer=Kenneth MacKay
sentence=uECC
paragraph=A small and fast ECDH and ECDSA implementation for 8-bit, 32-bit, and 64-bit processors.
category=Other
url=https://github.com/kmackay/micro-ecc
architectures=*

@ -0,0 +1,94 @@
/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */
#ifndef _UECC_PLATFORM_SPECIFIC_H_
#define _UECC_PLATFORM_SPECIFIC_H_
#include "types.h"
#if (defined(_WIN32) || defined(_WIN64))
/* Windows */
// use pragma syntax to prevent tweaking the linker script for getting CryptXYZ function
#pragma comment(lib, "crypt32.lib")
#pragma comment(lib, "advapi32.lib")
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <wincrypt.h>
static int default_RNG(uint8_t *dest, unsigned size) {
HCRYPTPROV prov;
if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
return 0;
}
CryptGenRandom(prov, size, (BYTE *)dest);
CryptReleaseContext(prov, 0);
return 1;
}
#define default_RNG_defined 1
#elif defined(unix) || defined(__linux__) || defined(__unix__) || defined(__unix) || \
(defined(__APPLE__) && defined(__MACH__)) || defined(uECC_POSIX)
/* Some POSIX-like system with /dev/urandom or /dev/random. */
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#ifndef O_CLOEXEC
#define O_CLOEXEC 0
#endif
static int default_RNG(uint8_t *dest, unsigned size) {
int fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC);
if (fd == -1) {
fd = open("/dev/random", O_RDONLY | O_CLOEXEC);
if (fd == -1) {
return 0;
}
}
char *ptr = (char *)dest;
size_t left = size;
while (left > 0) {
ssize_t bytes_read = read(fd, ptr, left);
if (bytes_read <= 0) { // read failed
close(fd);
return 0;
}
left -= bytes_read;
ptr += bytes_read;
}
close(fd);
return 1;
}
#define default_RNG_defined 1
#elif defined(RIOT_VERSION)
#include <random.h>
static int default_RNG(uint8_t *dest, unsigned size) {
random_bytes(dest, size);
return 1;
}
#define default_RNG_defined 1
#elif defined(NRF52_SERIES)
#include "app_error.h"
#include "nrf_crypto_rng.h"
static int default_RNG(uint8_t *dest, unsigned size)
{
// make sure to call nrf_crypto_init and nrf_crypto_rng_init first
ret_code_t ret_code = nrf_crypto_rng_vector_generate(dest, size);
return (ret_code == NRF_SUCCESS) ? 1 : 0;
}
#define default_RNG_defined 1
#endif /* platform */
#endif /* _UECC_PLATFORM_SPECIFIC_H_ */

@ -0,0 +1,188 @@
#!/usr/bin/env python
import sys
if len(sys.argv) < 2:
print "Provide the integer size in 32-bit words"
sys.exit(1)
size = int(sys.argv[1])
full_rows = size // 3
init_size = size % 3
if init_size == 0:
full_rows = full_rows - 1
init_size = 3
def emit(line, *args):
s = '"' + line + r' \n\t"'
print s % args
rx = [3, 4, 5]
ry = [6, 7, 8]
#### set up registers
emit("add r0, %s", (size - init_size) * 4) # move z
emit("add r2, %s", (size - init_size) * 4) # move y
emit("ldmia r1!, {%s}", ", ".join(["r%s" % (rx[i]) for i in xrange(init_size)]))
emit("ldmia r2!, {%s}", ", ".join(["r%s" % (ry[i]) for i in xrange(init_size)]))
print ""
if init_size == 1:
emit("umull r9, r10, r3, r6")
emit("stmia r0!, {r9, r10}")
else:
#### first two multiplications of initial block
emit("umull r11, r12, r3, r6")
emit("stmia r0!, {r11}")
print ""
emit("mov r10, #0")
emit("umull r11, r9, r3, r7")
emit("adds r12, r12, r11")
emit("adc r9, r9, #0")
emit("umull r11, r14, r4, r6")
emit("adds r12, r12, r11")
emit("adcs r9, r9, r14")
emit("adc r10, r10, #0")
emit("stmia r0!, {r12}")
print ""
#### rest of initial block, with moving accumulator registers
acc = [9, 10, 11, 12, 14]
if init_size == 3:
emit("mov r%s, #0", acc[2])
for i in xrange(0, 3):
emit("umull r%s, r%s, r%s, r%s", acc[3], acc[4], rx[i], ry[2 - i])
emit("adds r%s, r%s, r%s", acc[0], acc[0], acc[3])
emit("adcs r%s, r%s, r%s", acc[1], acc[1], acc[4])
emit("adc r%s, r%s, #0", acc[2], acc[2])
emit("stmia r0!, {r%s}", acc[0])
print ""
acc = acc[1:] + acc[:1]
emit("mov r%s, #0", acc[2])
for i in xrange(0, 2):
emit("umull r%s, r%s, r%s, r%s", acc[3], acc[4], rx[i + 1], ry[2 - i])
emit("adds r%s, r%s, r%s", acc[0], acc[0], acc[3])
emit("adcs r%s, r%s, r%s", acc[1], acc[1], acc[4])
emit("adc r%s, r%s, #0", acc[2], acc[2])
emit("stmia r0!, {r%s}", acc[0])
print ""
acc = acc[1:] + acc[:1]
emit("umull r%s, r%s, r%s, r%s", acc[3], acc[4], rx[init_size-1], ry[init_size-1])
emit("adds r%s, r%s, r%s", acc[0], acc[0], acc[3])
emit("adc r%s, r%s, r%s", acc[1], acc[1], acc[4])
emit("stmia r0!, {r%s}", acc[0])
emit("stmia r0!, {r%s}", acc[1])
print ""
#### reset y and z pointers
emit("sub r0, %s", (2 * init_size + 3) * 4)
emit("sub r2, %s", (init_size + 3) * 4)
#### load y registers
emit("ldmia r2!, {%s}", ", ".join(["r%s" % (ry[i]) for i in xrange(3)]))
#### load additional x registers
if init_size != 3:
emit("ldmia r1!, {%s}", ", ".join(["r%s" % (rx[i]) for i in xrange(init_size, 3)]))
print ""
prev_size = init_size
for row in xrange(full_rows):
emit("umull r11, r12, r3, r6")
emit("stmia r0!, {r11}")
print ""
emit("mov r10, #0")
emit("umull r11, r9, r3, r7")
emit("adds r12, r12, r11")
emit("adc r9, r9, #0")
emit("umull r11, r14, r4, r6")
emit("adds r12, r12, r11")
emit("adcs r9, r9, r14")
emit("adc r10, r10, #0")
emit("stmia r0!, {r12}")
print ""
acc = [9, 10, 11, 12, 14]
emit("mov r%s, #0", acc[2])
for i in xrange(0, 3):
emit("umull r%s, r%s, r%s, r%s", acc[3], acc[4], rx[i], ry[2 - i])
emit("adds r%s, r%s, r%s", acc[0], acc[0], acc[3])
emit("adcs r%s, r%s, r%s", acc[1], acc[1], acc[4])
emit("adc r%s, r%s, #0", acc[2], acc[2])
emit("stmia r0!, {r%s}", acc[0])
print ""
acc = acc[1:] + acc[:1]
#### now we need to start shifting x and loading from z
x_regs = [3, 4, 5]
for r in xrange(0, prev_size):
x_regs = x_regs[1:] + x_regs[:1]
emit("ldmia r1!, {r%s}", x_regs[2])
emit("mov r%s, #0", acc[2])
for i in xrange(0, 3):
emit("umull r%s, r%s, r%s, r%s", acc[3], acc[4], x_regs[i], ry[2 - i])
emit("adds r%s, r%s, r%s", acc[0], acc[0], acc[3])
emit("adcs r%s, r%s, r%s", acc[1], acc[1], acc[4])
emit("adc r%s, r%s, #0", acc[2], acc[2])
emit("ldr r%s, [r0]", acc[3]) # load stored value from initial block, and add to accumulator
emit("adds r%s, r%s, r%s", acc[0], acc[0], acc[3])
emit("adcs r%s, r%s, #0", acc[1], acc[1])
emit("adc r%s, r%s, #0", acc[2], acc[2])
emit("stmia r0!, {r%s}", acc[0])
print ""
acc = acc[1:] + acc[:1]
# done shifting x, start shifting y
y_regs = [6, 7, 8]
for r in xrange(0, prev_size):
y_regs = y_regs[1:] + y_regs[:1]
emit("ldmia r2!, {r%s}", y_regs[2])
emit("mov r%s, #0", acc[2])
for i in xrange(0, 3):
emit("umull r%s, r%s, r%s, r%s", acc[3], acc[4], x_regs[i], y_regs[2 - i])
emit("adds r%s, r%s, r%s", acc[0], acc[0], acc[3])
emit("adcs r%s, r%s, r%s", acc[1], acc[1], acc[4])
emit("adc r%s, r%s, #0", acc[2], acc[2])
emit("ldr r%s, [r0]", acc[3]) # load stored value from initial block, and add to accumulator
emit("adds r%s, r%s, r%s", acc[0], acc[0], acc[3])
emit("adcs r%s, r%s, #0", acc[1], acc[1])
emit("adc r%s, r%s, #0", acc[2], acc[2])
emit("stmia r0!, {r%s}", acc[0])
print ""
acc = acc[1:] + acc[:1]
# done both shifts, do remaining corner
emit("mov r%s, #0", acc[2])
for i in xrange(0, 2):
emit("umull r%s, r%s, r%s, r%s", acc[3], acc[4], x_regs[i + 1], y_regs[2 - i])
emit("adds r%s, r%s, r%s", acc[0], acc[0], acc[3])
emit("adcs r%s, r%s, r%s", acc[1], acc[1], acc[4])
emit("adc r%s, r%s, #0", acc[2], acc[2])
emit("stmia r0!, {r%s}", acc[0])
print ""
acc = acc[1:] + acc[:1]
emit("umull r%s, r%s, r%s, r%s", acc[3], acc[4], x_regs[2], y_regs[2])
emit("adds r%s, r%s, r%s", acc[0], acc[0], acc[3])
emit("adc r%s, r%s, r%s", acc[1], acc[1], acc[4])
emit("stmia r0!, {r%s}", acc[0])
emit("stmia r0!, {r%s}", acc[1])
print ""
prev_size = prev_size + 3
if row < full_rows - 1:
#### reset x, y and z pointers
emit("sub r0, %s", (2 * prev_size + 3) * 4)
emit("sub r1, %s", prev_size * 4)
emit("sub r2, %s", (prev_size + 3) * 4)
#### load x and y registers
emit("ldmia r1!, {%s}", ",".join(["r%s" % (rx[i]) for i in xrange(3)]))
emit("ldmia r2!, {%s}", ",".join(["r%s" % (ry[i]) for i in xrange(3)]))
print ""

@ -0,0 +1,203 @@
#!/usr/bin/env python
import sys
if len(sys.argv) < 2:
print "Provide the integer size in bytes"
sys.exit(1)
size = int(sys.argv[1])
full_rows = size // 10
init_size = size % 10
if init_size == 0:
full_rows = full_rows - 1
init_size = 10
def rx(i):
return i + 2
def ry(i):
return i + 12
def emit(line, *args):
s = '"' + line + r' \n\t"'
print s % args
#### set up registers
emit("adiw r30, %s", size - init_size) # move z
emit("adiw r28, %s", size - init_size) # move y
for i in xrange(init_size):
emit("ld r%s, x+", rx(i))
for i in xrange(init_size):
emit("ld r%s, y+", ry(i))
emit("ldi r25, 0")
print ""
if init_size == 1:
emit("mul r2, r12")
emit("st z+, r0")
emit("st z+, r1")
else:
#### first two multiplications of initial block
emit("ldi r23, 0")
emit("mul r2, r12")
emit("st z+, r0")
emit("mov r22, r1")
print ""
emit("ldi r24, 0")
emit("mul r2, r13")
emit("add r22, r0")
emit("adc r23, r1")
emit("mul r3, r12")
emit("add r22, r0")
emit("adc r23, r1")
emit("adc r24, r25")
emit("st z+, r22")
print ""
#### rest of initial block, with moving accumulator registers
acc = [23, 24, 22]
for r in xrange(2, init_size):
emit("ldi r%s, 0", acc[2])
for i in xrange(0, r+1):
emit("mul r%s, r%s", rx(i), ry(r - i))
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, r25", acc[2])
emit("st z+, r%s", acc[0])
print ""
acc = acc[1:] + acc[:1]
for r in xrange(1, init_size-1):
emit("ldi r%s, 0", acc[2])
for i in xrange(0, init_size-r):
emit("mul r%s, r%s", rx(r+i), ry((init_size-1) - i))
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, r25", acc[2])
emit("st z+, r%s", acc[0])
print ""
acc = acc[1:] + acc[:1]
emit("mul r%s, r%s", rx(init_size-1), ry(init_size-1))
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("st z+, r%s", acc[0])
emit("st z+, r%s", acc[1])
print ""
#### reset y and z pointers
emit("sbiw r30, %s", 2 * init_size + 10)
emit("sbiw r28, %s", init_size + 10)
#### load y registers
for i in xrange(10):
emit("ld r%s, y+", ry(i))
#### load additional x registers
for i in xrange(init_size, 10):
emit("ld r%s, x+", rx(i))
print ""
prev_size = init_size
for row in xrange(full_rows):
#### do x = 0-9, y = 0-9 multiplications
emit("ldi r23, 0")
emit("mul r2, r12")
emit("st z+, r0")
emit("mov r22, r1")
print ""
emit("ldi r24, 0")
emit("mul r2, r13")
emit("add r22, r0")
emit("adc r23, r1")
emit("mul r3, r12")
emit("add r22, r0")
emit("adc r23, r1")
emit("adc r24, r25")
emit("st z+, r22")
print ""
acc = [23, 24, 22]
for r in xrange(2, 10):
emit("ldi r%s, 0", acc[2])
for i in xrange(0, r+1):
emit("mul r%s, r%s", rx(i), ry(r - i))
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, r25", acc[2])
emit("st z+, r%s", acc[0])
print ""
acc = acc[1:] + acc[:1]
#### now we need to start shifting x and loading from z
x_regs = [2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
for r in xrange(0, prev_size):
x_regs = x_regs[1:] + x_regs[:1]
emit("ld r%s, x+", x_regs[9]) # load next byte of left
emit("ldi r%s, 0", acc[2])
for i in xrange(0, 10):
emit("mul r%s, r%s", x_regs[i], ry(9 - i))
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, r25", acc[2])
emit("ld r0, z") # load stored value from initial block, and add to accumulator (note z does not increment)
emit("add r%s, r0", acc[0])
emit("adc r%s, r25", acc[1])
emit("adc r%s, r25", acc[2])
emit("st z+, r%s", acc[0]) # store next byte (z increments)
print ""
acc = acc[1:] + acc[:1]
# done shifting x, start shifting y
y_regs = [12, 13, 14, 15, 16, 17, 18, 19, 20, 21]
for r in xrange(0, prev_size):
y_regs = y_regs[1:] + y_regs[:1]
emit("ld r%s, y+", y_regs[9]) # load next byte of right
emit("ldi r%s, 0", acc[2])
for i in xrange(0, 10):
emit("mul r%s, r%s", x_regs[i], y_regs[9 -i])
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, r25", acc[2])
emit("ld r0, z") # load stored value from initial block, and add to accumulator (note z does not increment)
emit("add r%s, r0", acc[0])
emit("adc r%s, r25", acc[1])
emit("adc r%s, r25", acc[2])
emit("st z+, r%s", acc[0]) # store next byte (z increments)
print ""
acc = acc[1:] + acc[:1]
# done both shifts, do remaining corner
for r in xrange(1, 9):
emit("ldi r%s, 0", acc[2])
for i in xrange(0, 10-r):
emit("mul r%s, r%s", x_regs[r+i], y_regs[9 - i])
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, r25", acc[2])
emit("st z+, r%s", acc[0])
print ""
acc = acc[1:] + acc[:1]
emit("mul r%s, r%s", x_regs[9], y_regs[9])
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("st z+, r%s", acc[0])
emit("st z+, r%s", acc[1])
print ""
prev_size = prev_size + 10
if row < full_rows - 1:
#### reset x, y and z pointers
emit("sbiw r30, %s", 2 * prev_size + 10)
emit("sbiw r28, %s", prev_size + 10)
emit("sbiw r26, %s", prev_size)
#### load x and y registers
for i in xrange(10):
emit("ld r%s, x+", rx(i))
emit("ld r%s, y+", ry(i))
print ""
emit("eor r1, r1")

@ -0,0 +1,143 @@
#!/usr/bin/env python
import sys
if len(sys.argv) < 2:
print "Provide the integer size in bytes"
sys.exit(1)
size = int(sys.argv[1])
def lhi(i):
return i + 2
def rhi(i):
return i + 6
left_lo = [10, 11, 12, 13]
right_lo = [14, 15, 16, 17]
def llo(i):
return left_lo[i]
def rlo(i):
return right_lo[i]
def emit(line, *args):
s = '"' + line + r' \n\t"'
print s % args
def update_low():
global left_lo
global right_lo
left_lo = left_lo[1:] + left_lo[:1]
right_lo = right_lo[1:] + right_lo[:1]
emit("ld r%s, x+", left_lo[3])
emit("ld r%s, y+", right_lo[3])
accum = [19, 20, 21]
def acc(i):
return accum[i]
def rotate_acc():
global accum
accum = accum[1:] + accum[:1]
# Load high values
for i in xrange(4):
emit("ld r%s, x+", lhi(i))
emit("ld r%s, y+", rhi(i))
emit("sbiw r26, %s", size + 4)
emit("sbiw r28, %s", size + 4)
emit("sbiw r30, %s", size)
# Load low values
for i in xrange(4):
emit("ld r%s, x+", llo(i))
emit("ld r%s, y+", rlo(i))
print ""
# Compute initial triangles
emit("mul r%s, r%s", lhi(0), rlo(0))
emit("mov r%s, r0", acc(0))
emit("mov r%s, r1", acc(1))
emit("ldi r%s, 0", acc(2))
emit("ld r0, z")
emit("add r%s, r0", acc(0))
emit("adc r%s, r25", acc(1))
emit("mul r%s, r%s", rhi(0), llo(0))
emit("add r%s, r0", acc(0))
emit("adc r%s, r1", acc(1))
emit("adc r%s, r25", acc(2))
emit("st z+, r%s", acc(0))
print ""
rotate_acc()
for i in xrange(1, 4):
emit("ldi r%s, 0", acc(2))
emit("ld r0, z")
emit("add r%s, r0", acc(0))
emit("adc r%s, r25", acc(1))
for j in xrange(i + 1):
emit("mul r%s, r%s", lhi(j), rlo(i-j))
emit("add r%s, r0", acc(0))
emit("adc r%s, r1", acc(1))
emit("adc r%s, r25", acc(2))
emit("mul r%s, r%s", rhi(j), llo(i-j))
emit("add r%s, r0", acc(0))
emit("adc r%s, r1", acc(1))
emit("adc r%s, r25", acc(2))
emit("st z+, r%s", acc(0))
print ""
rotate_acc()
# Compute rows overlapping old block
for i in xrange(4, size):
emit("ldi r%s, 0", acc(2))
emit("ld r0, z")
emit("add r%s, r0", acc(0))
emit("adc r%s, r25", acc(1))
update_low()
for j in xrange(4):
emit("mul r%s, r%s", lhi(j), rlo(3-j))
emit("add r%s, r0", acc(0))
emit("adc r%s, r1", acc(1))
emit("adc r%s, r25", acc(2))
emit("mul r%s, r%s", rhi(j), llo(3-j))
emit("add r%s, r0", acc(0))
emit("adc r%s, r1", acc(1))
emit("adc r%s, r25", acc(2))
emit("st z+, r%s", acc(0))
print ""
rotate_acc()
# Compute new triangle
left_combined = [llo(1), llo(2), llo(3), lhi(0), lhi(1), lhi(2), lhi(3)]
right_combined = [rlo(1), rlo(2), rlo(3), rhi(0), rhi(1), rhi(2), rhi(3)]
def left(i):
return left_combined[i]
def right(i):
return right_combined[i]
for i in xrange(6):
emit("ldi r%s, 0", acc(2))
for j in xrange(7 - i):
emit("mul r%s, r%s", left(i+j), right(6-j))
emit("add r%s, r0", acc(0))
emit("adc r%s, r1", acc(1))
emit("adc r%s, r25", acc(2))
emit("st z+, r%s", acc(0))
print ""
rotate_acc()
emit("mul r%s, r%s", left(6), right(6))
emit("add r%s, r0", acc(0))
emit("adc r%s, r1", acc(1))
emit("st z+, r%s", acc(0))
emit("st z+, r%s", acc(1))
emit("adiw r26, 4")
emit("adiw r28, 4")

@ -0,0 +1,242 @@
#!/usr/bin/env python
import sys
if len(sys.argv) < 2:
print "Provide the integer size in 32-bit words"
sys.exit(1)
size = int(sys.argv[1])
if size > 8:
print "This script doesn't work with integer size %s due to laziness" % (size)
sys.exit(1)
init_size = 0
if size > 6:
init_size = size - 6
def emit(line, *args):
s = '"' + line + r' \n\t"'
print s % args
def mulacc(acc, r1, r2):
if size <= 6:
emit("umull r1, r14, r%s, r%s", r1, r2)
emit("adds r%s, r%s, r1", acc[0], acc[0])
emit("adcs r%s, r%s, r14", acc[1], acc[1])
emit("adc r%s, r%s, #0", acc[2], acc[2])
else:
emit("mov r14, r%s", acc[1])
emit("umlal r%s, r%s, r%s, r%s", acc[0], acc[1], r1, r2)
emit("cmp r14, r%s", acc[1])
emit("it hi")
emit("adchi r%s, r%s, #0", acc[2], acc[2])
r = [2, 3, 4, 5, 6, 7]
s = size - init_size
if init_size == 1:
emit("ldmia r1!, {r2}")
emit("add r1, %s", (size - init_size * 2) * 4)
emit("ldmia r1!, {r5}")
emit("add r0, %s", (size - init_size) * 4)
emit("umull r8, r9, r2, r5")
emit("stmia r0!, {r8, r9}")
emit("sub r0, %s", (size + init_size) * 4)
emit("sub r1, %s", (size) * 4)
print ""
elif init_size == 2:
emit("ldmia r1!, {r2, r3}")
emit("add r1, %s", (size - init_size * 2) * 4)
emit("ldmia r1!, {r5, r6}")
emit("add r0, %s", (size - init_size) * 4)
print ""
emit("umull r8, r9, r2, r5")
emit("stmia r0!, {r8}")
print ""
emit("umull r12, r10, r2, r6")
emit("adds r9, r9, r12")
emit("adc r10, r10, #0")
emit("stmia r0!, {r9}")
print ""
emit("umull r8, r9, r3, r6")
emit("adds r10, r10, r8")
emit("adc r11, r9, #0")
emit("stmia r0!, {r10, r11}")
print ""
emit("sub r0, %s", (size + init_size) * 4)
emit("sub r1, %s", (size) * 4)
# load input words
emit("ldmia r1!, {%s}", ", ".join(["r%s" % (r[i]) for i in xrange(s)]))
print ""
emit("umull r11, r12, r2, r2")
emit("stmia r0!, {r11}")
print ""
emit("mov r9, #0")
emit("umull r10, r11, r2, r3")
emit("adds r12, r12, r10")
emit("adcs r8, r11, #0")
emit("adc r9, r9, #0")
emit("adds r12, r12, r10")
emit("adcs r8, r8, r11")
emit("adc r9, r9, #0")
emit("stmia r0!, {r12}")
print ""
emit("mov r10, #0")
emit("umull r11, r12, r2, r4")
emit("adds r11, r11, r11")
emit("adcs r12, r12, r12")
emit("adc r10, r10, #0")
emit("adds r8, r8, r11")
emit("adcs r9, r9, r12")
emit("adc r10, r10, #0")
emit("umull r11, r12, r3, r3")
emit("adds r8, r8, r11")
emit("adcs r9, r9, r12")
emit("adc r10, r10, #0")
emit("stmia r0!, {r8}")
print ""
acc = [8, 9, 10]
old_acc = [11, 12]
for i in xrange(3, s):
emit("mov r%s, #0", old_acc[1])
tmp = [acc[1], acc[2]]
acc = [acc[0], old_acc[0], old_acc[1]]
old_acc = tmp
# gather non-equal words
emit("umull r%s, r%s, r%s, r%s", acc[0], acc[1], r[0], r[i])
for j in xrange(1, (i+1)//2):
mulacc(acc, r[j], r[i-j])
# multiply by 2
emit("adds r%s, r%s, r%s", acc[0], acc[0], acc[0])
emit("adcs r%s, r%s, r%s", acc[1], acc[1], acc[1])
emit("adc r%s, r%s, r%s", acc[2], acc[2], acc[2])
# add equal word (if any)
if ((i+1) % 2) != 0:
mulacc(acc, r[i//2], r[i//2])
# add old accumulator
emit("adds r%s, r%s, r%s", acc[0], acc[0], old_acc[0])
emit("adcs r%s, r%s, r%s", acc[1], acc[1], old_acc[1])
emit("adc r%s, r%s, #0", acc[2], acc[2])
# store
emit("stmia r0!, {r%s}", acc[0])
print ""
regs = list(r)
for i in xrange(init_size):
regs = regs[1:] + regs[:1]
emit("ldmia r1!, {r%s}", regs[5])
for limit in [4, 5]:
emit("mov r%s, #0", old_acc[1])
tmp = [acc[1], acc[2]]
acc = [acc[0], old_acc[0], old_acc[1]]
old_acc = tmp
# gather non-equal words
emit("umull r%s, r%s, r%s, r%s", acc[0], acc[1], regs[0], regs[limit])
for j in xrange(1, (limit+1)//2):
mulacc(acc, regs[j], regs[limit-j])
emit("ldr r14, [r0]") # load stored value from initial block, and add to accumulator
emit("adds r%s, r%s, r14", acc[0], acc[0])
emit("adcs r%s, r%s, #0", acc[1], acc[1])
emit("adc r%s, r%s, #0", acc[2], acc[2])
# multiply by 2
emit("adds r%s, r%s, r%s", acc[0], acc[0], acc[0])
emit("adcs r%s, r%s, r%s", acc[1], acc[1], acc[1])
emit("adc r%s, r%s, r%s", acc[2], acc[2], acc[2])
# add equal word
if limit == 4:
mulacc(acc, regs[2], regs[2])
# add old accumulator
emit("adds r%s, r%s, r%s", acc[0], acc[0], old_acc[0])
emit("adcs r%s, r%s, r%s", acc[1], acc[1], old_acc[1])
emit("adc r%s, r%s, #0", acc[2], acc[2])
# store
emit("stmia r0!, {r%s}", acc[0])
print ""
for i in xrange(1, s-3):
emit("mov r%s, #0", old_acc[1])
tmp = [acc[1], acc[2]]
acc = [acc[0], old_acc[0], old_acc[1]]
old_acc = tmp
# gather non-equal words
emit("umull r%s, r%s, r%s, r%s", acc[0], acc[1], regs[i], regs[s - 1])
for j in xrange(1, (s-i)//2):
mulacc(acc, regs[i+j], regs[s - 1 - j])
# multiply by 2
emit("adds r%s, r%s, r%s", acc[0], acc[0], acc[0])
emit("adcs r%s, r%s, r%s", acc[1], acc[1], acc[1])
emit("adc r%s, r%s, r%s", acc[2], acc[2], acc[2])
# add equal word (if any)
if ((s-i) % 2) != 0:
mulacc(acc, regs[i + (s-i)//2], regs[i + (s-i)//2])
# add old accumulator
emit("adds r%s, r%s, r%s", acc[0], acc[0], old_acc[0])
emit("adcs r%s, r%s, r%s", acc[1], acc[1], old_acc[1])
emit("adc r%s, r%s, #0", acc[2], acc[2])
# store
emit("stmia r0!, {r%s}", acc[0])
print ""
acc = acc[1:] + acc[:1]
emit("mov r%s, #0", acc[2])
emit("umull r1, r%s, r%s, r%s", old_acc[1], regs[s - 3], regs[s - 1])
emit("adds r1, r1, r1")
emit("adcs r%s, r%s, r%s", old_acc[1], old_acc[1], old_acc[1])
emit("adc r%s, r%s, #0", acc[2], acc[2])
emit("adds r%s, r%s, r1", acc[0], acc[0])
emit("adcs r%s, r%s, r%s", acc[1], acc[1], old_acc[1])
emit("adc r%s, r%s, #0", acc[2], acc[2])
emit("umull r1, r%s, r%s, r%s", old_acc[1], regs[s - 2], regs[s - 2])
emit("adds r%s, r%s, r1", acc[0], acc[0])
emit("adcs r%s, r%s, r%s", acc[1], acc[1], old_acc[1])
emit("adc r%s, r%s, #0", acc[2], acc[2])
emit("stmia r0!, {r%s}", acc[0])
print ""
acc = acc[1:] + acc[:1]
emit("mov r%s, #0", acc[2])
emit("umull r1, r%s, r%s, r%s", old_acc[1], regs[s - 2], regs[s - 1])
emit("adds r1, r1, r1")
emit("adcs r%s, r%s, r%s", old_acc[1], old_acc[1], old_acc[1])
emit("adc r%s, r%s, #0", acc[2], acc[2])
emit("adds r%s, r%s, r1", acc[0], acc[0])
emit("adcs r%s, r%s, r%s", acc[1], acc[1], old_acc[1])
emit("adc r%s, r%s, #0", acc[2], acc[2])
emit("stmia r0!, {r%s}", acc[0])
print ""
acc = acc[1:] + acc[:1]
emit("umull r1, r%s, r%s, r%s", old_acc[1], regs[s - 1], regs[s - 1])
emit("adds r%s, r%s, r1", acc[0], acc[0])
emit("adcs r%s, r%s, r%s", acc[1], acc[1], old_acc[1])
emit("stmia r0!, {r%s}", acc[0])
emit("stmia r0!, {r%s}", acc[1])

@ -0,0 +1,327 @@
#!/usr/bin/env python
import sys
if len(sys.argv) < 2:
print "Provide the integer size in bytes"
sys.exit(1)
size = int(sys.argv[1])
if size > 40:
print "This script doesn't work with integer size %s due to laziness" % (size)
sys.exit(1)
init_size = size - 20
if size < 20:
init_size = 0
def rg(i):
return i + 2
def lo(i):
return i + 2
def hi(i):
return i + 12
def emit(line, *args):
s = '"' + line + r' \n\t"'
print s % args
#### set up registers
zero = "r25"
emit("ldi %s, 0", zero) # zero register
if init_size > 0:
emit("movw r28, r26") # y = x
h = (init_size + 1)//2
for i in xrange(h):
emit("ld r%s, x+", lo(i))
emit("adiw r28, %s", size - init_size) # move y to other end
for i in xrange(h):
emit("ld r%s, y+", hi(i))
emit("adiw r30, %s", size - init_size) # move z
if init_size == 1:
emit("mul %s, %s", lo(0), hi(0))
emit("st z+, r0")
emit("st z+, r1")
else:
#### first one
print ""
emit("ldi r23, 0")
emit("mul %s, %s", lo(0), hi(0))
emit("st z+, r0")
emit("mov r22, r1")
print ""
#### rest of initial block, with moving accumulator registers
acc = [22, 23, 24]
for r in xrange(1, h):
emit("ldi r%s, 0", acc[2])
for i in xrange(0, (r+2)//2):
emit("mul r%s, r%s", lo(i), hi(r - i))
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, %s", acc[2], zero)
emit("st z+, r%s", acc[0])
print ""
acc = acc[1:] + acc[:1]
lo_r = range(2, 2 + h)
hi_r = range(12, 12 + h)
# now we need to start loading more from the high end
for r in xrange(h, init_size):
hi_r = hi_r[1:] + hi_r[:1]
emit("ld r%s, y+", hi_r[h-1])
emit("ldi r%s, 0", acc[2])
for i in xrange(0, (r+2)//2):
emit("mul r%s, r%s", lo(i), hi_r[h - 1 - i])
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, %s", acc[2], zero)
emit("st z+, r%s", acc[0])
print ""
acc = acc[1:] + acc[:1]
# loaded all of the high end bytes; now need to start loading the rest of the low end
for r in xrange(1, init_size-h):
lo_r = lo_r[1:] + lo_r[:1]
emit("ld r%s, x+", lo_r[h-1])
emit("ldi r%s, 0", acc[2])
for i in xrange(0, (init_size+1 - r)//2):
emit("mul r%s, r%s", lo_r[i], hi_r[h - 1 - i])
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, %s", acc[2], zero)
emit("st z+, r%s", acc[0])
print ""
acc = acc[1:] + acc[:1]
lo_r = lo_r[1:] + lo_r[:1]
emit("ld r%s, x+", lo_r[h-1])
# now we have loaded everything, and we just need to finish the last corner
for r in xrange(init_size-h, init_size-1):
emit("ldi r%s, 0", acc[2])
for i in xrange(0, (init_size+1 - r)//2):
emit("mul r%s, r%s", lo_r[i], hi_r[h - 1 - i])
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, %s", acc[2], zero)
emit("st z+, r%s", acc[0])
print ""
acc = acc[1:] + acc[:1]
lo_r = lo_r[1:] + lo_r[:1] # make the indexing easy
emit("mul r%s, r%s", lo_r[0], hi_r[h - 1])
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("st z+, r%s", acc[0])
emit("st z+, r%s", acc[1])
print ""
emit("sbiw r26, %s", init_size) # reset x
emit("sbiw r30, %s", size + init_size) # reset z
# TODO you could do more rows of size 20 here if your integers are larger than 40 bytes
s = size - init_size
for i in xrange(s):
emit("ld r%s, x+", rg(i))
#### first few columns
# NOTE: this is only valid if size >= 3
print ""
emit("ldi r23, 0")
emit("mul r%s, r%s", rg(0), rg(0))
emit("st z+, r0")
emit("mov r22, r1")
print ""
emit("ldi r24, 0")
emit("mul r%s, r%s", rg(0), rg(1))
emit("add r22, r0")
emit("adc r23, r1")
emit("adc r24, %s", zero)
emit("add r22, r0")
emit("adc r23, r1")
emit("adc r24, %s", zero)
emit("st z+, r22")
print ""
emit("ldi r22, 0")
emit("mul r%s, r%s", rg(0), rg(2))
emit("add r23, r0")
emit("adc r24, r1")
emit("adc r22, %s", zero)
emit("add r23, r0")
emit("adc r24, r1")
emit("adc r22, %s", zero)
emit("mul r%s, r%s", rg(1), rg(1))
emit("add r23, r0")
emit("adc r24, r1")
emit("adc r22, %s", zero)
emit("st z+, r23")
print ""
acc = [23, 24, 22]
old_acc = [28, 29]
for i in xrange(3, s):
emit("ldi r%s, 0", old_acc[1])
tmp = [acc[1], acc[2]]
acc = [acc[0], old_acc[0], old_acc[1]]
old_acc = tmp
# gather non-equal words
emit("mul r%s, r%s", rg(0), rg(i))
emit("mov r%s, r0", acc[0])
emit("mov r%s, r1", acc[1])
for j in xrange(1, (i+1)//2):
emit("mul r%s, r%s", rg(j), rg(i-j))
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, %s", acc[2], zero)
# multiply by 2
emit("lsl r%s", acc[0])
emit("rol r%s", acc[1])
emit("rol r%s", acc[2])
# add equal word (if any)
if ((i+1) % 2) != 0:
emit("mul r%s, r%s", rg(i//2), rg(i//2))
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, %s", acc[2], zero)
# add old accumulator
emit("add r%s, r%s", acc[0], old_acc[0])
emit("adc r%s, r%s", acc[1], old_acc[1])
emit("adc r%s, %s", acc[2], zero)
# store
emit("st z+, r%s", acc[0])
print ""
regs = range(2, 22)
for i in xrange(init_size):
regs = regs[1:] + regs[:1]
emit("ld r%s, x+", regs[19])
for limit in [18, 19]:
emit("ldi r%s, 0", old_acc[1])
tmp = [acc[1], acc[2]]
acc = [acc[0], old_acc[0], old_acc[1]]
old_acc = tmp
# gather non-equal words
emit("mul r%s, r%s", regs[0], regs[limit])
emit("mov r%s, r0", acc[0])
emit("mov r%s, r1", acc[1])
for j in xrange(1, (limit+1)//2):
emit("mul r%s, r%s", regs[j], regs[limit-j])
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, %s", acc[2], zero)
emit("ld r0, z") # load stored value from initial block, and add to accumulator (note z does not increment)
emit("add r%s, r0", acc[0])
emit("adc r%s, r25", acc[1])
emit("adc r%s, r25", acc[2])
# multiply by 2
emit("lsl r%s", acc[0])
emit("rol r%s", acc[1])
emit("rol r%s", acc[2])
# add equal word
if limit == 18:
emit("mul r%s, r%s", regs[9], regs[9])
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, %s", acc[2], zero)
# add old accumulator
emit("add r%s, r%s", acc[0], old_acc[0])
emit("adc r%s, r%s", acc[1], old_acc[1])
emit("adc r%s, %s", acc[2], zero)
# store
emit("st z+, r%s", acc[0])
print ""
for i in xrange(1, s-3):
emit("ldi r%s, 0", old_acc[1])
tmp = [acc[1], acc[2]]
acc = [acc[0], old_acc[0], old_acc[1]]
old_acc = tmp
# gather non-equal words
emit("mul r%s, r%s", regs[i], regs[s - 1])
emit("mov r%s, r0", acc[0])
emit("mov r%s, r1", acc[1])
for j in xrange(1, (s-i)//2):
emit("mul r%s, r%s", regs[i+j], regs[s - 1 - j])
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, %s", acc[2], zero)
# multiply by 2
emit("lsl r%s", acc[0])
emit("rol r%s", acc[1])
emit("rol r%s", acc[2])
# add equal word (if any)
if ((s-i) % 2) != 0:
emit("mul r%s, r%s", regs[i + (s-i)//2], regs[i + (s-i)//2])
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, %s", acc[2], zero)
# add old accumulator
emit("add r%s, r%s", acc[0], old_acc[0])
emit("adc r%s, r%s", acc[1], old_acc[1])
emit("adc r%s, %s", acc[2], zero)
# store
emit("st z+, r%s", acc[0])
print ""
acc = acc[1:] + acc[:1]
emit("ldi r%s, 0", acc[2])
emit("mul r%s, r%s", regs[17], regs[19])
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, %s", acc[2], zero)
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, %s", acc[2], zero)
emit("mul r%s, r%s", regs[18], regs[18])
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, %s", acc[2], zero)
emit("st z+, r%s", acc[0])
print ""
acc = acc[1:] + acc[:1]
emit("ldi r%s, 0", acc[2])
emit("mul r%s, r%s", regs[18], regs[19])
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, %s", acc[2], zero)
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, %s", acc[2], zero)
emit("st z+, r%s", acc[0])
print ""
emit("mul r%s, r%s", regs[19], regs[19])
emit("add r%s, r0", acc[1])
emit("adc r%s, r1", acc[2])
emit("st z+, r%s", acc[1])
emit("st z+, r%s", acc[2])
emit("eor r1, r1")

@ -0,0 +1,128 @@
/* Copyright 2020, Kenneth MacKay. Licensed under the BSD 2-clause license. */
#include "uECC.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
const char* private_key;
const char* public_key;
const char* k;
const char* hash;
const char* r;
const char* s;
} Test;
Test secp256k1_tests[] = {
{
"ebb2c082fd7727890a28ac82f6bdf97bad8de9f5d7c9028692de1a255cad3e0f",
"779dd197a5df977ed2cf6cb31d82d43328b790dc6b3b7d4437a427bd5847dfcde94b724a555b6d017bb7607c3e3281daf5b1699d6ef4124975c9237b917d426f",
"49a0d7b786ec9cde0d0721d72804befd06571c974b191efb42ecf322ba9ddd9a",
"4b688df40bcedbe641ddb16ff0a1842d9c67ea1c3bf63f3e0471baa664531d1a",
"241097efbf8b63bf145c8961dbdf10c310efbb3b2676bbc0f8b08505c9e2f795",
"021006b7838609339e8b415a7f9acb1b661828131aef1ecbc7955dfb01f3ca0e"
},
};
extern int uECC_sign_with_k(const uint8_t *private_key,
const uint8_t *message_hash,
unsigned hash_size,
const uint8_t *k,
uint8_t *signature,
uECC_Curve curve);
void vli_print(uint8_t *vli, unsigned int size) {
for(unsigned i=0; i<size; ++i) {
printf("%02X ", (unsigned)vli[i]);
}
printf("\n");
}
void strtobytes(const char* str, uint8_t* bytes, int count) {
for (int c = 0; c < count; ++c) {
if (sscanf(str, "%2hhx", &bytes[c]) != 1) {
printf("Failed to read string to bytes");
exit(1);
}
str += 2;
}
}
int run(Test* tests, int num_tests, uECC_Curve curve) {
uint8_t private[32] = {0};
uint8_t public[64] = {0};
uint8_t k[32] = {0};
uint8_t hash[32] = {0};
uint8_t r[32] = {0};
uint8_t s[32] = {0};
uint8_t signature[64] = {0};
int result;
int i;
int private_key_size;
int public_key_size;
int all_success = 1;
private_key_size = uECC_curve_private_key_size(curve);
public_key_size = uECC_curve_public_key_size(curve);
for (i = 0; i < num_tests; ++i) {
strtobytes(tests[i].private_key, private, private_key_size);
strtobytes(tests[i].public_key, public, public_key_size);
strtobytes(tests[i].k, k, private_key_size);
strtobytes(tests[i].hash, hash, private_key_size);
strtobytes(tests[i].r, r, private_key_size);
strtobytes(tests[i].s, s, private_key_size);
result = uECC_sign_with_k(private, hash, private_key_size, k, signature, curve);
if (!result) {
all_success = 0;
printf(" Sign failed for test %d\n", i);
}
if (result) {
if (memcmp(signature, r, private_key_size) != 0) {
all_success = 0;
printf(" Got incorrect r for test %d\n", i);
printf(" Expected: ");
vli_print(r, private_key_size);
printf(" Calculated: ");
vli_print(signature, private_key_size);
}
if (memcmp(signature + private_key_size, s, private_key_size) != 0) {
all_success = 0;
printf(" Got incorrect s for test %d\n", i);
printf(" Expected: ");
vli_print(s, private_key_size);
printf(" Calculated: ");
vli_print(signature + private_key_size, private_key_size);
}
result = uECC_verify(public, hash, private_key_size, signature, curve);
if (!result) {
printf(" Verify failed for test %d\n", i);
}
}
}
return all_success;
}
#define RUN_TESTS(curve) \
printf(#curve ":\n"); \
if (run(curve##_tests, sizeof(curve##_tests) / sizeof(curve##_tests[0]), uECC_##curve()) ) { \
printf(" All passed\n"); \
} else { \
printf(" Failed\n"); \
}
int main() {
#if uECC_SUPPORTS_secp256k1
RUN_TESTS(secp256k1)
#endif
return 0;
}

@ -0,0 +1,4 @@
c, link = emk.module("c", "link")
link.depdirs += [
"$:proj:$"
]

@ -0,0 +1,338 @@
/* Copyright 2020, Kenneth MacKay. Licensed under the BSD 2-clause license. */
#include "uECC.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
const char* k;
const char* Q;
int success;
} Test;
Test secp160r1_tests[] = {
/* Note, I couldn't find any test vectors for secp160r1 online, so these are just
generated on my desktop using uECC. */
{
"000000000000000000000000000000000000000000",
"00000000000000000000000000000000000000000000000000000000000000000000000000000000",
0
},
{
"000000000000000000000000000000000000000001",
"00000000000000000000000000000000000000000000000000000000000000000000000000000000",
0
},
{
"000000000000000000000000000000000000000002",
"02F997F33C5ED04C55D3EDF8675D3E92E8F46686F083A323482993E9440E817E21CFB7737DF8797B",
1
},
{
"000000000000000000000000000000000000000003",
"7B76FF541EF363F2DF13DE1650BD48DAA958BC59C915CA790D8C8877B55BE0079D12854FFE9F6F5A",
1
},
{ /* n - 4 */
"0100000000000000000001F4C8F927AED3CA752253",
"B4041D8683BE99F0AFE01C307B1AD4C100CF2A88C0CD35127BE0F73FF99F338B350B5A42864112F7",
1
},
{ /* n - 3 */
"0100000000000000000001F4C8F927AED3CA752254",
"7B76FF541EF363F2DF13DE1650BD48DAA958BC5936EA3586F27377884AA41FF862ED7AAF816090A5",
1
},
{ /* n - 2 */
"0100000000000000000001F4C8F927AED3CA752255",
"00000000000000000000000000000000000000000000000000000000000000000000000000000000",
0
},
{ /* n - 1 */
"0100000000000000000001F4C8F927AED3CA752256",
"00000000000000000000000000000000000000000000000000000000000000000000000000000000",
0
},
{ /* n */
"0100000000000000000001F4C8F927AED3CA752257",
"00000000000000000000000000000000000000000000000000000000000000000000000000000000",
0
},
};
Test secp192r1_tests[] = {
{
"000000000000000000000000000000000000000000000000",
"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
0
},
{
"000000000000000000000000000000000000000000000001",
"188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF101207192B95FFC8DA78631011ED6B24CDD573F977A11E794811",
0
},
{
"000000000000000000000000000000000000000000000002",
"DAFEBF5828783F2AD35534631588A3F629A70FB16982A888DD6BDA0D993DA0FA46B27BBC141B868F59331AFA5C7E93AB",
1
},
{
"000000000000000000000000000000000000000000000003",
"76E32A2557599E6EDCD283201FB2B9AADFD0D359CBB263DA782C37E372BA4520AA62E0FED121D49EF3B543660CFD05FD",
1
},
{ /* n - 4 */
"FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D2282D",
"35433907297CC378B0015703374729D7A4FE46647084E4BA5D9B667B0DECA3CFE15C534F88932B0DDAC764CEE24C41CD",
1
},
{ /* n - 3 */
"FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D2282E",
"76E32A2557599E6EDCD283201FB2B9AADFD0D359CBB263DA87D3C81C8D45BADF559D1F012EDE2B600C4ABC99F302FA02",
1
},
{ /* n - 2 */
"FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D2282F",
"DAFEBF5828783F2AD35534631588A3F629A70FB16982A888229425F266C25F05B94D8443EBE4796FA6CCE505A3816C54",
0
},
{ /* n - 1 */
"FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22830",
"188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012F8E6D46A003725879CEFEE1294DB32298C06885EE186B7EE",
0
},
{ /* n */
"FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831",
"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
0
},
};
Test secp224r1_tests[] = {
{
"00000000000000000000000000000000000000000000000000000000",
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
0
},
{
"00000000000000000000000000000000000000000000000000000001",
"B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34",
0
},
{
"00000000000000000000000000000000000000000000000000000002",
"706A46DC76DCB76798E60E6D89474788D16DC18032D268FD1A704FA61C2B76A7BC25E7702A704FA986892849FCA629487ACF3709D2E4E8BB",
1
},
{
"00000000000000000000000000000000000000000000000000000003",
"DF1B1D66A551D0D31EFF822558B9D2CC75C2180279FE0D08FD896D04A3F7F03CADD0BE444C0AA56830130DDF77D317344E1AF3591981A925",
1
},
{ /* n - 4 */
"FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A39",
"AE99FEEBB5D26945B54892092A8AEE02912930FA41CD114E40447301FB7DA7F5F13A43B81774373C879CD32D6934C05FA758EEB14FCFAB38",
1
},
{ /* n - 3 */
"FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3A",
"DF1B1D66A551D0D31EFF822558B9D2CC75C2180279FE0D08FD896D045C080FC3522F41BBB3F55A97CFECF21F882CE8CBB1E50CA6E67E56DC",
1
},
{ /* n - 2 */
"FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3B",
"706A46DC76DCB76798E60E6D89474788D16DC18032D268FD1A704FA6E3D4895843DA188FD58FB0567976D7B50359D6B78530C8F62D1B1746",
0
},
{ /* n - 1 */
"FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3C",
"B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D2142C89C774A08DC04B3DD201932BC8A5EA5F8B89BBB2A7E667AFF81CD",
0
},
{ /* n */
"FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D",
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
0
},
};
Test secp256r1_tests[] = {
{
"0000000000000000000000000000000000000000000000000000000000000000",
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
0
},
{
"0000000000000000000000000000000000000000000000000000000000000001",
"6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C2964FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
0
},
{
"0000000000000000000000000000000000000000000000000000000000000002",
"7CF27B188D034F7E8A52380304B51AC3C08969E277F21B35A60B48FC4766997807775510DB8ED040293D9AC69F7430DBBA7DADE63CE982299E04B79D227873D1",
1
},
{
"0000000000000000000000000000000000000000000000000000000000000003",
"5ECBE4D1A6330A44C8F7EF951D4BF165E6C6B721EFADA985FB41661BC6E7FD6C8734640C4998FF7E374B06CE1A64A2ECD82AB036384FB83D9A79B127A27D5032",
1
},
{ /* n - 4 */
"FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC63254D",
"E2534A3532D08FBBA02DDE659EE62BD0031FE2DB785596EF509302446B0308521F0EA8A4B39CC339E62011A02579D289B103693D0CF11FFAA3BD3DC0E7B12739",
1
},
{ /* n - 3 */
"FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC63254E",
"5ECBE4D1A6330A44C8F7EF951D4BF165E6C6B721EFADA985FB41661BC6E7FD6C78CB9BF2B6670082C8B4F931E59B5D1327D54FCAC7B047C265864ED85D82AFCD",
1
},
{ /* n - 2 */
"FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC63254F",
"7CF27B188D034F7E8A52380304B51AC3C08969E277F21B35A60B48FC47669978F888AAEE24712FC0D6C26539608BCF244582521AC3167DD661FB4862DD878C2E",
0
},
{ /* n - 1 */
"FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632550",
"6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296B01CBD1C01E58065711814B583F061E9D431CCA994CEA1313449BF97C840AE0A",
0
},
{ /* n */
"FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
0
},
};
Test secp256k1_tests[] = {
{
"0000000000000000000000000000000000000000000000000000000000000000",
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
0
},
{
"0000000000000000000000000000000000000000000000000000000000000001",
"79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8",
0
},
{
"0000000000000000000000000000000000000000000000000000000000000002",
"C6047F9441ED7D6D3045406E95C07CD85C778E4B8CEF3CA7ABAC09B95C709EE51AE168FEA63DC339A3C58419466CEAEEF7F632653266D0E1236431A950CFE52A",
1
},
{
"0000000000000000000000000000000000000000000000000000000000000003",
"F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9388F7B0F632DE8140FE337E62A37F3566500A99934C2231B6CB9FD7584B8E672",
1
},
{ /* n - 4 */
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD036413D",
"E493DBF1C10D80F3581E4904930B1404CC6C13900EE0758474FA94ABE8C4CD13AE1266C15F2BAA48A9BD1DF6715AEBB7269851CC404201BF30168422B88C630D",
1
},
{ /* n - 3 */
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD036413E",
"F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9C77084F09CD217EBF01CC819D5C80CA99AFF5666CB3DDCE4934602897B4715BD",
1
},
{ /* n - 2 */
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD036413F",
"C6047F9441ED7D6D3045406E95C07CD85C778E4B8CEF3CA7ABAC09B95C709EE5E51E970159C23CC65C3A7BE6B99315110809CD9ACD992F1EDC9BCE55AF301705",
0
},
{ /* n - 1 */
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140",
"79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798B7C52588D95C3B9AA25B0403F1EEF75702E84BB7597AABE663B82F6F04EF2777",
0
},
{ /* n */
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141",
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
0
},
};
void vli_print(uint8_t *vli, unsigned int size) {
for(unsigned i=0; i<size; ++i) {
printf("%02X ", (unsigned)vli[i]);
}
printf("\n");
}
void strtobytes(const char* str, uint8_t* bytes, int count) {
for (int c = 0; c < count; ++c) {
if (sscanf(str, "%2hhx", &bytes[c]) != 1) {
printf("Failed to read string to bytes");
exit(1);
}
str += 2;
}
}
int run(Test* tests, int num_tests, uECC_Curve curve) {
uint8_t private[32] = {0};
uint8_t public[64] = {0};
uint8_t expected[64] = {0};
int result;
int i;
int private_key_size;
int public_key_size;
int all_success = 1;
private_key_size = uECC_curve_private_key_size(curve);
public_key_size = uECC_curve_public_key_size(curve);
for (i = 0; i < num_tests; ++i) {
strtobytes(tests[i].k, private, private_key_size);
result = uECC_compute_public_key(private, public, curve);
if (result != tests[i].success) {
all_success = 0;
printf(" Got unexpected result from test %d: %d\n", i, result);
}
if (result) {
strtobytes(tests[i].Q, expected, public_key_size);
if (memcmp(public, expected, public_key_size) != 0) {
all_success = 0;
printf(" Got incorrect public key for test %d\n", i);
printf(" Expected: ");
vli_print(expected, public_key_size);
printf(" Calculated: ");
vli_print(public, public_key_size);
}
}
}
return all_success;
}
#define RUN_TESTS(curve) \
printf(#curve ":\n"); \
if (run(curve##_tests, sizeof(curve##_tests) / sizeof(curve##_tests[0]), uECC_##curve()) ) { \
printf(" All passed\n"); \
} else { \
printf(" Failed\n"); \
}
int main() {
#if uECC_SUPPORTS_secp160r1
RUN_TESTS(secp160r1)
#endif
#if uECC_SUPPORTS_secp192r1
RUN_TESTS(secp192r1)
#endif
#if uECC_SUPPORTS_secp224r1
RUN_TESTS(secp224r1)
#endif
#if uECC_SUPPORTS_secp256r1
RUN_TESTS(secp256r1)
#endif
#if uECC_SUPPORTS_secp256k1
RUN_TESTS(secp256k1)
#endif
return 0;
}

@ -0,0 +1,79 @@
/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */
#include "uECC.h"
#include <stdio.h>
#include <string.h>
#ifndef uECC_TEST_NUMBER_OF_ITERATIONS
#define uECC_TEST_NUMBER_OF_ITERATIONS 256
#endif
void vli_print(char *str, uint8_t *vli, unsigned int size) {
printf("%s ", str);
for(unsigned i=0; i<size; ++i) {
printf("%02X ", (unsigned)vli[i]);
}
printf("\n");
}
int main() {
uint8_t public[64];
uint8_t private[32];
uint8_t compressed_point[33];
uint8_t decompressed_point[64];
int i;
int c;
const struct uECC_Curve_t * curves[5];
int num_curves = 0;
#if uECC_SUPPORTS_secp160r1
curves[num_curves++] = uECC_secp160r1();
#endif
#if uECC_SUPPORTS_secp192r1
curves[num_curves++] = uECC_secp192r1();
#endif
#if uECC_SUPPORTS_secp224r1
curves[num_curves++] = uECC_secp224r1();
#endif
#if uECC_SUPPORTS_secp256r1
curves[num_curves++] = uECC_secp256r1();
#endif
#if uECC_SUPPORTS_secp256k1
curves[num_curves++] = uECC_secp256k1();
#endif
printf("Testing compression and decompression of %d random EC points\n",
uECC_TEST_NUMBER_OF_ITERATIONS);
for (c = 0; c < num_curves; ++c) {
for (i = 0; i < uECC_TEST_NUMBER_OF_ITERATIONS; ++i) {
printf(".");
fflush(stdout);
memset(public, 0, sizeof(public));
memset(decompressed_point, 0, sizeof(decompressed_point));
/* Generate arbitrary EC point (public) on Curve */
if (!uECC_make_key(public, private, curves[c])) {
printf("uECC_make_key() failed\n");
continue;
}
/* compress and decompress point */
uECC_compress(public, compressed_point, curves[c]);
uECC_decompress(compressed_point, decompressed_point, curves[c]);
if (memcmp(public, decompressed_point, sizeof(public)) != 0) {
printf("Original and decompressed points are not identical!\n");
vli_print("Original point = ", public, sizeof(public));
vli_print("Compressed point = ", compressed_point, sizeof(compressed_point));
vli_print("Decompressed point = ", decompressed_point, sizeof(decompressed_point));
}
}
printf("\n");
}
return 0;
}

@ -0,0 +1,81 @@
/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */
#include "uECC.h"
#include <stdio.h>
#include <string.h>
void vli_print(char *str, uint8_t *vli, unsigned int size) {
printf("%s ", str);
for(unsigned i=0; i<size; ++i) {
printf("%02X ", (unsigned)vli[i]);
}
printf("\n");
}
int main() {
int i;
int success;
uint8_t private[32];
uint8_t public[64];
uint8_t public_computed[64];
int c;
const struct uECC_Curve_t * curves[5];
int num_curves = 0;
#if uECC_SUPPORTS_secp160r1
curves[num_curves++] = uECC_secp160r1();
#endif
#if uECC_SUPPORTS_secp192r1
curves[num_curves++] = uECC_secp192r1();
#endif
#if uECC_SUPPORTS_secp224r1
curves[num_curves++] = uECC_secp224r1();
#endif
#if uECC_SUPPORTS_secp256r1
curves[num_curves++] = uECC_secp256r1();
#endif
#if uECC_SUPPORTS_secp256k1
curves[num_curves++] = uECC_secp256k1();
#endif
printf("Testing 256 random private key pairs\n");
for (c = 0; c < num_curves; ++c) {
for (i = 0; i < 256; ++i) {
printf(".");
fflush(stdout);
memset(public, 0, sizeof(public));
memset(public_computed, 0, sizeof(public_computed));
if (!uECC_make_key(public, private, curves[c])) {
printf("uECC_make_key() failed\n");
continue;
}
if (!uECC_compute_public_key(private, public_computed, curves[c])) {
printf("uECC_compute_public_key() failed\n");
}
if (memcmp(public, public_computed, sizeof(public)) != 0) {
printf("Computed and provided public keys are not identical!\n");
vli_print("Computed public key = ", public_computed, sizeof(public_computed));
vli_print("Provided public key = ", public, sizeof(public));
vli_print("Private key = ", private, sizeof(private));
}
}
printf("\n");
printf("Testing private key = 0\n");
memset(private, 0, sizeof(private));
success = uECC_compute_public_key(private, public_computed, curves[c]);
if (success) {
printf("uECC_compute_public_key() should have failed\n");
}
printf("\n");
}
return 0;
}

@ -0,0 +1,90 @@
/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */
#include "uECC.h"
#include <stdio.h>
#include <string.h>
void vli_print(uint8_t *vli, unsigned int size) {
for(unsigned i=0; i<size; ++i) {
printf("%02X ", (unsigned)vli[i]);
}
}
int main() {
int i, c;
uint8_t private1[32] = {0};
uint8_t private2[32] = {0};
uint8_t public1[64] = {0};
uint8_t public2[64] = {0};
uint8_t secret1[32] = {0};
uint8_t secret2[32] = {0};
const struct uECC_Curve_t * curves[5];
int num_curves = 0;
#if uECC_SUPPORTS_secp160r1
curves[num_curves++] = uECC_secp160r1();
#endif
#if uECC_SUPPORTS_secp192r1
curves[num_curves++] = uECC_secp192r1();
#endif
#if uECC_SUPPORTS_secp224r1
curves[num_curves++] = uECC_secp224r1();
#endif
#if uECC_SUPPORTS_secp256r1
curves[num_curves++] = uECC_secp256r1();
#endif
#if uECC_SUPPORTS_secp256k1
curves[num_curves++] = uECC_secp256k1();
#endif
printf("Testing 256 random private key pairs\n");
for (c = 0; c < num_curves; ++c) {
for (i = 0; i < 256; ++i) {
printf(".");
fflush(stdout);
if (!uECC_make_key(public1, private1, curves[c]) ||
!uECC_make_key(public2, private2, curves[c])) {
printf("uECC_make_key() failed\n");
return 1;
}
if (!uECC_shared_secret(public2, private1, secret1, curves[c])) {
printf("shared_secret() failed (1)\n");
return 1;
}
if (!uECC_shared_secret(public1, private2, secret2, curves[c])) {
printf("shared_secret() failed (2)\n");
return 1;
}
if (memcmp(secret1, secret2, sizeof(secret1)) != 0) {
printf("Shared secrets are not identical!\n");
printf("Private key 1 = ");
vli_print(private1, 32);
printf("\n");
printf("Private key 2 = ");
vli_print(private2, 32);
printf("\n");
printf("Public key 1 = ");
vli_print(public1, 64);
printf("\n");
printf("Public key 2 = ");
vli_print(public2, 64);
printf("\n");
printf("Shared secret 1 = ");
vli_print(secret1, 32);
printf("\n");
printf("Shared secret 2 = ");
vli_print(secret2, 32);
printf("\n");
}
}
printf("\n");
}
return 0;
}

@ -0,0 +1,59 @@
/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */
#include "uECC.h"
#include <stdio.h>
#include <string.h>
int main() {
int i, c;
uint8_t private[32] = {0};
uint8_t public[64] = {0};
uint8_t hash[32] = {0};
uint8_t sig[64] = {0};
const struct uECC_Curve_t * curves[5];
int num_curves = 0;
#if uECC_SUPPORTS_secp160r1
curves[num_curves++] = uECC_secp160r1();
#endif
#if uECC_SUPPORTS_secp192r1
curves[num_curves++] = uECC_secp192r1();
#endif
#if uECC_SUPPORTS_secp224r1
curves[num_curves++] = uECC_secp224r1();
#endif
#if uECC_SUPPORTS_secp256r1
curves[num_curves++] = uECC_secp256r1();
#endif
#if uECC_SUPPORTS_secp256k1
curves[num_curves++] = uECC_secp256k1();
#endif
printf("Testing 256 signatures\n");
for (c = 0; c < num_curves; ++c) {
for (i = 0; i < 256; ++i) {
printf(".");
fflush(stdout);
if (!uECC_make_key(public, private, curves[c])) {
printf("uECC_make_key() failed\n");
return 1;
}
memcpy(hash, public, sizeof(hash));
if (!uECC_sign(private, hash, sizeof(hash), sig, curves[c])) {
printf("uECC_sign() failed\n");
return 1;
}
if (!uECC_verify(public, hash, sizeof(hash), sig, curves[c])) {
printf("uECC_verify() failed\n");
return 1;
}
}
printf("\n");
}
return 0;
}

@ -0,0 +1,93 @@
/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */
#include "uECC.h"
#include <stdio.h>
#include <string.h>
#define SHA256_BLOCK_LENGTH 64
#define SHA256_DIGEST_LENGTH 32
typedef struct SHA256_CTX {
uint32_t state[8];
uint64_t bitcount;
uint8_t buffer[SHA256_BLOCK_LENGTH];
} SHA256_CTX;
extern void SHA256_Init(SHA256_CTX *ctx);
extern void SHA256_Update(SHA256_CTX *ctx, const uint8_t *message, size_t message_size);
extern void SHA256_Final(uint8_t digest[SHA256_DIGEST_LENGTH], SHA256_CTX *ctx);
typedef struct SHA256_HashContext {
uECC_HashContext uECC;
SHA256_CTX ctx;
} SHA256_HashContext;
static void init_SHA256(const uECC_HashContext *base) {
SHA256_HashContext *context = (SHA256_HashContext *)base;
SHA256_Init(&context->ctx);
}
static void update_SHA256(const uECC_HashContext *base,
const uint8_t *message,
unsigned message_size) {
SHA256_HashContext *context = (SHA256_HashContext *)base;
SHA256_Update(&context->ctx, message, message_size);
}
static void finish_SHA256(const uECC_HashContext *base, uint8_t *hash_result) {
SHA256_HashContext *context = (SHA256_HashContext *)base;
SHA256_Final(hash_result, &context->ctx);
}
int main() {
int i, c;
uint8_t private[32] = {0};
uint8_t public[64] = {0};
uint8_t hash[32] = {0};
uint8_t sig[64] = {0};
uint8_t tmp[2 * SHA256_DIGEST_LENGTH + SHA256_BLOCK_LENGTH];
SHA256_HashContext ctx = {{
&init_SHA256,
&update_SHA256,
&finish_SHA256,
SHA256_BLOCK_LENGTH,
SHA256_DIGEST_LENGTH,
tmp
}};
const struct uECC_Curve_t * curves[5];
curves[0] = uECC_secp160r1();
curves[1] = uECC_secp192r1();
curves[2] = uECC_secp224r1();
curves[3] = uECC_secp256r1();
curves[4] = uECC_secp256k1();
printf("Testing 256 signatures\n");
for (c = 0; c < 5; ++c) {
for (i = 0; i < 256; ++i) {
printf(".");
fflush(stdout);
if (!uECC_make_key(public, private, curves[c])) {
printf("uECC_make_key() failed\n");
return 1;
}
memcpy(hash, public, sizeof(hash));
if (!uECC_sign_deterministic(private, hash, sizeof(hash), &ctx.uECC, sig, curves[c])) {
printf("uECC_sign() failed\n");
return 1;
}
if (!uECC_verify(public, hash, sizeof(hash), sig, curves[c])) {
printf("uECC_verify() failed\n");
return 1;
}
}
printf("\n");
}
return 0;
}

@ -0,0 +1,108 @@
/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */
#ifndef _UECC_TYPES_H_
#define _UECC_TYPES_H_
#ifndef uECC_PLATFORM
#if __AVR__
#define uECC_PLATFORM uECC_avr
#elif defined(__thumb2__) || defined(_M_ARMT) /* I think MSVC only supports Thumb-2 targets */
#define uECC_PLATFORM uECC_arm_thumb2
#elif defined(__thumb__)
#define uECC_PLATFORM uECC_arm_thumb
#elif defined(__arm__) || defined(_M_ARM)
#define uECC_PLATFORM uECC_arm
#elif defined(__aarch64__)
#define uECC_PLATFORM uECC_arm64
#elif defined(__i386__) || defined(_M_IX86) || defined(_X86_) || defined(__I86__)
#define uECC_PLATFORM uECC_x86
#elif defined(__amd64__) || defined(_M_X64)
#define uECC_PLATFORM uECC_x86_64
#else
#define uECC_PLATFORM uECC_arch_other
#endif
#endif
#ifndef uECC_ARM_USE_UMAAL
#if (uECC_PLATFORM == uECC_arm) && (__ARM_ARCH >= 6)
#define uECC_ARM_USE_UMAAL 1
#elif (uECC_PLATFORM == uECC_arm_thumb2) && (__ARM_ARCH >= 6) && !__ARM_ARCH_7M__
#define uECC_ARM_USE_UMAAL 1
#else
#define uECC_ARM_USE_UMAAL 0
#endif
#endif
#ifndef uECC_WORD_SIZE
#if uECC_PLATFORM == uECC_avr
#define uECC_WORD_SIZE 1
#elif (uECC_PLATFORM == uECC_x86_64 || uECC_PLATFORM == uECC_arm64)
#define uECC_WORD_SIZE 8
#else
#define uECC_WORD_SIZE 4
#endif
#endif
#if (uECC_WORD_SIZE != 1) && (uECC_WORD_SIZE != 4) && (uECC_WORD_SIZE != 8)
#error "Unsupported value for uECC_WORD_SIZE"
#endif
#if ((uECC_PLATFORM == uECC_avr) && (uECC_WORD_SIZE != 1))
#pragma message ("uECC_WORD_SIZE must be 1 for AVR")
#undef uECC_WORD_SIZE
#define uECC_WORD_SIZE 1
#endif
#if ((uECC_PLATFORM == uECC_arm || uECC_PLATFORM == uECC_arm_thumb || \
uECC_PLATFORM == uECC_arm_thumb2) && \
(uECC_WORD_SIZE != 4))
#pragma message ("uECC_WORD_SIZE must be 4 for ARM")
#undef uECC_WORD_SIZE
#define uECC_WORD_SIZE 4
#endif
#if defined(__SIZEOF_INT128__) || ((__clang_major__ * 100 + __clang_minor__) >= 302)
#define SUPPORTS_INT128 1
#else
#define SUPPORTS_INT128 0
#endif
typedef int8_t wordcount_t;
typedef int16_t bitcount_t;
typedef int8_t cmpresult_t;
#if (uECC_WORD_SIZE == 1)
typedef uint8_t uECC_word_t;
typedef uint16_t uECC_dword_t;
#define HIGH_BIT_SET 0x80
#define uECC_WORD_BITS 8
#define uECC_WORD_BITS_SHIFT 3
#define uECC_WORD_BITS_MASK 0x07
#elif (uECC_WORD_SIZE == 4)
typedef uint32_t uECC_word_t;
typedef uint64_t uECC_dword_t;
#define HIGH_BIT_SET 0x80000000
#define uECC_WORD_BITS 32
#define uECC_WORD_BITS_SHIFT 5
#define uECC_WORD_BITS_MASK 0x01F
#elif (uECC_WORD_SIZE == 8)
typedef uint64_t uECC_word_t;
#if SUPPORTS_INT128
typedef unsigned __int128 uECC_dword_t;
#endif
#define HIGH_BIT_SET 0x8000000000000000ull
#define uECC_WORD_BITS 64
#define uECC_WORD_BITS_SHIFT 6
#define uECC_WORD_BITS_MASK 0x03F
#endif /* uECC_WORD_SIZE */
#endif /* _UECC_TYPES_H_ */

File diff suppressed because it is too large Load Diff

@ -0,0 +1,367 @@
/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */
#ifndef _UECC_H_
#define _UECC_H_
#include <stdint.h>
/* Platform selection options.
If uECC_PLATFORM is not defined, the code will try to guess it based on compiler macros.
Possible values for uECC_PLATFORM are defined below: */
#define uECC_arch_other 0
#define uECC_x86 1
#define uECC_x86_64 2
#define uECC_arm 3
#define uECC_arm_thumb 4
#define uECC_arm_thumb2 5
#define uECC_arm64 6
#define uECC_avr 7
/* If desired, you can define uECC_WORD_SIZE as appropriate for your platform (1, 4, or 8 bytes).
If uECC_WORD_SIZE is not explicitly defined then it will be automatically set based on your
platform. */
/* Optimization level; trade speed for code size.
Larger values produce code that is faster but larger.
Currently supported values are 0 - 4; 0 is unusably slow for most applications.
Optimization level 4 currently only has an effect ARM platforms where more than one
curve is enabled. */
#ifndef uECC_OPTIMIZATION_LEVEL
#define uECC_OPTIMIZATION_LEVEL 2
#endif
/* uECC_SQUARE_FUNC - If enabled (defined as nonzero), this will cause a specific function to be
used for (scalar) squaring instead of the generic multiplication function. This can make things
faster somewhat faster, but increases the code size. */
#ifndef uECC_SQUARE_FUNC
#define uECC_SQUARE_FUNC 0
#endif
/* uECC_VLI_NATIVE_LITTLE_ENDIAN - If enabled (defined as nonzero), this will switch to native
little-endian format for *all* arrays passed in and out of the public API. This includes public
and private keys, shared secrets, signatures and message hashes.
Using this switch reduces the amount of call stack memory used by uECC, since less intermediate
translations are required.
Note that this will *only* work on native little-endian processors and it will treat the uint8_t
arrays passed into the public API as word arrays, therefore requiring the provided byte arrays
to be word aligned on architectures that do not support unaligned accesses.
IMPORTANT: Keys and signatures generated with uECC_VLI_NATIVE_LITTLE_ENDIAN=1 are incompatible
with keys and signatures generated with uECC_VLI_NATIVE_LITTLE_ENDIAN=0; all parties must use
the same endianness. */
#ifndef uECC_VLI_NATIVE_LITTLE_ENDIAN
#define uECC_VLI_NATIVE_LITTLE_ENDIAN 0
#endif
/* Curve support selection. Set to 0 to remove that curve. */
#ifndef uECC_SUPPORTS_secp160r1
#define uECC_SUPPORTS_secp160r1 1
#endif
#ifndef uECC_SUPPORTS_secp192r1
#define uECC_SUPPORTS_secp192r1 1
#endif
#ifndef uECC_SUPPORTS_secp224r1
#define uECC_SUPPORTS_secp224r1 1
#endif
#ifndef uECC_SUPPORTS_secp256r1
#define uECC_SUPPORTS_secp256r1 1
#endif
#ifndef uECC_SUPPORTS_secp256k1
#define uECC_SUPPORTS_secp256k1 1
#endif
/* Specifies whether compressed point format is supported.
Set to 0 to disable point compression/decompression functions. */
#ifndef uECC_SUPPORT_COMPRESSED_POINT
#define uECC_SUPPORT_COMPRESSED_POINT 1
#endif
struct uECC_Curve_t;
typedef const struct uECC_Curve_t * uECC_Curve;
#ifdef __cplusplus
extern "C"
{
#endif
#if uECC_SUPPORTS_secp160r1
uECC_Curve uECC_secp160r1(void);
#endif
#if uECC_SUPPORTS_secp192r1
uECC_Curve uECC_secp192r1(void);
#endif
#if uECC_SUPPORTS_secp224r1
uECC_Curve uECC_secp224r1(void);
#endif
#if uECC_SUPPORTS_secp256r1
uECC_Curve uECC_secp256r1(void);
#endif
#if uECC_SUPPORTS_secp256k1
uECC_Curve uECC_secp256k1(void);
#endif
/* uECC_RNG_Function type
The RNG function should fill 'size' random bytes into 'dest'. It should return 1 if
'dest' was filled with random data, or 0 if the random data could not be generated.
The filled-in values should be either truly random, or from a cryptographically-secure PRNG.
A correctly functioning RNG function must be set (using uECC_set_rng()) before calling
uECC_make_key() or uECC_sign().
Setting a correctly functioning RNG function improves the resistance to side-channel attacks
for uECC_shared_secret() and uECC_sign_deterministic().
A correct RNG function is set by default when building for Windows, Linux, or OS X.
If you are building on another POSIX-compliant system that supports /dev/random or /dev/urandom,
you can define uECC_POSIX to use the predefined RNG. For embedded platforms there is no predefined
RNG function; you must provide your own.
*/
typedef int (*uECC_RNG_Function)(uint8_t *dest, unsigned size);
/* uECC_set_rng() function.
Set the function that will be used to generate random bytes. The RNG function should
return 1 if the random data was generated, or 0 if the random data could not be generated.
On platforms where there is no predefined RNG function (eg embedded platforms), this must
be called before uECC_make_key() or uECC_sign() are used.
Inputs:
rng_function - The function that will be used to generate random bytes.
*/
void uECC_set_rng(uECC_RNG_Function rng_function);
/* uECC_get_rng() function.
Returns the function that will be used to generate random bytes.
*/
uECC_RNG_Function uECC_get_rng(void);
/* uECC_curve_private_key_size() function.
Returns the size of a private key for the curve in bytes.
*/
int uECC_curve_private_key_size(uECC_Curve curve);
/* uECC_curve_public_key_size() function.
Returns the size of a public key for the curve in bytes.
*/
int uECC_curve_public_key_size(uECC_Curve curve);
/* uECC_make_key() function.
Create a public/private key pair.
Outputs:
public_key - Will be filled in with the public key. Must be at least 2 * the curve size
(in bytes) long. For example, if the curve is secp256r1, public_key must be 64
bytes long.
private_key - Will be filled in with the private key. Must be as long as the curve order; this
is typically the same as the curve size, except for secp160r1. For example, if the
curve is secp256r1, private_key must be 32 bytes long.
For secp160r1, private_key must be 21 bytes long! Note that the first byte will
almost always be 0 (there is about a 1 in 2^80 chance of it being non-zero).
Returns 1 if the key pair was generated successfully, 0 if an error occurred.
*/
int uECC_make_key(uint8_t *public_key, uint8_t *private_key, uECC_Curve curve);
/* uECC_shared_secret() function.
Compute a shared secret given your secret key and someone else's public key. If the public key
is not from a trusted source and has not been previously verified, you should verify it first
using uECC_valid_public_key().
Note: It is recommended that you hash the result of uECC_shared_secret() before using it for
symmetric encryption or HMAC.
Inputs:
public_key - The public key of the remote party.
private_key - Your private key.
Outputs:
secret - Will be filled in with the shared secret value. Must be the same size as the
curve size; for example, if the curve is secp256r1, secret must be 32 bytes long.
Returns 1 if the shared secret was generated successfully, 0 if an error occurred.
*/
int uECC_shared_secret(const uint8_t *public_key,
const uint8_t *private_key,
uint8_t *secret,
uECC_Curve curve);
#if uECC_SUPPORT_COMPRESSED_POINT
/* uECC_compress() function.
Compress a public key.
Inputs:
public_key - The public key to compress.
Outputs:
compressed - Will be filled in with the compressed public key. Must be at least
(curve size + 1) bytes long; for example, if the curve is secp256r1,
compressed must be 33 bytes long.
*/
void uECC_compress(const uint8_t *public_key, uint8_t *compressed, uECC_Curve curve);
/* uECC_decompress() function.
Decompress a compressed public key.
Inputs:
compressed - The compressed public key.
Outputs:
public_key - Will be filled in with the decompressed public key.
*/
void uECC_decompress(const uint8_t *compressed, uint8_t *public_key, uECC_Curve curve);
#endif /* uECC_SUPPORT_COMPRESSED_POINT */
/* uECC_valid_public_key() function.
Check to see if a public key is valid.
Note that you are not required to check for a valid public key before using any other uECC
functions. However, you may wish to avoid spending CPU time computing a shared secret or
verifying a signature using an invalid public key.
Inputs:
public_key - The public key to check.
Returns 1 if the public key is valid, 0 if it is invalid.
*/
int uECC_valid_public_key(const uint8_t *public_key, uECC_Curve curve);
/* uECC_compute_public_key() function.
Compute the corresponding public key for a private key.
Inputs:
private_key - The private key to compute the public key for
Outputs:
public_key - Will be filled in with the corresponding public key
Returns 1 if the key was computed successfully, 0 if an error occurred.
*/
int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uECC_Curve curve);
/* uECC_sign() function.
Generate an ECDSA signature for a given hash value.
Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and pass it in to
this function along with your private key.
Inputs:
private_key - Your private key.
message_hash - The hash of the message to sign.
hash_size - The size of message_hash in bytes.
Outputs:
signature - Will be filled in with the signature value. Must be at least 2 * curve size long.
For example, if the curve is secp256r1, signature must be 64 bytes long.
Returns 1 if the signature generated successfully, 0 if an error occurred.
*/
int uECC_sign(const uint8_t *private_key,
const uint8_t *message_hash,
unsigned hash_size,
uint8_t *signature,
uECC_Curve curve);
/* uECC_HashContext structure.
This is used to pass in an arbitrary hash function to uECC_sign_deterministic().
The structure will be used for multiple hash computations; each time a new hash
is computed, init_hash() will be called, followed by one or more calls to
update_hash(), and finally a call to finish_hash() to produce the resulting hash.
The intention is that you will create a structure that includes uECC_HashContext
followed by any hash-specific data. For example:
typedef struct SHA256_HashContext {
uECC_HashContext uECC;
SHA256_CTX ctx;
} SHA256_HashContext;
void init_SHA256(uECC_HashContext *base) {
SHA256_HashContext *context = (SHA256_HashContext *)base;
SHA256_Init(&context->ctx);
}
void update_SHA256(uECC_HashContext *base,
const uint8_t *message,
unsigned message_size) {
SHA256_HashContext *context = (SHA256_HashContext *)base;
SHA256_Update(&context->ctx, message, message_size);
}
void finish_SHA256(uECC_HashContext *base, uint8_t *hash_result) {
SHA256_HashContext *context = (SHA256_HashContext *)base;
SHA256_Final(hash_result, &context->ctx);
}
... when signing ...
{
uint8_t tmp[32 + 32 + 64];
SHA256_HashContext ctx = {{&init_SHA256, &update_SHA256, &finish_SHA256, 64, 32, tmp}};
uECC_sign_deterministic(key, message_hash, &ctx.uECC, signature);
}
*/
typedef struct uECC_HashContext {
void (*init_hash)(const struct uECC_HashContext *context);
void (*update_hash)(const struct uECC_HashContext *context,
const uint8_t *message,
unsigned message_size);
void (*finish_hash)(const struct uECC_HashContext *context, uint8_t *hash_result);
unsigned block_size; /* Hash function block size in bytes, eg 64 for SHA-256. */
unsigned result_size; /* Hash function result size in bytes, eg 32 for SHA-256. */
uint8_t *tmp; /* Must point to a buffer of at least (2 * result_size + block_size) bytes. */
} uECC_HashContext;
/* uECC_sign_deterministic() function.
Generate an ECDSA signature for a given hash value, using a deterministic algorithm
(see RFC 6979). You do not need to set the RNG using uECC_set_rng() before calling
this function; however, if the RNG is defined it will improve resistance to side-channel
attacks.
Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and pass it to
this function along with your private key and a hash context. Note that the message_hash
does not need to be computed with the same hash function used by hash_context.
Inputs:
private_key - Your private key.
message_hash - The hash of the message to sign.
hash_size - The size of message_hash in bytes.
hash_context - A hash context to use.
Outputs:
signature - Will be filled in with the signature value.
Returns 1 if the signature generated successfully, 0 if an error occurred.
*/
int uECC_sign_deterministic(const uint8_t *private_key,
const uint8_t *message_hash,
unsigned hash_size,
const uECC_HashContext *hash_context,
uint8_t *signature,
uECC_Curve curve);
/* uECC_verify() function.
Verify an ECDSA signature.
Usage: Compute the hash of the signed data using the same hash as the signer and
pass it to this function along with the signer's public key and the signature values (r and s).
Inputs:
public_key - The signer's public key.
message_hash - The hash of the signed data.
hash_size - The size of message_hash in bytes.
signature - The signature value.
Returns 1 if the signature is valid, 0 if it is invalid.
*/
int uECC_verify(const uint8_t *public_key,
const uint8_t *message_hash,
unsigned hash_size,
const uint8_t *signature,
uECC_Curve curve);
#ifdef __cplusplus
} /* end of extern "C" */
#endif
#endif /* _UECC_H_ */

@ -0,0 +1,172 @@
/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */
#ifndef _UECC_VLI_H_
#define _UECC_VLI_H_
#include "uECC.h"
#include "types.h"
/* Functions for raw large-integer manipulation. These are only available
if uECC.c is compiled with uECC_ENABLE_VLI_API defined to 1. */
#ifndef uECC_ENABLE_VLI_API
#define uECC_ENABLE_VLI_API 0
#endif
#ifdef __cplusplus
extern "C"
{
#endif
#if uECC_ENABLE_VLI_API
void uECC_vli_clear(uECC_word_t *vli, wordcount_t num_words);
/* Constant-time comparison to zero - secure way to compare long integers */
/* Returns 1 if vli == 0, 0 otherwise. */
uECC_word_t uECC_vli_isZero(const uECC_word_t *vli, wordcount_t num_words);
/* Returns nonzero if bit 'bit' of vli is set. */
uECC_word_t uECC_vli_testBit(const uECC_word_t *vli, bitcount_t bit);
/* Counts the number of bits required to represent vli. */
bitcount_t uECC_vli_numBits(const uECC_word_t *vli, const wordcount_t max_words);
/* Sets dest = src. */
void uECC_vli_set(uECC_word_t *dest, const uECC_word_t *src, wordcount_t num_words);
/* Constant-time comparison function - secure way to compare long integers */
/* Returns one if left == right, zero otherwise */
uECC_word_t uECC_vli_equal(const uECC_word_t *left,
const uECC_word_t *right,
wordcount_t num_words);
/* Constant-time comparison function - secure way to compare long integers */
/* Returns sign of left - right, in constant time. */
cmpresult_t uECC_vli_cmp(const uECC_word_t *left, const uECC_word_t *right, wordcount_t num_words);
/* Computes vli = vli >> 1. */
void uECC_vli_rshift1(uECC_word_t *vli, wordcount_t num_words);
/* Computes result = left + right, returning carry. Can modify in place. */
uECC_word_t uECC_vli_add(uECC_word_t *result,
const uECC_word_t *left,
const uECC_word_t *right,
wordcount_t num_words);
/* Computes result = left - right, returning borrow. Can modify in place. */
uECC_word_t uECC_vli_sub(uECC_word_t *result,
const uECC_word_t *left,
const uECC_word_t *right,
wordcount_t num_words);
/* Computes result = left * right. Result must be 2 * num_words long. */
void uECC_vli_mult(uECC_word_t *result,
const uECC_word_t *left,
const uECC_word_t *right,
wordcount_t num_words);
/* Computes result = left^2. Result must be 2 * num_words long. */
void uECC_vli_square(uECC_word_t *result, const uECC_word_t *left, wordcount_t num_words);
/* Computes result = (left + right) % mod.
Assumes that left < mod and right < mod, and that result does not overlap mod. */
void uECC_vli_modAdd(uECC_word_t *result,
const uECC_word_t *left,
const uECC_word_t *right,
const uECC_word_t *mod,
wordcount_t num_words);
/* Computes result = (left - right) % mod.
Assumes that left < mod and right < mod, and that result does not overlap mod. */
void uECC_vli_modSub(uECC_word_t *result,
const uECC_word_t *left,
const uECC_word_t *right,
const uECC_word_t *mod,
wordcount_t num_words);
/* Computes result = product % mod, where product is 2N words long.
Currently only designed to work for mod == curve->p or curve_n. */
void uECC_vli_mmod(uECC_word_t *result,
uECC_word_t *product,
const uECC_word_t *mod,
wordcount_t num_words);
/* Calculates result = product (mod curve->p), where product is up to
2 * curve->num_words long. */
void uECC_vli_mmod_fast(uECC_word_t *result, uECC_word_t *product, uECC_Curve curve);
/* Computes result = (left * right) % mod.
Currently only designed to work for mod == curve->p or curve_n. */
void uECC_vli_modMult(uECC_word_t *result,
const uECC_word_t *left,
const uECC_word_t *right,
const uECC_word_t *mod,
wordcount_t num_words);
/* Computes result = (left * right) % curve->p. */
void uECC_vli_modMult_fast(uECC_word_t *result,
const uECC_word_t *left,
const uECC_word_t *right,
uECC_Curve curve);
/* Computes result = left^2 % mod.
Currently only designed to work for mod == curve->p or curve_n. */
void uECC_vli_modSquare(uECC_word_t *result,
const uECC_word_t *left,
const uECC_word_t *mod,
wordcount_t num_words);
/* Computes result = left^2 % curve->p. */
void uECC_vli_modSquare_fast(uECC_word_t *result, const uECC_word_t *left, uECC_Curve curve);
/* Computes result = (1 / input) % mod.*/
void uECC_vli_modInv(uECC_word_t *result,
const uECC_word_t *input,
const uECC_word_t *mod,
wordcount_t num_words);
#if uECC_SUPPORT_COMPRESSED_POINT
/* Calculates a = sqrt(a) (mod curve->p) */
void uECC_vli_mod_sqrt(uECC_word_t *a, uECC_Curve curve);
#endif
/* Converts an integer in uECC native format to big-endian bytes. */
void uECC_vli_nativeToBytes(uint8_t *bytes, int num_bytes, const uECC_word_t *native);
/* Converts big-endian bytes to an integer in uECC native format. */
void uECC_vli_bytesToNative(uECC_word_t *native, const uint8_t *bytes, int num_bytes);
unsigned uECC_curve_num_words(uECC_Curve curve);
unsigned uECC_curve_num_bytes(uECC_Curve curve);
unsigned uECC_curve_num_bits(uECC_Curve curve);
unsigned uECC_curve_num_n_words(uECC_Curve curve);
unsigned uECC_curve_num_n_bytes(uECC_Curve curve);
unsigned uECC_curve_num_n_bits(uECC_Curve curve);
const uECC_word_t *uECC_curve_p(uECC_Curve curve);
const uECC_word_t *uECC_curve_n(uECC_Curve curve);
const uECC_word_t *uECC_curve_G(uECC_Curve curve);
const uECC_word_t *uECC_curve_b(uECC_Curve curve);
int uECC_valid_point(const uECC_word_t *point, uECC_Curve curve);
/* Multiplies a point by a scalar. Points are represented by the X coordinate followed by
the Y coordinate in the same array, both coordinates are curve->num_words long. Note
that scalar must be curve->num_n_words long (NOT curve->num_words). */
void uECC_point_mult(uECC_word_t *result,
const uECC_word_t *point,
const uECC_word_t *scalar,
uECC_Curve curve);
/* Generates a random integer in the range 0 < random < top.
Both random and top have num_words words. */
int uECC_generate_random_int(uECC_word_t *random,
const uECC_word_t *top,
wordcount_t num_words);
#endif /* uECC_ENABLE_VLI_API */
#ifdef __cplusplus
} /* end of extern "C" */
#endif
#endif /* _UECC_VLI_H_ */

@ -0,0 +1,4 @@
#define VERSION_MAJOR 0
#define VERSION_MINOR 0
#define VERSION_PATCH 0
#define VERSION_BUILD 0

@ -0,0 +1,203 @@
#include "ble_gap.h"
#include "advertising.h"
#include "ble_advdata.h"
#include "ble_advertising.h"
#include "ble_nus.h"
#include "connection.h"
#include "defs.h"
#include "int_comm.h"
#include "nrf_log.h"
#include "pm.h"
#include "power.h"
#define APP_ADV_INTERVAL \
64 /**< The advertising interval (in units of 0.625 ms. This value \
corresponds to 40 ms). */
#define APP_ADV_DURATION \
18000 /**< The advertising duration (180 seconds) in units of 10 \
milliseconds. */
#define NUS_SERVICE_UUID_TYPE \
BLE_UUID_TYPE_VENDOR_BEGIN /**< UUID type for the Nordic UART Service \
(vendor specific). */
static ble_uuid_t m_adv_uuids[] = /**< Universally unique service identifier. */
{{BLE_UUID_NUS_SERVICE, NUS_SERVICE_UUID_TYPE}};
BLE_ADVERTISING_DEF(m_advertising); /**< Advertising module instance. */
/**@brief Function for handling advertising events.
*
* @details This function will be called for advertising events which are passed
* to the application.
*
* @param[in] ble_adv_evt Advertising event.
*/
static void on_adv_evt(ble_adv_evt_t ble_adv_evt) {
uint32_t err_code;
switch (ble_adv_evt) {
case BLE_ADV_EVT_DIRECTED_HIGH_DUTY:
NRF_LOG_INFO("High Duty Directed advertising.");
send_status_event();
break;
case BLE_ADV_EVT_DIRECTED:
NRF_LOG_INFO("Directed advertising.");
send_status_event();
break;
case BLE_ADV_EVT_FAST:
NRF_LOG_INFO("Fast advertising.");
send_status_event();
break;
case BLE_ADV_EVT_SLOW:
NRF_LOG_INFO("Slow advertising.");
send_status_event();
break;
case BLE_ADV_EVT_FAST_WHITELIST:
NRF_LOG_INFO("Fast advertising with whitelist.");
send_status_event();
break;
case BLE_ADV_EVT_SLOW_WHITELIST:
NRF_LOG_INFO("Slow advertising with whitelist.");
send_status_event();
break;
case BLE_ADV_EVT_IDLE:
send_status_event();
// sleep_mode_enter();
break;
case BLE_ADV_EVT_WHITELIST_REQUEST: {
ble_gap_addr_t whitelist_addrs[BLE_GAP_WHITELIST_ADDR_MAX_COUNT];
ble_gap_irk_t whitelist_irks[BLE_GAP_WHITELIST_ADDR_MAX_COUNT];
uint32_t addr_cnt = BLE_GAP_WHITELIST_ADDR_MAX_COUNT;
uint32_t irk_cnt = BLE_GAP_WHITELIST_ADDR_MAX_COUNT;
err_code = pm_whitelist_get(whitelist_addrs, &addr_cnt, whitelist_irks,
&irk_cnt);
if (err_code != NRF_ERROR_NOT_FOUND) {
APP_ERROR_CHECK(err_code);
} else {
break;
}
NRF_LOG_DEBUG(
"pm_whitelist_get returns %d addr in whitelist and %d irk whitelist",
addr_cnt, irk_cnt);
// Set the correct identities list (no excluding peers with no Central
// Address Resolution).
identities_set(PM_PEER_ID_LIST_SKIP_NO_IRK);
// Apply the whitelist.
err_code = ble_advertising_whitelist_reply(
&m_advertising, whitelist_addrs, addr_cnt, whitelist_irks, irk_cnt);
APP_ERROR_CHECK(err_code);
} break; // BLE_ADV_EVT_WHITELIST_REQUEST
case BLE_ADV_EVT_PEER_ADDR_REQUEST: {
pm_peer_data_bonding_t peer_bonding_data;
// Only Give peer address if we have a handle to the bonded peer.
if (get_peer_id() != PM_PEER_ID_INVALID) {
err_code = pm_peer_data_bonding_load(get_peer_id(), &peer_bonding_data);
if (err_code != NRF_ERROR_NOT_FOUND) {
APP_ERROR_CHECK(err_code);
// Manipulate identities to exclude peers with no Central Address
// Resolution.
identities_set(PM_PEER_ID_LIST_SKIP_ALL);
ble_gap_addr_t *p_peer_addr =
&(peer_bonding_data.peer_ble_id.id_addr_info);
err_code =
ble_advertising_peer_addr_reply(&m_advertising, p_peer_addr);
APP_ERROR_CHECK(err_code);
}
}
} break; // BLE_ADV_EVT_PEER_ADDR_REQUEST
default:
break;
}
}
void advertising_init(void) {
uint32_t err_code;
uint8_t adv_flags;
ble_advertising_init_t init;
memset(&init, 0, sizeof(init));
adv_flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
init.advdata.name_type = BLE_ADVDATA_FULL_NAME;
init.advdata.include_appearance = false;
init.advdata.flags = adv_flags;
init.advdata.uuids_complete.uuid_cnt = 0;
init.advdata.uuids_complete.p_uuids = NULL;
init.config.ble_adv_whitelist_enabled = true;
init.config.ble_adv_directed_high_duty_enabled = true;
init.config.ble_adv_directed_enabled = false;
init.config.ble_adv_directed_interval = 0;
init.config.ble_adv_directed_timeout = 0;
init.config.ble_adv_fast_enabled = true;
init.config.ble_adv_fast_interval = APP_ADV_INTERVAL;
init.config.ble_adv_fast_timeout = APP_ADV_DURATION;
init.evt_handler = on_adv_evt;
init.srdata.uuids_more_available.uuid_cnt =
sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]);
init.srdata.uuids_more_available.p_uuids = m_adv_uuids;
err_code = ble_advertising_init(&m_advertising, &init);
APP_ERROR_CHECK(err_code);
ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);
}
void advertising_start(bool whitelist) {
m_advertising.adv_modes_config.ble_adv_on_disconnect_disabled = false;
if (m_advertising.adv_mode_current != BLE_ADV_MODE_DIRECTED_HIGH_DUTY) {
if (m_advertising.adv_mode_current != BLE_ADV_MODE_FAST &&
get_connection_handle() == BLE_CONN_HANDLE_INVALID) {
whitelist_set(PM_PEER_ID_LIST_SKIP_NO_ID_ADDR);
ret_code_t ret = ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST);
APP_ERROR_CHECK(ret);
}
if (!whitelist) {
ret_code_t ret =
ble_advertising_restart_without_whitelist(&m_advertising);
APP_ERROR_CHECK(ret);
}
}
}
void advertising_stop(void) {
m_advertising.adv_modes_config.ble_adv_on_disconnect_disabled = true;
ret_code_t ret = ble_advertising_start(&m_advertising, BLE_ADV_MODE_IDLE);
APP_ERROR_CHECK(ret);
// ret =sd_ble_gap_disconnect(get_connection_handle(),
// BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); APP_ERROR_CHECK(ret);
}
void advertising_restart_without_whitelist(void) {
ret_code_t ret = ble_advertising_restart_without_whitelist(&m_advertising);
APP_ERROR_CHECK(ret);
}
bool is_advertising(void) {
return m_advertising.adv_mode_current != BLE_ADV_MODE_IDLE;
}
bool is_advertising_wl(void) { return m_advertising.whitelist_in_use; }

@ -0,0 +1,18 @@
#ifndef __ADVERTISING__
#define __ADVERTISING__
#include <stdbool.h>
void advertising_init(void);
void advertising_start(bool whitelist);
void advertising_stop(void);
void advertising_restart_without_whitelist(void);
bool is_advertising(void);
bool is_advertising_wl(void);
#endif

@ -0,0 +1,356 @@
// clang-format off
/**
* Copyright (c) 2012 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "sdk_common.h"
#if NRF_MODULE_ENABLED(BLE_NUS)
#include "ble.h"
#include "ble_nus.h"
#include "ble_srv_common.h"
#define NRF_LOG_MODULE_NAME ble_nus
#if BLE_NUS_CONFIG_LOG_ENABLED
#define NRF_LOG_LEVEL BLE_NUS_CONFIG_LOG_LEVEL
#define NRF_LOG_INFO_COLOR BLE_NUS_CONFIG_INFO_COLOR
#define NRF_LOG_DEBUG_COLOR BLE_NUS_CONFIG_DEBUG_COLOR
#else // BLE_NUS_CONFIG_LOG_ENABLED
#define NRF_LOG_LEVEL 0
#endif // BLE_NUS_CONFIG_LOG_ENABLED
#include "nrf_log.h"
NRF_LOG_MODULE_REGISTER();
#define BLE_UUID_NUS_TX_CHARACTERISTIC 0x0003 /**< The UUID of the TX Characteristic. */
#define BLE_UUID_NUS_RX_CHARACTERISTIC 0x0002 /**< The UUID of the RX Characteristic. */
#define BLE_NUS_MAX_RX_CHAR_LEN BLE_NUS_MAX_DATA_LEN /**< Maximum length of the RX Characteristic (in bytes). */
#define BLE_NUS_MAX_TX_CHAR_LEN BLE_NUS_MAX_DATA_LEN /**< Maximum length of the TX Characteristic (in bytes). */
#define NUS_BASE_UUID {{0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x00, 0x00, 0x40, 0x6E}} /**< Used vendor specific UUID. */
/**@brief Function for handling the @ref BLE_GAP_EVT_CONNECTED event from the SoftDevice.
*
* @param[in] p_nus Nordic UART Service structure.
* @param[in] p_ble_evt Pointer to the event received from BLE stack.
*/
static void on_connect(ble_nus_t * p_nus, ble_evt_t const * p_ble_evt)
{
ret_code_t err_code;
ble_nus_evt_t evt;
ble_gatts_value_t gatts_val;
uint8_t cccd_value[2];
ble_nus_client_context_t * p_client = NULL;
err_code = blcm_link_ctx_get(p_nus->p_link_ctx_storage,
p_ble_evt->evt.gap_evt.conn_handle,
(void *) &p_client);
if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("Link context for 0x%02X connection handle could not be fetched.",
p_ble_evt->evt.gap_evt.conn_handle);
}
/* Check the hosts CCCD value to inform of readiness to send data using the RX characteristic */
memset(&gatts_val, 0, sizeof(ble_gatts_value_t));
gatts_val.p_value = cccd_value;
gatts_val.len = sizeof(cccd_value);
gatts_val.offset = 0;
err_code = sd_ble_gatts_value_get(p_ble_evt->evt.gap_evt.conn_handle,
p_nus->tx_handles.cccd_handle,
&gatts_val);
if ((err_code == NRF_SUCCESS) &&
(p_nus->data_handler != NULL) &&
ble_srv_is_notification_enabled(gatts_val.p_value))
{
if (p_client != NULL)
{
p_client->is_notification_enabled = true;
}
memset(&evt, 0, sizeof(ble_nus_evt_t));
evt.type = BLE_NUS_EVT_COMM_STARTED;
evt.p_nus = p_nus;
evt.conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
evt.p_link_ctx = p_client;
p_nus->data_handler(&evt);
}
}
/**@brief Function for handling the @ref BLE_GATTS_EVT_WRITE event from the SoftDevice.
*
* @param[in] p_nus Nordic UART Service structure.
* @param[in] p_ble_evt Pointer to the event received from BLE stack.
*/
static void on_write(ble_nus_t * p_nus, ble_evt_t const * p_ble_evt)
{
ret_code_t err_code;
ble_nus_evt_t evt;
ble_nus_client_context_t * p_client;
ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
err_code = blcm_link_ctx_get(p_nus->p_link_ctx_storage,
p_ble_evt->evt.gatts_evt.conn_handle,
(void *) &p_client);
if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("Link context for 0x%02X connection handle could not be fetched.",
p_ble_evt->evt.gatts_evt.conn_handle);
}
memset(&evt, 0, sizeof(ble_nus_evt_t));
evt.p_nus = p_nus;
evt.conn_handle = p_ble_evt->evt.gatts_evt.conn_handle;
evt.p_link_ctx = p_client;
if ((p_evt_write->handle == p_nus->tx_handles.cccd_handle) &&
(p_evt_write->len == 2))
{
if (p_client != NULL)
{
if (ble_srv_is_notification_enabled(p_evt_write->data))
{
p_client->is_notification_enabled = true;
evt.type = BLE_NUS_EVT_COMM_STARTED;
}
else
{
p_client->is_notification_enabled = false;
evt.type = BLE_NUS_EVT_COMM_STOPPED;
}
if (p_nus->data_handler != NULL)
{
p_nus->data_handler(&evt);
}
}
}
else if ((p_evt_write->handle == p_nus->rx_handles.value_handle) &&
(p_nus->data_handler != NULL))
{
evt.type = BLE_NUS_EVT_RX_DATA;
evt.params.rx_data.p_data = p_evt_write->data;
evt.params.rx_data.length = p_evt_write->len;
p_nus->data_handler(&evt);
}
else
{
// Do Nothing. This event is not relevant for this service.
}
}
/**@brief Function for handling the @ref BLE_GATTS_EVT_HVN_TX_COMPLETE event from the SoftDevice.
*
* @param[in] p_nus Nordic UART Service structure.
* @param[in] p_ble_evt Pointer to the event received from BLE stack.
*/
static void on_hvx_tx_complete(ble_nus_t * p_nus, ble_evt_t const * p_ble_evt)
{
ret_code_t err_code;
ble_nus_evt_t evt;
ble_nus_client_context_t * p_client;
err_code = blcm_link_ctx_get(p_nus->p_link_ctx_storage,
p_ble_evt->evt.gatts_evt.conn_handle,
(void *) &p_client);
if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("Link context for 0x%02X connection handle could not be fetched.",
p_ble_evt->evt.gatts_evt.conn_handle);
return;
}
if ((p_client->is_notification_enabled) && (p_nus->data_handler != NULL))
{
memset(&evt, 0, sizeof(ble_nus_evt_t));
evt.type = BLE_NUS_EVT_TX_RDY;
evt.p_nus = p_nus;
evt.conn_handle = p_ble_evt->evt.gatts_evt.conn_handle;
evt.p_link_ctx = p_client;
p_nus->data_handler(&evt);
}
}
void ble_nus_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
{
if ((p_context == NULL) || (p_ble_evt == NULL))
{
return;
}
ble_nus_t * p_nus = (ble_nus_t *)p_context;
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
on_connect(p_nus, p_ble_evt);
break;
case BLE_GATTS_EVT_WRITE:
on_write(p_nus, p_ble_evt);
break;
case BLE_GATTS_EVT_HVN_TX_COMPLETE:
on_hvx_tx_complete(p_nus, p_ble_evt);
break;
default:
// No implementation needed.
break;
}
}
uint32_t ble_nus_init(ble_nus_t * p_nus, ble_nus_init_t const * p_nus_init)
{
ret_code_t err_code;
ble_uuid_t ble_uuid;
ble_uuid128_t nus_base_uuid = NUS_BASE_UUID;
ble_add_char_params_t add_char_params;
VERIFY_PARAM_NOT_NULL(p_nus);
VERIFY_PARAM_NOT_NULL(p_nus_init);
// Initialize the service structure.
p_nus->data_handler = p_nus_init->data_handler;
/**@snippet [Adding proprietary Service to the SoftDevice] */
// Add a custom base UUID.
err_code = sd_ble_uuid_vs_add(&nus_base_uuid, &p_nus->uuid_type);
VERIFY_SUCCESS(err_code);
ble_uuid.type = p_nus->uuid_type;
ble_uuid.uuid = BLE_UUID_NUS_SERVICE;
// Add the service.
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
&ble_uuid,
&p_nus->service_handle);
/**@snippet [Adding proprietary Service to the SoftDevice] */
VERIFY_SUCCESS(err_code);
// Add the RX Characteristic.
memset(&add_char_params, 0, sizeof(add_char_params));
add_char_params.uuid = BLE_UUID_NUS_RX_CHARACTERISTIC;
add_char_params.uuid_type = p_nus->uuid_type;
add_char_params.max_len = BLE_NUS_MAX_RX_CHAR_LEN;
add_char_params.init_len = sizeof(uint8_t);
add_char_params.is_var_len = true;
add_char_params.char_props.write = 1;
add_char_params.char_props.write_wo_resp = 1;
add_char_params.read_access = SEC_MITM;
add_char_params.write_access = SEC_MITM;
err_code = characteristic_add(p_nus->service_handle, &add_char_params, &p_nus->rx_handles);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
// Add the TX Characteristic.
/**@snippet [Adding proprietary characteristic to the SoftDevice] */
memset(&add_char_params, 0, sizeof(add_char_params));
add_char_params.uuid = BLE_UUID_NUS_TX_CHARACTERISTIC;
add_char_params.uuid_type = p_nus->uuid_type;
add_char_params.max_len = BLE_NUS_MAX_TX_CHAR_LEN;
add_char_params.init_len = sizeof(uint8_t);
add_char_params.is_var_len = true;
add_char_params.char_props.notify = 1;
add_char_params.read_access = SEC_MITM;
add_char_params.write_access = SEC_MITM;
add_char_params.cccd_write_access = SEC_MITM;
return characteristic_add(p_nus->service_handle, &add_char_params, &p_nus->tx_handles);
/**@snippet [Adding proprietary characteristic to the SoftDevice] */
}
uint32_t ble_nus_data_send(ble_nus_t * p_nus,
uint8_t * p_data,
uint16_t * p_length,
uint16_t conn_handle)
{
ret_code_t err_code;
ble_gatts_hvx_params_t hvx_params;
ble_nus_client_context_t * p_client;
VERIFY_PARAM_NOT_NULL(p_nus);
err_code = blcm_link_ctx_get(p_nus->p_link_ctx_storage, conn_handle, (void *) &p_client);
VERIFY_SUCCESS(err_code);
if ((conn_handle == BLE_CONN_HANDLE_INVALID) || (p_client == NULL))
{
return NRF_ERROR_NOT_FOUND;
}
if (!p_client->is_notification_enabled)
{
return NRF_ERROR_INVALID_STATE;
}
if (*p_length > BLE_NUS_MAX_DATA_LEN)
{
return NRF_ERROR_INVALID_PARAM;
}
memset(&hvx_params, 0, sizeof(hvx_params));
hvx_params.handle = p_nus->tx_handles.value_handle;
hvx_params.p_data = p_data;
hvx_params.p_len = p_length;
hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
return sd_ble_gatts_hvx(conn_handle, &hvx_params);
}
#endif // NRF_MODULE_ENABLED(BLE_NUS)

@ -0,0 +1,17 @@
#include "ble_gap.h"
#include "connection.h"
static uint16_t m_conn_handle =
BLE_CONN_HANDLE_INVALID; /**< Handle of the current connection. */
void set_connection_handle(uint16_t val) { m_conn_handle = val; }
uint16_t get_connection_handle(void) { return m_conn_handle; }
void disconnect(void) {
if (m_conn_handle != BLE_CONN_HANDLE_INVALID) {
sd_ble_gap_disconnect(m_conn_handle,
BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
}
}

@ -0,0 +1,11 @@
#ifndef BLE_CONNECTION_H__
#define BLE_CONNECTION_H__
#include <stdint.h>
void set_connection_handle(uint16_t val);
uint16_t get_connection_handle(void);
void disconnect(void);
#endif

@ -0,0 +1,3 @@
#define APP_BLE_CONN_CFG_TAG \
1 /**< A tag identifying the SoftDevice BLE configuration. */

@ -0,0 +1,23 @@
#include "dis.h"
#include <string.h>
#include "app_error.h"
#include "ble_dis.h"
#include "sdk_errors.h"
#define MANUFACTURER_NAME \
"SatoshiLabs" /**< Manufacturer. Will be passed to Device Information \
Service. */
void dis_init(void) {
ret_code_t err_code;
ble_dis_init_t dis_init_obj;
memset(&dis_init_obj, 0, sizeof(dis_init_obj));
ble_srv_ascii_to_utf8(&dis_init_obj.manufact_name_str, MANUFACTURER_NAME);
dis_init_obj.dis_char_rd_sec = SEC_JUST_WORKS;
err_code = ble_dis_init(&dis_init_obj);
APP_ERROR_CHECK(err_code);
}

@ -0,0 +1,6 @@
#ifndef __DIS__
#define __DIS__
void dis_init(void);
#endif

@ -0,0 +1,458 @@
#include "int_comm.h"
#include "advertising.h"
#include "app_error.h"
#include "app_uart.h"
#include "ble/int_comm_defs.h"
#include "ble_advertising.h"
#include "ble_nus.h"
#include "connection.h"
#include "messages.pb.h"
#include "nrf_drv_spi.h"
#include "nrf_log.h"
#include "pm.h"
#include "protob_helpers.h"
#include "stdint.h"
#include "trezor_t3w1_d1_NRF.h"
#define SPI_INSTANCE 0 /**< SPI instance index. */
static uint8_t m_uart_rx_data[BLE_NUS_MAX_DATA_LEN];
static uint8_t m_spi_tx_data[BLE_PACKET_SIZE];
static bool m_uart_rx_data_ready_internal = false;
BLE_NUS_DEF(m_nus,
NRF_SDH_BLE_TOTAL_LINK_COUNT); /**< BLE NUS service instance. */
static const nrf_drv_spi_t spi =
NRF_DRV_SPI_INSTANCE(SPI_INSTANCE); /**< SPI instance. */
static volatile bool spi_xfer_done = true; /**< Flag used to indicate that SPI
instance completed the transfer. */
/**
* @brief SPI user event handler.
* @param event
*/
void spi_event_handler(nrf_drv_spi_evt_t const *p_event, void *p_context) {
spi_xfer_done = true;
NRF_LOG_INFO("Transfer completed.");
}
void spi_init(void) {
nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
spi_config.ss_pin = SPI_SS_PIN;
spi_config.miso_pin = SPI_MISO_PIN;
spi_config.mosi_pin = SPI_MOSI_PIN;
spi_config.sck_pin = SPI_SCK_PIN;
spi_config.frequency = NRF_DRV_SPI_FREQ_8M;
APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler, NULL));
}
void nus_init() {
uint32_t err_code;
ble_nus_init_t nus_init;
memset(&nus_init, 0, sizeof(nus_init));
nus_init.data_handler = nus_data_handler;
err_code = ble_nus_init(&m_nus, &nus_init);
APP_ERROR_CHECK(err_code);
}
void send_byte(uint8_t byte) {
uint32_t err_code;
do {
err_code = app_uart_put(byte);
if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_BUSY)) {
NRF_LOG_ERROR("Failed receiving NUS message. Error 0x%x. ", err_code);
}
} while (err_code == NRF_ERROR_BUSY);
}
void send_packet(uint8_t message_type, const uint8_t *tx_data, uint16_t len) {
uint16_t total_len = len + OVERHEAD_SIZE;
send_byte(message_type);
send_byte((total_len >> 8) & 0xFF);
send_byte(total_len & 0xFF);
for (uint32_t i = 0; i < len; i++) {
send_byte(tx_data[i]);
}
send_byte(EOM);
}
bool write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count) {
write_state *state = (write_state *)(stream->state);
size_t written = 0;
// while we have data left
while (written < count) {
size_t remaining = count - written;
// if all remaining data fit into our packet
if (state->packet_pos + remaining <= USB_PACKET_SIZE) {
// append data from buf to state->buf
memcpy(state->buf + state->packet_pos, buf + written, remaining);
// advance position
state->packet_pos += remaining;
// and return
return true;
} else {
// append data that fits
memcpy(state->buf + state->packet_pos, buf + written,
USB_PACKET_SIZE - state->packet_pos);
written += USB_PACKET_SIZE - state->packet_pos;
// send packet
send_packet(state->iface_num, state->buf, USB_PACKET_SIZE);
// prepare new packet
state->packet_index++;
memset(state->buf, 0, USB_PACKET_SIZE);
state->buf[0] = '?';
state->packet_pos = MSG_HEADER2_LEN;
}
}
return true;
};
void write_flush(write_state *state) {
// if packet is not filled up completely
if (state->packet_pos < USB_PACKET_SIZE) {
// pad it with zeroes
memset(state->buf + state->packet_pos, 0,
USB_PACKET_SIZE - state->packet_pos);
}
// send packet
send_packet(state->iface_num, state->buf, USB_PACKET_SIZE);
}
/* we don't use secbool/sectrue/secfalse here as it is a nanopb api */
static bool read(pb_istream_t *stream, uint8_t *buf, size_t count) {
read_state *state = (read_state *)(stream->state);
size_t read = 0;
// while we have data left
while (read < count) {
size_t remaining = count - read;
// if all remaining data fit into our packet
if (state->packet_pos + remaining <= state->packet_size) {
// append data from buf to state->buf
memcpy(buf + read, state->buf + state->packet_pos, remaining);
// advance position
state->packet_pos += remaining;
// and return
return true;
} else {
// append data that fits
memcpy(buf + read, state->buf + state->packet_pos,
state->packet_size - state->packet_pos);
read += state->packet_size - state->packet_pos;
// read next packet
while (!m_uart_rx_data_ready_internal)
;
m_uart_rx_data_ready_internal = false;
memcpy(state->buf, m_uart_rx_data, USB_PACKET_SIZE);
// prepare next packet
state->packet_index++;
state->packet_pos = MSG_HEADER2_LEN;
}
}
return true;
}
static void read_flush(read_state *state) { (void)state; }
#define MSG_SEND_NRF(msg) (MSG_SEND(msg, write, write_flush))
void process_command(uint8_t *data, uint16_t len) {
uint8_t cmd = data[0];
switch (cmd) {
case INTERNAL_CMD_SEND_STATE:
send_status_event();
break;
case INTERNAL_CMD_ADVERTISING_ON:
advertising_start(data[1] != 0);
send_status_event();
break;
case INTERNAL_CMD_ADVERTISING_OFF:
advertising_stop();
send_status_event();
break;
case INTERNAL_CMD_ERASE_BONDS:
delete_bonds();
send_success_event();
break;
case INTERNAL_CMD_DISCONNECT:
disconnect();
send_success_event();
break;
default:
break;
}
}
secbool process_auth_key(uint8_t *data, uint32_t len, void *msg) {
recv_protob_msg(INTERNAL_MESSAGE, len, data, AuthKey_fields, msg, read,
read_flush, USB_PACKET_SIZE);
return sectrue;
}
secbool process_success(uint8_t *data, uint32_t len, void *msg) {
recv_protob_msg(INTERNAL_MESSAGE, len, data, Success_fields, msg, read,
read_flush, USB_PACKET_SIZE);
return sectrue;
}
void process_unexpected(uint8_t *data, uint32_t len) {}
secbool await_response(uint16_t expected,
secbool (*process)(uint8_t *data, uint32_t len,
void *msg),
void *msg_recv) {
while (!m_uart_rx_data_ready_internal)
;
m_uart_rx_data_ready_internal = false;
uint16_t id = 0;
uint32_t msg_size = 0;
msg_parse_header(m_uart_rx_data, &id, &msg_size);
if (id == expected) {
if (process != NULL) {
return process(m_uart_rx_data, msg_size, msg_recv);
}
return sectrue;
} else {
process_unexpected(m_uart_rx_data, msg_size);
}
return secfalse;
}
/**@brief Function for handling app_uart events.
*
* @details This function will receive a single character from the app_uart
* module and append it to a string. The string will be be sent over BLE when
* the last character received was a 'new line' '\n' (hex 0x0A) or if the string
* has reached the maximum data length.
*/
/**@snippet [Handling the data received over UART] */
void uart_event_handle(app_uart_evt_t *p_event) {
static uint8_t index = 0;
static uint8_t message_type = 0;
static uint16_t len = 0;
uint32_t err_code;
uint8_t rx_byte = 0;
switch (p_event->evt_type) {
case APP_UART_DATA_READY:
while (app_uart_get(&rx_byte) == NRF_SUCCESS) {
if (index == 0) {
if (rx_byte == INTERNAL_MESSAGE || rx_byte == INTERNAL_EVENT ||
rx_byte == EXTERNAL_MESSAGE) {
message_type = rx_byte;
index += 1;
continue;
} else {
// unknown message
continue;
}
}
if (index == 1) {
// len HI
len = rx_byte << 8;
index += 1;
continue;
}
if (index == 2) {
// len LO
len |= rx_byte;
index += 1;
if (len > sizeof(m_uart_rx_data) + OVERHEAD_SIZE) {
// message too long
index = 0;
continue;
}
continue;
}
if (index < (len - 1)) {
// command
m_uart_rx_data[index - COMM_HEADER_SIZE] = rx_byte;
index += 1;
continue;
}
if (index >= (len - 1)) {
if (rx_byte == EOM) {
if (message_type == EXTERNAL_MESSAGE) {
NRF_LOG_DEBUG("Ready to send data over BLE NUS");
NRF_LOG_HEXDUMP_DEBUG(m_uart_rx_data, index);
do {
uint16_t length = (uint16_t)len - OVERHEAD_SIZE;
err_code = ble_nus_data_send(&m_nus, m_uart_rx_data, &length,
get_connection_handle());
if ((err_code != NRF_ERROR_INVALID_STATE) &&
(err_code != NRF_ERROR_RESOURCES) &&
(err_code != NRF_ERROR_NOT_FOUND)) {
APP_ERROR_CHECK(err_code);
}
} while (err_code == NRF_ERROR_RESOURCES);
} else if (message_type == INTERNAL_MESSAGE) {
m_uart_rx_data_ready_internal = true;
} else if (message_type == INTERNAL_EVENT) {
process_command(m_uart_rx_data, len - OVERHEAD_SIZE);
}
}
index = 0;
}
}
break;
default:
break;
}
}
/**@snippet [Handling the data received over UART] */
/**@brief Function for handling the data from the Nordic UART Service.
*
* @details This function will process the data received from the Nordic UART
* BLE Service and forward it to Trezor
*
* @param[in] p_evt Nordic UART Service event.
*/
/**@snippet [Handling the data received over BLE] */
void nus_data_handler(ble_nus_evt_t *p_evt) {
if (p_evt->type == BLE_NUS_EVT_RX_DATA) {
NRF_LOG_DEBUG("Received data from BLE NUS. Forwarding.");
NRF_LOG_HEXDUMP_DEBUG(p_evt->params.rx_data.p_data,
p_evt->params.rx_data.length);
if (p_evt->params.rx_data.length != BLE_PACKET_SIZE) {
return;
}
while (!spi_xfer_done)
;
spi_xfer_done = false;
memcpy(m_spi_tx_data, p_evt->params.rx_data.p_data, BLE_PACKET_SIZE);
nrf_drv_spi_transfer(&spi, m_spi_tx_data, BLE_PACKET_SIZE, NULL, 0);
}
}
/**@snippet [Handling the data received over BLE] */
void send_status_event(void) {
uint8_t tx_data[] = {
INTERNAL_EVENT_STATUS,
(get_connection_handle() != BLE_CONN_HANDLE_INVALID) ? 1
: 0, // connected
is_advertising() ? 1 : 0, // advertising
is_advertising_wl() ? 1 : 0, // advertising whitelist
pm_peer_count(), // peer count
};
send_packet(INTERNAL_EVENT, tx_data, sizeof(tx_data));
}
void send_success_event(void) {
uint8_t tx_data[] = {
INTERNAL_EVENT_SUCCESS,
};
send_packet(INTERNAL_EVENT, tx_data, sizeof(tx_data));
}
uint16_t get_message_type(const uint8_t *rx_data) {
return (rx_data[3] << 8) | rx_data[4];
}
static bool read_authkey(pb_istream_t *stream, const pb_field_t *field,
void **arg) {
uint8_t *key_buffer = (uint8_t *)(*arg);
if (stream->bytes_left > BLE_GAP_PASSKEY_LEN) {
return false;
}
memset(key_buffer, 0, BLE_GAP_PASSKEY_LEN);
while (stream->bytes_left) {
// read data
if (!pb_read(stream, (pb_byte_t *)(key_buffer),
(stream->bytes_left > BLE_GAP_PASSKEY_LEN)
? BLE_GAP_PASSKEY_LEN
: stream->bytes_left)) {
return false;
}
}
return true;
}
static bool write_authkey(pb_ostream_t *stream, const pb_field_t *field,
void *const *arg) {
uint8_t *key = (uint8_t *)(*arg);
if (!pb_encode_tag_for_field(stream, field)) return false;
return pb_encode_string(stream, (uint8_t *)key, BLE_GAP_PASSKEY_LEN);
}
bool send_comparison_request(uint8_t *p_key, int8_t p_key_len) {
uint8_t iface_num = INTERNAL_MESSAGE;
MSG_SEND_INIT(ComparisonRequest);
MSG_SEND_CALLBACK(key, write_authkey, p_key);
MSG_SEND_NRF(ComparisonRequest);
MSG_RECV_INIT(Success);
secbool result = await_response(MessageType_MessageType_Success,
process_success, &msg_recv);
if (result != sectrue) {
return false;
}
return true;
}
bool send_auth_key_request(uint8_t *p_key, uint8_t p_key_len) {
uint8_t iface_num = INTERNAL_MESSAGE;
MSG_SEND_INIT(PairingRequest);
MSG_SEND_NRF(PairingRequest);
uint8_t buffer[BLE_GAP_PASSKEY_LEN];
MSG_RECV_INIT(AuthKey);
MSG_RECV_CALLBACK(key, read_authkey, buffer);
secbool result = await_response(MessageType_MessageType_AuthKey,
process_auth_key, &msg_recv);
if (result != sectrue) {
return false;
}
memcpy(p_key, buffer,
BLE_GAP_PASSKEY_LEN > p_key_len ? p_key_len : BLE_GAP_PASSKEY_LEN);
return true;
}
bool send_repair_request(void) {
uint8_t iface_num = INTERNAL_MESSAGE;
MSG_SEND_INIT(RepairRequest);
MSG_SEND_NRF(RepairRequest);
MSG_RECV_INIT(Success);
secbool result = await_response(MessageType_MessageType_Success,
process_success, &msg_recv);
return result == sectrue;
}

@ -0,0 +1,27 @@
#ifndef __INT_COMM__
#define __INT_COMM__
#include "app_uart.h"
#include "ble_nus.h"
#include "stdint.h"
void spi_init(void);
void nus_init(void);
void nus_data_handler(ble_nus_evt_t *p_evt);
void uart_event_handle(app_uart_evt_t *p_event);
void send_status_event(void);
void send_success_event(void);
bool send_comparison_request(uint8_t *p_key, int8_t p_key_len);
bool send_auth_key_request(uint8_t *p_key, uint8_t p_key_len);
bool send_repair_request(void);
void send_initialized(void);
#endif

@ -0,0 +1,332 @@
/*********************************************************************
* (c) SEGGER Microcontroller GmbH *
* The Embedded Experts *
* www.segger.com *
**********************************************************************
File : /home/mbruna/CLionProjects/trezor-model_r/core/embed/ble_firmware/jlink.jdebug
Created : 6 Feb 2023 15:54
Ozone Version : V3.28c
*/
/*********************************************************************
*
* OnProjectLoad
*
* Function description
* Project load routine. Required.
*
**********************************************************************
*/
void OnProjectLoad (void) {
//
// Dialog-generated settings
//
Project.AddPathSubstitute (".", "$(ProjectDir)");
Project.AddPathSubstitute (".", "$(ProjectDir)");
Project.SetDevice ("Cortex-M4");
Project.SetHostIF ("USB", "");
Project.SetTargetIF ("SWD");
Project.SetTIFSpeed ("20 MHz");
Project.AddSvdFile ("$(InstallDir)/Config/CPU/Cortex-M4F.svd");
//
// User settings
//
File.Open ("../../build/ble_firmware/ble_firmware.elf");
}
/*********************************************************************
*
* OnStartupComplete
*
* Function description
* Called when program execution has reached/passed
* the startup completion point. Optional.
*
**********************************************************************
*/
//void OnStartupComplete (void) {
//}
/*********************************************************************
*
* TargetReset
*
* Function description
* Replaces the default target device reset routine. Optional.
*
* Notes
* This example demonstrates the usage when
* debugging an application in RAM on a Cortex-M target device.
*
**********************************************************************
*/
//void TargetReset (void) {
//
// unsigned int SP;
// unsigned int PC;
// unsigned int VectorTableAddr;
//
// VectorTableAddr = Elf.GetBaseAddr();
// //
// // Set up initial stack pointer
// //
// if (VectorTableAddr != 0xFFFFFFFF) {
// SP = Target.ReadU32(VectorTableAddr);
// Target.SetReg("SP", SP);
// }
// //
// // Set up entry point PC
// //
// PC = Elf.GetEntryPointPC();
//
// if (PC != 0xFFFFFFFF) {
// Target.SetReg("PC", PC);
// } else if (VectorTableAddr != 0xFFFFFFFF) {
// PC = Target.ReadU32(VectorTableAddr + 4);
// Target.SetReg("PC", PC);
// } else {
// Util.Error("Project file error: failed to set entry point PC", 1);
// }
//}
/*********************************************************************
*
* BeforeTargetReset
*
* Function description
* Event handler routine. Optional.
*
**********************************************************************
*/
//void BeforeTargetReset (void) {
//}
/*********************************************************************
*
* AfterTargetReset
*
* Function description
* Event handler routine. Optional.
* The default implementation initializes SP and PC to reset values.
**
**********************************************************************
*/
void AfterTargetReset (void) {
_SetupTarget();
}
/*********************************************************************
*
* DebugStart
*
* Function description
* Replaces the default debug session startup routine. Optional.
*
**********************************************************************
*/
//void DebugStart (void) {
//}
/*********************************************************************
*
* TargetConnect
*
* Function description
* Replaces the default target IF connection routine. Optional.
*
**********************************************************************
*/
//void TargetConnect (void) {
//}
/*********************************************************************
*
* BeforeTargetConnect
*
* Function description
* Event handler routine. Optional.
*
**********************************************************************
*/
void BeforeTargetConnect (void) {
Project.SetJLinkScript("./MMDScript.JLinkScript");
}
/*********************************************************************
*
* AfterTargetConnect
*
* Function description
* Event handler routine. Optional.
*
**********************************************************************
*/
//void AfterTargetConnect (void) {
//}
/*********************************************************************
*
* TargetDownload
*
* Function description
* Replaces the default program download routine. Optional.
*
**********************************************************************
*/
//void TargetDownload (void) {
//}
/*********************************************************************
*
* BeforeTargetDownload
*
* Function description
* Event handler routine. Optional.
*
**********************************************************************
*/
//void BeforeTargetDownload (void) {
//}
/*********************************************************************
*
* AfterTargetDownload
*
* Function description
* Event handler routine. Optional.
* The default implementation initializes SP and PC to reset values.
*
**********************************************************************
*/
void AfterTargetDownload (void) {
_SetupTarget();
}
/*********************************************************************
*
* BeforeTargetDisconnect
*
* Function description
* Event handler routine. Optional.
*
**********************************************************************
*/
//void BeforeTargetDisconnect (void) {
//}
/*********************************************************************
*
* AfterTargetDisconnect
*
* Function description
* Event handler routine. Optional.
*
**********************************************************************
*/
//void AfterTargetDisconnect (void) {
//}
/*********************************************************************
*
* AfterTargetHalt
*
* Function description
* Event handler routine. Optional.
*
**********************************************************************
*/
//void AfterTargetHalt (void) {
//}
/*********************************************************************
*
* BeforeTargetResume
*
* Function description
* Event handler routine. Optional.
*
**********************************************************************
*/
//void BeforeTargetResume (void) {
//}
/*********************************************************************
*
* OnSnapshotLoad
*
* Function description
* Called upon loading a snapshot. Optional.
*
* Additional information
* This function is used to restore the target state in cases
* where values cannot simply be written to the target.
* Typical use: GPIO clock needs to be enabled, before
* GPIO is configured.
*
**********************************************************************
*/
//void OnSnapshotLoad (void) {
//}
/*********************************************************************
*
* OnSnapshotSave
*
* Function description
* Called upon saving a snapshot. Optional.
*
* Additional information
* This function is usually used to save values of the target
* state which can either not be trivially read,
* or need to be restored in a specific way or order.
* Typically use: Memory Mapped Registers,
* such as PLL and GPIO configuration.
*
**********************************************************************
*/
//void OnSnapshotSave (void) {
//}
/*********************************************************************
*
* OnError
*
* Function description
* Called when an error ocurred. Optional.
*
**********************************************************************
*/
//void OnError (void) {
//}
/*********************************************************************
*
* AfterProjectLoad
*
* Function description
* After Project load routine. Optional.
*
**********************************************************************
*/
//void AfterProjectLoad (void) {
//}
/*********************************************************************
*
* _SetupTarget
*
* Function description
* Setup the target.
* Called by AfterTargetReset() and AfterTargetDownload().
*
* Auto-generated function. May be overridden by Ozone.
*
**********************************************************************
*/
void _SetupTarget(void) {
//
// this function is intentionally empty because both inital PC and
// initial SP were chosen not to be set
//
}

@ -0,0 +1,631 @@
/**
* Copyright (c) 2014 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be
* reverse engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
/** @file
*
* @defgroup ble_sdk_uart_over_ble_main main.c
* @{
* @ingroup ble_sdk_app_nus_eval
* @brief UART over BLE application main file.
*
* This file contains the source code for a sample application that uses the
* Nordic UART service. This application uses the @ref srvlib_conn_params
* module.
*/
#include <stdint.h>
#include <string.h>
#include "app_scheduler.h"
#include "app_timer.h"
#include "app_uart.h"
#include "app_util_platform.h"
#include "ble_conn_params.h"
#include "ble_hci.h"
#include "nordic_common.h"
#include "nrf.h"
#include "nrf_ble_gatt.h"
#include "nrf_ble_qwr.h"
#include "nrf_drv_uart.h"
#include "nrf_gpio.h"
#include "nrf_pwr_mgmt.h"
#include "nrf_sdh.h"
#include "nrf_sdh_ble.h"
#include "nrf_sdh_soc.h"
#include "trezor_t3w1_d1_NRF.h"
#if defined(SOFTDEVICE_PRESENT) && SOFTDEVICE_PRESENT
#include "nrf_sdm.h"
#endif
#if defined(UART_PRESENT)
#include "nrf_uart.h"
#endif
#if defined(UARTE_PRESENT)
#include "nrf_uarte.h"
#endif
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "advertising.h"
#include "ble_nus.h"
#include "connection.h"
#include "defs.h"
#include "dis.h"
#include "int_comm.h"
#include "nrf_ble_lesc.h"
#include "pm.h"
#include "power.h"
#define DEVICE_NAME \
"Trezor" /**< Name of device. Will be included in the advertising data. \
*/
#define APP_BLE_OBSERVER_PRIO \
3 /**< Application's BLE observer priority. You shouldn't need to modify \
this value. */
#define MIN_CONN_INTERVAL \
MSEC_TO_UNITS( \
7.5, UNIT_1_25_MS) /**< Minimum acceptable connection interval (20 ms), \
Connection interval uses 1.25 ms units. */
#define MAX_CONN_INTERVAL \
MSEC_TO_UNITS( \
7.5, UNIT_1_25_MS) /**< Maximum acceptable connection interval (75 ms), \
Connection interval uses 1.25 ms units. */
#define SLAVE_LATENCY 0 /**< Slave latency. */
#define CONN_SUP_TIMEOUT \
MSEC_TO_UNITS(4000, \
UNIT_10_MS) /**< Connection supervisory timeout (4 seconds), \
Supervision Timeout uses 10 ms units. */
#define FIRST_CONN_PARAMS_UPDATE_DELAY \
APP_TIMER_TICKS( \
5000) /**< Time from initiating event (connect or start of notification) \
to first time sd_ble_gap_conn_param_update is called (5 \
seconds). */
#define NEXT_CONN_PARAMS_UPDATE_DELAY \
APP_TIMER_TICKS( \
30000) /**< Time between each call to sd_ble_gap_conn_param_update after \
the first call (30 seconds). */
#define MAX_CONN_PARAMS_UPDATE_COUNT \
3 /**< Number of attempts before giving up the connection parameter \
negotiation. */
#define DEAD_BEEF \
0xDEADBEEF /**< Value used as error code on stack dump, can be used to \
identify stack location on stack unwind. */
#define UART_TX_BUF_SIZE 256 /**< UART TX buffer size. */
#define UART_RX_BUF_SIZE 256 /**< UART RX buffer size. */
NRF_BLE_GATT_DEF(m_gatt); /**< GATT module instance. */
NRF_BLE_QWR_DEF(m_qwr); /**< Context for the Queued Write module.*/
#define SCHED_MAX_EVENT_DATA_SIZE \
APP_TIMER_SCHED_EVENT_DATA_SIZE /**< Maximum size of scheduler events. */
#ifdef SVCALL_AS_NORMAL_FUNCTION
#define SCHED_QUEUE_SIZE \
20 /**< Maximum number of events in the scheduler queue. More is needed in \
case of Serialization. */
#else
#define SCHED_QUEUE_SIZE \
10 /**< Maximum number of events in the scheduler queue. */
#endif
static uint16_t m_ble_nus_max_data_len =
BLE_GATT_ATT_MTU_DEFAULT -
3; /**< Maximum length of data (in bytes) that can be transmitted to the
peer by the Nordic UART service module. */
/**@brief Function for assert macro callback.
*
* @details This function will be called in case of an assert in the SoftDevice.
*
* @warning On assert from the SoftDevice, the system can only recover on reset.
*
* @param[in] line_num Line number of the failing ASSERT call.
* @param[in] p_file_name File name of the failing ASSERT call.
*/
void assert_nrf_callback(uint16_t line_num, const uint8_t *p_file_name) {
app_error_handler(DEAD_BEEF, line_num, p_file_name);
}
/*lint -save -e14 */
/**
* Function is implemented as weak so that it can be overwritten by custom
* application error handler when needed.
*/
void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info) {
__disable_irq();
// signalize firmware not running
nrf_gpio_pin_clear(GPIO_2_PIN);
NRF_LOG_FINAL_FLUSH();
#ifndef DEBUG
NRF_LOG_ERROR("Fatal error");
#else
switch (id) {
#if defined(SOFTDEVICE_PRESENT) && SOFTDEVICE_PRESENT
case NRF_FAULT_ID_SD_ASSERT:
NRF_LOG_ERROR("SOFTDEVICE: ASSERTION FAILED");
break;
case NRF_FAULT_ID_APP_MEMACC:
NRF_LOG_ERROR("SOFTDEVICE: INVALID MEMORY ACCESS");
break;
#endif
case NRF_FAULT_ID_SDK_ASSERT: {
assert_info_t *p_info = (assert_info_t *)info;
NRF_LOG_ERROR("ASSERTION FAILED at %s:%u", p_info->p_file_name,
p_info->line_num);
break;
}
case NRF_FAULT_ID_SDK_ERROR: {
error_info_t *p_info = (error_info_t *)info;
NRF_LOG_ERROR("ERROR %u [%s] at %s:%u\r\nPC at: 0x%08x", p_info->err_code,
nrf_strerror_get(p_info->err_code), p_info->p_file_name,
p_info->line_num, pc);
NRF_LOG_ERROR("End of error report");
break;
}
default:
NRF_LOG_ERROR("UNKNOWN FAULT at 0x%08X", pc);
break;
}
#endif
NRF_BREAKPOINT_COND;
// On assert, the system can only recover with a reset.
#ifndef DEBUG
NRF_LOG_WARNING("System reset");
NVIC_SystemReset();
#else
app_error_save_and_stop(id, pc, info);
#endif // DEBUG
}
/**@brief Function for initializing the timer module.
*/
static void timers_init(void) {
ret_code_t err_code = app_timer_init();
APP_ERROR_CHECK(err_code);
}
/**@brief Function for the GAP initialization.
*
* @details This function will set up all the necessary GAP (Generic Access
* Profile) parameters of the device. It also sets the permissions and
* appearance.
*/
static void gap_params_init(void) {
uint32_t err_code;
ble_gap_conn_params_t gap_conn_params;
ble_gap_conn_sec_mode_t sec_mode;
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
err_code = sd_ble_gap_device_name_set(&sec_mode, (const uint8_t *)DEVICE_NAME,
strlen(DEVICE_NAME));
APP_ERROR_CHECK(err_code);
err_code = sd_ble_gap_appearance_set(BLE_APPEARANCE_UNKNOWN);
APP_ERROR_CHECK(err_code);
memset(&gap_conn_params, 0, sizeof(gap_conn_params));
gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL;
gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL;
gap_conn_params.slave_latency = SLAVE_LATENCY;
gap_conn_params.conn_sup_timeout = CONN_SUP_TIMEOUT;
err_code = sd_ble_gap_ppcp_set(&gap_conn_params);
APP_ERROR_CHECK(err_code);
}
/**@brief Function for handling Queued Write Module errors.
*
* @details A pointer to this function will be passed to each service which may
* need to inform the application about an error.
*
* @param[in] nrf_error Error code containing information about what went
* wrong.
*/
static void nrf_qwr_error_handler(uint32_t nrf_error) {
APP_ERROR_HANDLER(nrf_error);
}
/**@brief Function for initializing services that will be used by the
* application.
*/
static void services_init(void) {
uint32_t err_code;
nrf_ble_qwr_init_t qwr_init = {0};
// Initialize Queued Write Module.
qwr_init.error_handler = nrf_qwr_error_handler;
err_code = nrf_ble_qwr_init(&m_qwr, &qwr_init);
APP_ERROR_CHECK(err_code);
dis_init();
nus_init();
}
/**@brief Function for handling errors from the Connection Parameters module.
*
* @param[in] nrf_error Error code containing information about what went
* wrong.
*/
static void conn_params_error_handler(uint32_t nrf_error) {
APP_ERROR_HANDLER(nrf_error);
}
/**@brief Function for initializing the Connection Parameters module.
*/
static void conn_params_init(void) {
uint32_t err_code;
ble_conn_params_init_t cp_init;
memset(&cp_init, 0, sizeof(cp_init));
cp_init.p_conn_params = NULL;
cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY;
cp_init.next_conn_params_update_delay = NEXT_CONN_PARAMS_UPDATE_DELAY;
cp_init.max_conn_params_update_count = MAX_CONN_PARAMS_UPDATE_COUNT;
cp_init.start_on_notify_cccd_handle = BLE_GATT_HANDLE_INVALID;
cp_init.disconnect_on_fail = false;
cp_init.evt_handler = NULL;
cp_init.error_handler = conn_params_error_handler;
err_code = ble_conn_params_init(&cp_init);
APP_ERROR_CHECK(err_code);
}
/**@brief Function for handling BLE events.
*
* @param[in] p_ble_evt Bluetooth stack event.
* @param[in] p_context Unused.
*/
static void ble_evt_handler(ble_evt_t const *p_ble_evt, void *p_context) {
uint32_t err_code;
char passkey[BLE_GAP_PASSKEY_LEN + 1] = {0};
switch (p_ble_evt->header.evt_id) {
case BLE_GAP_EVT_CONNECTED:
NRF_LOG_INFO("Connected");
// err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);
// APP_ERROR_CHECK(err_code);
uint16_t handle = p_ble_evt->evt.gap_evt.conn_handle;
set_connection_handle(handle);
send_status_event();
err_code = nrf_ble_qwr_conn_handle_assign(&m_qwr, handle);
APP_ERROR_CHECK(err_code);
break;
case BLE_GAP_EVT_DISCONNECTED:
NRF_LOG_INFO("Disconnected");
// bsp_indication_set(BSP_INDICATE_IDLE);
set_connection_handle(BLE_CONN_HANDLE_INVALID);
send_status_event();
break;
case BLE_GAP_EVT_PHY_UPDATE_REQUEST: {
NRF_LOG_DEBUG("PHY update request.");
ble_gap_phys_t const phys = {
.rx_phys = BLE_GAP_PHY_AUTO,
.tx_phys = BLE_GAP_PHY_AUTO,
};
err_code =
sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys);
APP_ERROR_CHECK(err_code);
} break;
case BLE_GAP_EVT_PASSKEY_DISPLAY:
memcpy(passkey, p_ble_evt->evt.gap_evt.params.passkey_display.passkey,
BLE_GAP_PASSKEY_LEN);
NRF_LOG_INFO("BLE_GAP_EVT_PASSKEY_DISPLAY: passkey=%s match_req=%d",
nrf_log_push(passkey),
p_ble_evt->evt.gap_evt.params.passkey_display.match_request);
if (p_ble_evt->evt.gap_evt.params.passkey_display.match_request) {
bool ok =
send_comparison_request((uint8_t *)passkey, BLE_GAP_PASSKEY_LEN);
if (ok) {
sd_ble_gap_auth_key_reply(p_ble_evt->evt.gap_evt.conn_handle,
BLE_GAP_AUTH_KEY_TYPE_PASSKEY, NULL);
} else {
sd_ble_gap_auth_key_reply(p_ble_evt->evt.gap_evt.conn_handle,
BLE_GAP_AUTH_KEY_TYPE_NONE, NULL);
}
}
break;
case BLE_GAP_EVT_LESC_DHKEY_REQUEST:
NRF_LOG_INFO("BLE_GAP_EVT_LESC_DHKEY_REQUEST");
break;
case BLE_GAP_EVT_AUTH_KEY_REQUEST: {
NRF_LOG_INFO("Key requested.");
bool ok = send_auth_key_request((uint8_t *)passkey, BLE_GAP_PASSKEY_LEN);
sd_ble_gap_auth_key_reply(p_ble_evt->evt.gap_evt.conn_handle,
BLE_GAP_AUTH_KEY_TYPE_PASSKEY,
(uint8_t *)passkey);
if (ok) {
NRF_LOG_INFO("Received data: %c", passkey);
} else {
NRF_LOG_INFO("Auth key request failed.");
}
// APP_ERROR_CHECK(err_code);
break;
}
case BLE_GATTC_EVT_TIMEOUT:
// Disconnect on GATT Client timeout event.
err_code =
sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle,
BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
APP_ERROR_CHECK(err_code);
break;
case BLE_GATTS_EVT_TIMEOUT:
// Disconnect on GATT Server timeout event.
err_code =
sd_ble_gap_disconnect(p_ble_evt->evt.gatts_evt.conn_handle,
BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
APP_ERROR_CHECK(err_code);
break;
default:
// No implementation needed.
break;
}
}
/**@brief Function for the SoftDevice initialization.
*
* @details This function initializes the SoftDevice and the BLE event
* interrupt.
*/
static void ble_stack_init(void) {
ret_code_t err_code;
err_code = nrf_sdh_enable_request();
APP_ERROR_CHECK(err_code);
// Configure the BLE stack using the default settings.
// Fetch the start address of the application RAM.
uint32_t ram_start = 0;
err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start);
APP_ERROR_CHECK(err_code);
// Enable BLE stack.
err_code = nrf_sdh_ble_enable(&ram_start);
APP_ERROR_CHECK(err_code);
// Register a handler for BLE events.
NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler,
NULL);
}
/**@brief Function for handling events from the GATT library. */
void gatt_evt_handler(nrf_ble_gatt_t *p_gatt, nrf_ble_gatt_evt_t const *p_evt) {
if ((get_connection_handle() == p_evt->conn_handle) &&
(p_evt->evt_id == NRF_BLE_GATT_EVT_ATT_MTU_UPDATED)) {
m_ble_nus_max_data_len =
p_evt->params.att_mtu_effective - OPCODE_LENGTH - HANDLE_LENGTH;
NRF_LOG_INFO("Data len is set to 0x%X(%d)", m_ble_nus_max_data_len,
m_ble_nus_max_data_len);
}
NRF_LOG_DEBUG("ATT MTU exchange completed. central 0x%x peripheral 0x%x",
p_gatt->att_mtu_desired_central,
p_gatt->att_mtu_desired_periph);
}
/**@brief Function for initializing the GATT library. */
void gatt_init(void) {
ret_code_t err_code;
err_code = nrf_ble_gatt_init(&m_gatt, gatt_evt_handler);
APP_ERROR_CHECK(err_code);
err_code =
nrf_ble_gatt_att_mtu_periph_set(&m_gatt, NRF_SDH_BLE_GATT_MAX_MTU_SIZE);
APP_ERROR_CHECK(err_code);
}
///**@brief Function for handling events from the BSP module.
// *
// * @param[in] event Event generated by button press.
// */
// void bsp_event_handler(bsp_event_t event) {
// uint32_t err_code;
// switch (event) {
// case BSP_EVENT_SLEEP:
// sleep_mode_enter();
// break;
//
// case BSP_EVENT_DISCONNECT:
// err_code = sd_ble_gap_disconnect(
// get_connection_handle(), BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
// if (err_code != NRF_ERROR_INVALID_STATE) {
// APP_ERROR_CHECK(err_code);
// }
// break;
//
// case BSP_EVENT_WHITELIST_OFF:
// if (get_connection_handle() == BLE_CONN_HANDLE_INVALID) {
// advertising_restart_without_whitelist();
// }
// break;
//
// default:
// break;
// }
//}
/**@brief Function for initializing the UART module.
*/
/**@snippet [UART Initialization] */
static void uart_init(void) {
uint32_t err_code;
app_uart_comm_params_t const comm_params = {
.rx_pin_no = RX_PIN_NUMBER,
.tx_pin_no = TX_PIN_NUMBER,
.rts_pin_no = RTS_PIN_NUMBER,
.cts_pin_no = CTS_PIN_NUMBER,
.flow_control = APP_UART_FLOW_CONTROL_ENABLED,
.use_parity = false,
#if defined(UART_PRESENT)
.baud_rate = NRF_UART_BAUDRATE_1000000
#else
.baud_rate = NRF_UARTE_BAUDRATE_1000000
#endif
};
APP_UART_FIFO_INIT(&comm_params, UART_RX_BUF_SIZE, UART_TX_BUF_SIZE,
uart_event_handle, APP_IRQ_PRIORITY_LOWEST, err_code);
APP_ERROR_CHECK(err_code);
}
/**@snippet [UART Initialization] */
///**@brief Function for initializing buttons and leds.
// *
// * @param[out] p_erase_bonds Will be true if the clear bonding button was
// * pressed to wake the application up.
// */
// static void buttons_leds_init(bool *p_erase_bonds) {
// bsp_event_t startup_event;
//
// uint32_t err_code =
// bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, bsp_event_handler);
// APP_ERROR_CHECK(err_code);
//
// err_code = bsp_btn_ble_init(NULL, &startup_event);
// APP_ERROR_CHECK(err_code);
//
// *p_erase_bonds = (startup_event == BSP_EVENT_CLEAR_BONDING_DATA);
//}
/**@brief Function for initializing the nrf log module.
*/
static void log_init(void) {
ret_code_t err_code = NRF_LOG_INIT(NULL);
APP_ERROR_CHECK(err_code);
NRF_LOG_DEFAULT_BACKENDS_INIT();
}
/**@brief Function for initializing power management.
*/
static void power_management_init(void) {
ret_code_t err_code;
err_code = nrf_pwr_mgmt_init();
APP_ERROR_CHECK(err_code);
}
/**@brief Function for handling the idle state (main loop).
*
* @details If there is no pending log operation, then sleep until next the next
* event occurs.
*/
static void idle_state_handle(void) {
app_sched_execute();
if (NRF_LOG_PROCESS() == false) {
nrf_pwr_mgmt_run();
}
}
/**@brief Function for the Event Scheduler initialization.
*/
static void scheduler_init(void) {
APP_SCHED_INIT(SCHED_MAX_EVENT_DATA_SIZE, SCHED_QUEUE_SIZE);
}
/**@brief Application main function.
*/
int main(void) {
bool erase_bonds = false;
nrf_gpio_cfg_output(GPIO_1_PIN);
nrf_gpio_cfg_output(GPIO_2_PIN);
nrf_gpio_pin_clear(GPIO_1_PIN);
// Initialize.
spi_init();
uart_init();
log_init();
timers_init();
// buttons_leds_init(&erase_bonds);
power_management_init();
ble_stack_init();
scheduler_init();
gap_params_init();
gatt_init();
services_init();
advertising_init();
conn_params_init();
peer_manager_init();
// signalize firmware running
nrf_gpio_pin_set(GPIO_2_PIN);
send_status_event();
if (erase_bonds) {
delete_bonds();
}
// Enter main loop.
for (;;) {
nrf_ble_lesc_request_handler();
idle_state_handle();
}
}
/**
* @}
*/

@ -0,0 +1,130 @@
/* Linker script to configure memory regions. */
SEARCH_DIR(.)
GROUP(-lgcc -lc -lnosys)
MEMORY
{
FLASH (rx) : ORIGIN = 0x27000, LENGTH = 0x49000
RAM (rwx) : ORIGIN = 0x20002ae8, LENGTH = 0x1d518
}
SECTIONS
{
}
SECTIONS
{
. = ALIGN(4);
.mem_section_dummy_ram :
{
}
.cli_sorted_cmd_ptrs :
{
PROVIDE(__start_cli_sorted_cmd_ptrs = .);
KEEP(*(.cli_sorted_cmd_ptrs))
PROVIDE(__stop_cli_sorted_cmd_ptrs = .);
} > RAM
.fs_data :
{
PROVIDE(__start_fs_data = .);
KEEP(*(.fs_data))
PROVIDE(__stop_fs_data = .);
} > RAM
.log_dynamic_data :
{
PROVIDE(__start_log_dynamic_data = .);
KEEP(*(SORT(.log_dynamic_data*)))
PROVIDE(__stop_log_dynamic_data = .);
} > RAM
.log_filter_data :
{
PROVIDE(__start_log_filter_data = .);
KEEP(*(SORT(.log_filter_data*)))
PROVIDE(__stop_log_filter_data = .);
} > RAM
} INSERT AFTER .data;
SECTIONS
{
.mem_section_dummy_rom :
{
}
.sdh_soc_observers :
{
PROVIDE(__start_sdh_soc_observers = .);
KEEP(*(SORT(.sdh_soc_observers*)))
PROVIDE(__stop_sdh_soc_observers = .);
} > FLASH
.sdh_ble_observers :
{
PROVIDE(__start_sdh_ble_observers = .);
KEEP(*(SORT(.sdh_ble_observers*)))
PROVIDE(__stop_sdh_ble_observers = .);
} > FLASH
.pwr_mgmt_data :
{
PROVIDE(__start_pwr_mgmt_data = .);
KEEP(*(SORT(.pwr_mgmt_data*)))
PROVIDE(__stop_pwr_mgmt_data = .);
} > FLASH
.sdh_req_observers :
{
PROVIDE(__start_sdh_req_observers = .);
KEEP(*(SORT(.sdh_req_observers*)))
PROVIDE(__stop_sdh_req_observers = .);
} > FLASH
.sdh_state_observers :
{
PROVIDE(__start_sdh_state_observers = .);
KEEP(*(SORT(.sdh_state_observers*)))
PROVIDE(__stop_sdh_state_observers = .);
} > FLASH
.sdh_stack_observers :
{
PROVIDE(__start_sdh_stack_observers = .);
KEEP(*(SORT(.sdh_stack_observers*)))
PROVIDE(__stop_sdh_stack_observers = .);
} > FLASH
.nrf_queue :
{
PROVIDE(__start_nrf_queue = .);
KEEP(*(.nrf_queue))
PROVIDE(__stop_nrf_queue = .);
} > FLASH
.nrf_balloc :
{
PROVIDE(__start_nrf_balloc = .);
KEEP(*(.nrf_balloc))
PROVIDE(__stop_nrf_balloc = .);
} > FLASH
.cli_command :
{
PROVIDE(__start_cli_command = .);
KEEP(*(.cli_command))
PROVIDE(__stop_cli_command = .);
} > FLASH
.crypto_data :
{
PROVIDE(__start_crypto_data = .);
KEEP(*(SORT(.crypto_data*)))
PROVIDE(__stop_crypto_data = .);
} > FLASH
.log_const_data :
{
PROVIDE(__start_log_const_data = .);
KEEP(*(SORT(.log_const_data*)))
PROVIDE(__stop_log_const_data = .);
} > FLASH
.log_backends :
{
PROVIDE(__start_log_backends = .);
KEEP(*(SORT(.log_backends*)))
PROVIDE(__stop_log_backends = .);
} > FLASH
} INSERT AFTER .text
INCLUDE "nrf_common.ld"

@ -0,0 +1,156 @@
#include "nrf_log.h"
#include "peer_manager_handler.h"
#include "int_comm.h"
#include "pm.h"
#define SEC_PARAM_BOND 1 /**< Perform bonding. */
#define SEC_PARAM_MITM 1 /**< Man In The Middle protection not required. */
#define SEC_PARAM_LESC 1 /**< LE Secure Connections not enabled. */
#define SEC_PARAM_KEYPRESS 0 /**< Keypress notifications not enabled. */
#define SEC_PARAM_IO_CAPABILITIES \
BLE_GAP_IO_CAPS_KEYBOARD_DISPLAY /**< No I/O capabilities. */
#define SEC_PARAM_OOB 0 /**< Out Of Band data not available. */
#define SEC_PARAM_MIN_KEY_SIZE 7 /**< Minimum encryption key size. */
#define SEC_PARAM_MAX_KEY_SIZE 16 /**< Maximum encryption key size. */
static pm_peer_id_t
m_peer_id; /**< Device reference handle to the current bonded central. */
pm_peer_id_t get_peer_id(void) { return m_peer_id; }
/**@brief Function for setting filtered whitelist.
*
* @param[in] skip Filter passed to @ref pm_peer_id_list.
*/
void whitelist_set(pm_peer_id_list_skip_t skip) {
pm_peer_id_t peer_ids[BLE_GAP_WHITELIST_ADDR_MAX_COUNT];
uint32_t peer_id_count = BLE_GAP_WHITELIST_ADDR_MAX_COUNT;
ret_code_t err_code =
pm_peer_id_list(peer_ids, &peer_id_count, PM_PEER_ID_INVALID, skip);
APP_ERROR_CHECK(err_code);
NRF_LOG_INFO("\tm_whitelist_peer_cnt %d, MAX_PEERS_WLIST %d",
peer_id_count + 1, BLE_GAP_WHITELIST_ADDR_MAX_COUNT);
err_code = pm_whitelist_set(peer_ids, peer_id_count);
APP_ERROR_CHECK(err_code);
}
/**@brief Function for handling Peer Manager events.
*
* @param[in] p_evt Peer Manager event.
*/
void pm_evt_handler(pm_evt_t const *p_evt) {
pm_handler_on_pm_evt(p_evt);
pm_handler_disconnect_on_sec_failure(p_evt);
pm_handler_flash_clean(p_evt);
switch (p_evt->evt_id) {
case PM_EVT_CONN_SEC_SUCCEEDED:
m_peer_id = p_evt->peer_id;
break;
case PM_EVT_PEERS_DELETE_SUCCEEDED:
// advertising_start(false);
break;
case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED:
if (p_evt->params.peer_data_update_succeeded.flash_changed &&
(p_evt->params.peer_data_update_succeeded.data_id ==
PM_PEER_DATA_ID_BONDING)) {
NRF_LOG_INFO("New Bond, add the peer to the whitelist if possible");
// Note: You should check on what kind of white list policy your
// application should use.
whitelist_set(PM_PEER_ID_LIST_SKIP_NO_ID_ADDR);
}
break;
case PM_EVT_CONN_SEC_CONFIG_REQ: {
bool ok = send_repair_request();
if (ok) {
// Allow pairing request from an already bonded peer.
pm_conn_sec_config_t conn_sec_config = {.allow_repairing = true};
pm_conn_sec_config_reply(p_evt->conn_handle, &conn_sec_config);
} else {
// Reject pairing request from an already bonded peer.
pm_conn_sec_config_t conn_sec_config = {.allow_repairing = false};
pm_conn_sec_config_reply(p_evt->conn_handle, &conn_sec_config);
}
} break;
default:
break;
}
}
/**@brief Function for the Peer Manager initialization.
*/
void peer_manager_init(void) {
ble_gap_sec_params_t sec_param;
pm_privacy_params_t privacy_params;
ret_code_t err_code;
err_code = pm_init();
APP_ERROR_CHECK(err_code);
memset(&sec_param, 0, sizeof(ble_gap_sec_params_t));
// Security parameters to be used for all security procedures.
sec_param.bond = SEC_PARAM_BOND;
sec_param.mitm = SEC_PARAM_MITM;
sec_param.lesc = SEC_PARAM_LESC;
sec_param.keypress = SEC_PARAM_KEYPRESS;
sec_param.io_caps = SEC_PARAM_IO_CAPABILITIES;
sec_param.oob = SEC_PARAM_OOB;
sec_param.min_key_size = SEC_PARAM_MIN_KEY_SIZE;
sec_param.max_key_size = SEC_PARAM_MAX_KEY_SIZE;
sec_param.kdist_own.enc = 1;
sec_param.kdist_own.id = 1;
sec_param.kdist_peer.enc = 1;
sec_param.kdist_peer.id = 1;
err_code = pm_sec_params_set(&sec_param);
APP_ERROR_CHECK(err_code);
privacy_params.p_device_irk = NULL;
privacy_params.privacy_mode = BLE_GAP_PRIVACY_MODE_DEVICE_PRIVACY;
privacy_params.private_addr_cycle_s = 0;
privacy_params.private_addr_type =
BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE;
pm_privacy_set(&privacy_params);
err_code = pm_register(pm_evt_handler);
APP_ERROR_CHECK(err_code);
}
/**@brief Function for setting filtered device identities.
*
* @param[in] skip Filter passed to @ref pm_peer_id_list.
*/
void identities_set(pm_peer_id_list_skip_t skip) {
pm_peer_id_t peer_ids[BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT];
uint32_t peer_id_count = BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT;
ret_code_t err_code =
pm_peer_id_list(peer_ids, &peer_id_count, PM_PEER_ID_INVALID, skip);
APP_ERROR_CHECK(err_code);
err_code = pm_device_identities_list_set(peer_ids, peer_id_count);
APP_ERROR_CHECK(err_code);
}
/////**@brief Clear bond information from persistent storage. */
void delete_bonds(void) {
ret_code_t err_code;
NRF_LOG_INFO("Erase bonds!");
// pm_whitelist_set(NULL, 0);
err_code = pm_peers_delete();
APP_ERROR_CHECK(err_code);
}

@ -0,0 +1,18 @@
#ifndef __PEER_MANAGER__
#define __PEER_MANAGER__
#include "peer_manager.h"
pm_peer_id_t get_peer_id(void);
void whitelist_set(pm_peer_id_list_skip_t skip);
void identities_set(pm_peer_id_list_skip_t skip);
/**@brief Function for the Peer Manager initialization.
*/
void peer_manager_init(void);
void delete_bonds(void);
#endif

@ -0,0 +1,21 @@
#include "power.h"
#include "app_error.h"
/**@brief Function for putting the chip into sleep mode.
*
* @note This function will not return.
*/
// void sleep_mode_enter(void) {
// uint32_t err_code = bsp_indication_set(BSP_INDICATE_IDLE);
// APP_ERROR_CHECK(err_code);
//
// // Prepare wakeup buttons.
// err_code = bsp_btn_ble_sleep_mode_prepare();
// APP_ERROR_CHECK(err_code);
//
// // Go to system-off mode (this function will not return; wakeup will cause
// a
// // reset).
// err_code = sd_power_system_off();
// APP_ERROR_CHECK(err_code);
// }

@ -0,0 +1,6 @@
#ifndef __POWER__
#define __POWER__
void sleep_mode_enter(void);
#endif

File diff suppressed because it is too large Load Diff

@ -0,0 +1,4 @@
#define VERSION_MAJOR 0
#define VERSION_MINOR 0
#define VERSION_PATCH 0
#define VERSION_BUILD 0

@ -98,6 +98,25 @@ def get_version(file: str) -> str:
return f"{major}.{minor}.{patch}"
def get_version_int(file):
major = 0
minor = 0
patch = 0
file = PROJECT_ROOT / file
with open(file, 'r') as f:
for line in f:
if line.startswith('#define VERSION_MAJOR '):
major = int(line.split('VERSION_MAJOR')[1].strip())
if line.startswith('#define VERSION_MINOR '):
minor = int(line.split('VERSION_MINOR')[1].strip())
if line.startswith('#define VERSION_PATCH '):
patch = int(line.split('VERSION_PATCH')[1].strip())
if major > 99 or minor > 99 or patch > 99:
raise Exception("Version number too large")
return major * 10000 + minor * 100 + patch
def get_git_revision_hash() -> str:
return subprocess.check_output(["git", "rev-parse", "HEAD"]).decode("ascii").strip()

@ -0,0 +1,35 @@
import click
import zipfile
def convert_file(archive, infile, outfile, name):
data = archive.read(infile)
with open(outfile, "w") as outfile:
outfile.write("// Firmware BLOB - automatically generated\n")
outfile.write("\n")
outfile.write(f"#ifndef __FW_BLOB_{name}_H__\n")
outfile.write(f"#define __FW_BLOB_{name}_H__ 1\n")
outfile.write("\n")
outfile.write(f"uint8_t {name}[] = " + "{")
for i, byte in enumerate(data):
if i % 16 == 0:
outfile.write("\n ")
outfile.write("0x{:02x}, ".format(byte))
outfile.write("\n};\n")
outfile.write("\n")
outfile.write("#endif\n")
@click.command()
@click.argument("infile", type=click.File("rb"))
def convert(infile):
with zipfile.ZipFile(infile) as archive:
convert_file(archive, "ble_firmware.bin", "./embed/firmware/dfu/ble_firmware_bin.h", "binfile")
convert_file(archive, "ble_firmware.dat", "./embed/firmware/dfu/ble_firmware_dat.h", "datfile")
if __name__ == "__main__":
convert()

@ -0,0 +1 @@
nrfutil settings generate --family NRF52 --bootloader-version 0 --bl-settings-version 2 --app-boot-validation VALIDATE_ECDSA_P256_SHA256 --application ./build/ble_firmware/ble_firmware.hex --application-version 0 --sd-boot-validation VALIDATE_ECDSA_P256_SHA256 --softdevice ./embed/sdk/nrf52/components/softdevice/s140/hex/s140_nrf52_7.2.0_softdevice.hex --key-file ./embed/ble_bootloader/priv.pem ./build/ble_bootloader/settings.hex

@ -12,3 +12,5 @@
^\./crypto/sha3
^\./legacy/vendor
^\./core/embed/segger
^\./core/embed/ble_bootloader/uecc
^\./core/embed/sdk

Loading…
Cancel
Save