diff --git a/speculos/cxlib/nanosp-api-level-cx-15.elf b/speculos/cxlib/nanosp-api-level-cx-15.elf new file mode 100755 index 00000000..332301e8 Binary files /dev/null and b/speculos/cxlib/nanosp-api-level-cx-15.elf differ diff --git a/speculos/cxlib/nanox-api-level-cx-15.elf b/speculos/cxlib/nanox-api-level-cx-15.elf new file mode 100755 index 00000000..f7a84e08 Binary files /dev/null and b/speculos/cxlib/nanox-api-level-cx-15.elf differ diff --git a/speculos/cxlib/stax-api-level-cx-15.elf b/speculos/cxlib/stax-api-level-cx-15.elf new file mode 100755 index 00000000..65a04356 Binary files /dev/null and b/speculos/cxlib/stax-api-level-cx-15.elf differ diff --git a/speculos/fonts/nanosp-fonts-15.bin b/speculos/fonts/nanosp-fonts-15.bin new file mode 100644 index 00000000..180a0f81 Binary files /dev/null and b/speculos/fonts/nanosp-fonts-15.bin differ diff --git a/speculos/fonts/nanox-fonts-15.bin b/speculos/fonts/nanox-fonts-15.bin new file mode 100644 index 00000000..94949885 Binary files /dev/null and b/speculos/fonts/nanox-fonts-15.bin differ diff --git a/speculos/fonts/stax-fonts-15.bin b/speculos/fonts/stax-fonts-15.bin new file mode 100644 index 00000000..4dd8545a Binary files /dev/null and b/speculos/fonts/stax-fonts-15.bin differ diff --git a/speculos/main.py b/speculos/main.py index da531853..f1413157 100644 --- a/speculos/main.py +++ b/speculos/main.py @@ -139,7 +139,26 @@ def get_cx_infos(app_path): return sh_offset, sh_size, sh_load, cx_ram_size, cx_ram_load -def run_qemu(s1: socket.socket, s2: socket.socket, args: argparse.Namespace) -> int: +def get_elf_fonts_size(app_path): + with open(app_path, 'rb') as fp: + elf = ELFFile(fp) + text = elf.get_section_by_name('.text') + for seg in elf.iter_segments(): + if seg['p_type'] != 'PT_LOAD': + continue + if seg.section_in_segment(text): + break + else: + raise RuntimeError("No program header with text section!") + symtab = elf.get_section_by_name('.symtab') + bagl_fonts_symbol = symtab.get_symbol_by_name('C_bagl_fonts') + if bagl_fonts_symbol is not None: + return bagl_fonts_symbol[0]['st_size'] + + return 0 + + +def run_qemu(s1: socket.socket, s2: socket.socket, args: argparse.Namespace, is_bagl: bool) -> int: argv = ['qemu-arm-static'] if args.debug: @@ -170,13 +189,12 @@ def run_qemu(s1: socket.socket, s2: socket.socket, args: argparse.Namespace) -> else: logger.warn(f"Cx lib {cxlib_filepath} not found") - if args.model == "stax": - fonts_filepath = f"/fonts/{args.model}-fonts-{args.apiLevel}.bin" - fonts = pkg_resources.resource_filename(__name__, fonts_filepath) - if os.path.exists(fonts): - argv += ['-f', fonts] - else: - logger.warn(f"Fonts {fonts_filepath} not found") + fonts_filepath = f"/fonts/{args.model}-fonts-{args.apiLevel}.bin" + fonts = pkg_resources.resource_filename(__name__, fonts_filepath) + if os.path.exists(fonts): + argv += ['-f', fonts] + elif not is_bagl: + logger.warn(f"Fonts {fonts_filepath} not found") extra_ram = '' app_path = getattr(args, 'app.elf') @@ -185,6 +203,7 @@ def run_qemu(s1: socket.socket, s2: socket.socket, args: argparse.Namespace) -> load_offset, load_size, stack, stack_size, ram_addr, ram_size, \ text_load_addr, svc_call_address, svc_cx_call_address, \ fonts_addr, fonts_size = get_elf_infos(lib_path) + # Since binaries loaded as libs could also declare extra RAM page(s), collect them all if (ram_addr, ram_size) != (0, 0): arg = f'{ram_addr:#x}:{ram_size:#x}' @@ -317,6 +336,7 @@ def main(prog=None) -> int: # Init model and api_level if not specified from app elf metadata app_path = getattr(args, 'app.elf') + is_bagl = get_elf_fonts_size(app_path) != 0 metadata = get_elf_ledger_metadata(app_path) if not args.model: if "target" not in metadata: @@ -473,13 +493,14 @@ def main(prog=None) -> int: s1, s2 = socket.socketpair() - qemu_pid = run_qemu(s1, s2, args) + qemu_pid = run_qemu(s1, s2, args, is_bagl) s1.close() apdu = apdu_server.ApduServer(host="0.0.0.0", port=args.apdu_port) seph = seproxyhal.SeProxyHal( s2, model=args.model, + is_bagl=is_bagl, automation=automation_path, automation_server=automation_server, transport=args.usb) @@ -521,7 +542,7 @@ def main(prog=None) -> int: display_args = DisplayArgs(args.color, args.model, args.ontop, rendering, args.keymap, zoom, x, y) server_args = ServerArgs(apdu, apirun, button, finger, seph, vnc) - screen_notifier = ScreenNotifier(display_args, server_args) + screen_notifier = ScreenNotifier(display_args, server_args, is_bagl) if apirun is not None: assert automation_server is not None diff --git a/speculos/mcu/display.py b/speculos/mcu/display.py index a2749c27..e5f232f0 100644 --- a/speculos/mcu/display.py +++ b/speculos/mcu/display.py @@ -272,7 +272,7 @@ class DisplayNotifier(ABC): through VNC if activated. """ - def __init__(self, display_args: DisplayArgs, server_args: ServerArgs) -> None: + def __init__(self, display_args: DisplayArgs, server_args: ServerArgs, is_bagl: bool) -> None: # TODO: this should be Dict[int, IODevice], but in QtScreen, it is # a QSocketNotifier, which has a completely different interface # and is not used in the same way in the mcu/screen.py module. @@ -280,10 +280,11 @@ def __init__(self, display_args: DisplayArgs, server_args: ServerArgs) -> None: self._server_args = server_args self._display_args = display_args self._display: Display + self.is_bagl = is_bagl self.__init_notifiers() def _set_display_class(self, display_class: type): - self._display = display_class(self._display_args, self._server_args) + self._display = display_class(self._display_args, self._server_args, self.is_bagl) @property def display(self) -> Display: diff --git a/speculos/mcu/headless.py b/speculos/mcu/headless.py index f0df659b..61a349c8 100644 --- a/speculos/mcu/headless.py +++ b/speculos/mcu/headless.py @@ -11,12 +11,12 @@ class Headless(Display): - def __init__(self, display: DisplayArgs, server: ServerArgs) -> None: + def __init__(self, display: DisplayArgs, server: ServerArgs, is_bagl: bool) -> None: super().__init__(display, server) self.m = HeadlessPaintWidget(self.model, server.vnc) self._gl: GraphicLibrary - if display.model != "stax": + if is_bagl: self._gl = bagl.Bagl(self.m, MODELS[self.model].screen_size, self.model) else: self._gl = nbgl.NBGL(self.m, MODELS[self.model].screen_size, self.model) @@ -67,8 +67,8 @@ def _redraw(self) -> None: class HeadlessNotifier(DisplayNotifier): - def __init__(self, display_args: DisplayArgs, server_args: ServerArgs) -> None: - super().__init__(display_args, server_args) + def __init__(self, display_args: DisplayArgs, server_args: ServerArgs, is_bagl: bool) -> None: + super().__init__(display_args, server_args, is_bagl) self._set_display_class(Headless) def run(self) -> None: diff --git a/speculos/mcu/nbgl.py b/speculos/mcu/nbgl.py index 944a2ec4..5fbd4df4 100644 --- a/speculos/mcu/nbgl.py +++ b/speculos/mcu/nbgl.py @@ -47,7 +47,7 @@ def __init__(self, self.logger = logging.getLogger("NBGL") def __assert_area(self, area) -> None: - if area.y0 % 4 or area.height % 4: + if self.model == "stax" and (area.y0 % 4 or area.height % 4): raise AssertionError("X(%d) or height(%d) not 4 aligned " % (area.y0, area.height)) if area.x0 > self.SCREEN_WIDTH or (area.x0+area.width) > self.SCREEN_WIDTH: raise AssertionError("left edge (%d) or right edge (%d) out of screen" % (area.x0, (area.x0 + area.width))) diff --git a/speculos/mcu/ocr.py b/speculos/mcu/ocr.py index 1f03856e..12046a87 100644 --- a/speculos/mcu/ocr.py +++ b/speculos/mcu/ocr.py @@ -121,10 +121,11 @@ class OCR: MAX_BLANK_SPACE_NANO = 12 MAX_BLANK_SPACE_STAX = 24 - def __init__(self, model: str): + def __init__(self, model: str, is_bagl: bool): self.events: List[TextEvent] = [] # Store the model of the device self.model = model + self.is_bagl = is_bagl # Maximum space for a letter to be considered part of the same word if model == "stax": self.max_blank_space = OCR.MAX_BLANK_SPACE_STAX @@ -215,7 +216,7 @@ def analyze_bitmap(self, data: bytes) -> None: For older SKD versions, legacy behaviour is used: parsing internal fonts to find a matching bitmap. """ - if self.model == "stax": + if not self.is_bagl: # Can be called via SephTag.NBGL_DRAW_IMAGE or SephTag.NBGL_DRAW_IMAGE_RLE # In both cases, data contains: # - area (sizeof(nbgl_area_t)) diff --git a/speculos/mcu/rle_custom.py b/speculos/mcu/rle_custom.py index f98892d6..a251cb48 100755 --- a/speculos/mcu/rle_custom.py +++ b/speculos/mcu/rle_custom.py @@ -153,9 +153,8 @@ def values_to_bpp1(data): if bits != 7: output += bytes([byte]) - nb_bytes = len(data)/8 - if len(data) % 8: - nb_bytes += 1 + nb_bytes = (len(data)+7)//8 + assert len(output) == nb_bytes return output diff --git a/speculos/mcu/screen.py b/speculos/mcu/screen.py index 9d00a69b..d99ef01a 100644 --- a/speculos/mcu/screen.py +++ b/speculos/mcu/screen.py @@ -28,9 +28,10 @@ def __init__(self, parent, model: str, pixel_size: int, vnc: Optional[VNC] = Non self.pixel_size = pixel_size self.mPixmap = QPixmap() self.vnc = vnc + self.updateRequested = False def paintEvent(self, event: QEvent): - if self.pixels: + if self.pixels and self.updateRequested: pixmap = QPixmap(self.size() / self.pixel_size) pixmap.fill(Qt.white) painter = QPainter(pixmap) @@ -38,6 +39,7 @@ def paintEvent(self, event: QEvent): self._redraw(painter) self.mPixmap = pixmap self.pixels = {} + self.updateRequested = False qp = QPainter(self) copied_pixmap = self.mPixmap @@ -53,6 +55,7 @@ def update(self, # type: ignore[override] y: Optional[int] = None, w: Optional[int] = None, h: Optional[int] = None) -> bool: + self.updateRequested = True if x and y and w and h: QWidget.update(self, QRect(x, y, w, h)) else: @@ -192,16 +195,17 @@ def closeEvent(self, event: QEvent): class Screen(Display): - def __init__(self, display: DisplayArgs, server: ServerArgs) -> None: + def __init__(self, display: DisplayArgs, server: ServerArgs, is_bagl: bool) -> None: super().__init__(display, server) self.app: App self._gl: GraphicLibrary + self.is_bagl = is_bagl - def set_app(self, app: App) -> None: + def set_app(self, app: App, is_bagl: bool) -> None: self.app = app self.app.set_screen(self) model = self._display_args.model - if model != "stax": + if self.is_bagl: self._gl = bagl.Bagl(app.widget, MODELS[model].screen_size, model) else: self._gl = nbgl.NBGL(app.widget, MODELS[model].screen_size, model) @@ -244,13 +248,13 @@ def screen_update(self) -> bool: class QtScreenNotifier(DisplayNotifier): - def __init__(self, display_args: DisplayArgs, server_args: ServerArgs) -> None: + def __init__(self, display_args: DisplayArgs, server_args: ServerArgs, is_bagl: bool) -> None: self._qapp = QApplication([]) - super().__init__(display_args, server_args) + super().__init__(display_args, server_args, is_bagl) self._set_display_class(Screen) self._app_widget = App(self._qapp, display_args, server_args) assert isinstance(self.display, Screen) - self.display.set_app(self._app_widget) + self.display.set_app(self._app_widget, is_bagl) def _can_read(self, device: IODevice) -> None: try: diff --git a/speculos/mcu/screen_text.py b/speculos/mcu/screen_text.py index ea509b14..53a9acc1 100644 --- a/speculos/mcu/screen_text.py +++ b/speculos/mcu/screen_text.py @@ -100,12 +100,12 @@ def _redraw(self): class TextScreen(Display): - def __init__(self, display_args: DisplayArgs, server_args: ServerArgs) -> None: + def __init__(self, display_args: DisplayArgs, server_args: ServerArgs, is_bagl: bool) -> None: super().__init__(display_args, server_args) self.width, self.height = MODELS[display_args.model].screen_size self.m = TextWidget(self, display_args.model) - if display_args.model != "stax": + if is_bagl: self._gl = bagl.Bagl(self.m, MODELS[display_args.model].screen_size, display_args.model) else: raise NotImplementedError("This display can not emulate NBGL OS yet") @@ -151,8 +151,8 @@ def get_keypress(self) -> bool: class TextScreenNotifier(DisplayNotifier): - def __init__(self, display_args: DisplayArgs, server_args: ServerArgs) -> None: - super().__init__(display_args, server_args) + def __init__(self, display_args: DisplayArgs, server_args: ServerArgs, _is_bagl: bool) -> None: + super().__init__(display_args, server_args, _is_bagl) self._set_display_class(TextScreen) def run(self) -> None: diff --git a/speculos/mcu/seproxyhal.py b/speculos/mcu/seproxyhal.py index 97a63383..86971e28 100644 --- a/speculos/mcu/seproxyhal.py +++ b/speculos/mcu/seproxyhal.py @@ -242,6 +242,7 @@ class SeProxyHal(IODevice): def __init__(self, sock: socket, model: str, + is_bagl: bool, automation: Optional[Automation] = None, automation_server: Optional[BroadcastInterface] = None, transport: str = 'hid'): @@ -262,7 +263,7 @@ def __init__(self, self.usb = usb.USB(self.socket_helper.queue_packet, transport=transport) - self.ocr = OCR(model) + self.ocr = OCR(model, is_bagl) # A list of callback methods when an APDU response is received self.apdu_callbacks: List[Callable[[bytes], None]] = [] @@ -326,10 +327,10 @@ def can_read(self, screen: DisplayNotifier): # Publish the new screenshot, we'll upload its associated events shortly screen.display.gl.update_public_screenshot() - if screen.display.model != "stax" and screen.display.screen_update(): + if not isinstance(screen.display.gl, NBGL) and screen.display.screen_update(): if screen.display.model in ["nanox", "nanosp"]: self.events += self.ocr.get_events() - elif screen.display.model == "stax": + elif isinstance(screen.display.gl, NBGL): self.events += self.ocr.get_events() # Apply automation rules after having received a GENERAL_STATUS_LAST_COMMAND tag. It allows the diff --git a/src/bolos/bagl.c b/src/bolos/bagl.c index 04b2ab16..deaf3ce6 100644 --- a/src/bolos/bagl.c +++ b/src/bolos/bagl.c @@ -157,7 +157,7 @@ unsigned long sys_bagl_hal_draw_bitmap_within_rect( sys_io_seph_send(buf, len); } - return 0; + return 0x9000; // SWO_SUCCESS } unsigned long sys_screen_update(void) diff --git a/src/bolos/fonts_info.c b/src/bolos/fonts_info.c index 5000566b..ba42b193 100644 --- a/src/bolos/fonts_info.c +++ b/src/bolos/fonts_info.c @@ -12,8 +12,8 @@ typedef struct { uint32_t character; } BITMAP_CHAR; -BITMAP_CHAR bitmap_char[MAX_BITMAP_CHAR]; -uint32_t nb_bitmap_char; +static BITMAP_CHAR bitmap_char[MAX_BITMAP_CHAR]; +static uint32_t nb_bitmap_char; // Return the real addr depending on where the app was loaded static void *remap_addr(void *code, uint32_t addr, uint32_t text_load_addr) @@ -190,7 +190,7 @@ void parse_fonts(void *code, unsigned long text_load_addr, unsigned long fonts_addr, unsigned long fonts_size) { // Number of fonts stored at fonts_addr - uint32_t nb_fonts; + uint32_t nb_fonts = 0; uint32_t *fonts; nb_bitmap_char = 0; @@ -203,15 +203,31 @@ void parse_fonts(void *code, unsigned long text_load_addr, case SDK_API_LEVEL_12: case SDK_API_LEVEL_13: case SDK_API_LEVEL_14: + case SDK_API_LEVEL_15: break; default: // Unsupported API_LEVEL, will not parse fonts! return; } - // On Stax, fonts are loaded at a known location - if (hw_model == MODEL_STAX) { - fonts = (void *)STAX_FONTS_ARRAY_ADDR; - nb_fonts = STAX_NB_FONTS; + // With NBGL apps, fonts are loaded at a known location, in the OS + if (fonts_size == 0) { + if (hw_model == MODEL_STAX) { + fonts = (void *)STAX_FONTS_ARRAY_ADDR; + if (sdk_version >= SDK_API_LEVEL_15) { + nb_fonts = STAX_NB_FONTS; + } else { + nb_fonts = STAX_NB_FONTS_LEVEL_14; + } + } else if (hw_model == MODEL_NANO_SP) { + fonts = (void *)NANOSP_FONTS_ARRAY_ADDR; + nb_fonts = NANO_NB_FONTS; + } else if (hw_model == MODEL_NANO_X) { + fonts = (void *)NANOX_FONTS_ARRAY_ADDR; + nb_fonts = NANO_NB_FONTS; + } else { + return; + } + } else { fonts = remap_addr(code, fonts_addr, text_load_addr); nb_fonts = fonts_size / 4; @@ -236,7 +252,7 @@ void parse_fonts(void *code, unsigned long text_load_addr, // Parse all those fonts and add bitmap/character pairs for (uint32_t i = 0; i < nb_fonts; i++) { - if (hw_model == MODEL_STAX) { + if (fonts_size == 0) { switch (sdk_version) { case SDK_API_LEVEL_12: case SDK_API_LEVEL_13: diff --git a/src/bolos/nbgl.c b/src/bolos/nbgl.c index fbf9b92c..7b05c1d8 100644 --- a/src/bolos/nbgl.c +++ b/src/bolos/nbgl.c @@ -148,10 +148,34 @@ unsigned long sys_nbgl_front_draw_img_file(nbgl_area_t *area, uint8_t *buffer, unsigned long sys_nbgl_get_font(unsigned int fontId) { - if (fontId >= STAX_NB_FONTS) { - return 0; + if (hw_model == MODEL_STAX) { + unsigned int maxNbFonts; + if (sdk_version >= SDK_API_LEVEL_15) { + maxNbFonts = STAX_NB_FONTS; + } else { + maxNbFonts = STAX_NB_FONTS_LEVEL_14; + } + if (fontId >= maxNbFonts) { + return 0; + } else { + return *((unsigned int *)(STAX_FONTS_ARRAY_ADDR + (4 * fontId))); + } + } else if (hw_model == MODEL_NANO_SP) { + fontId -= 8; // BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp + if (fontId >= NANO_NB_FONTS) { + return 0; + } else { + return *((unsigned int *)(NANOSP_FONTS_ARRAY_ADDR + (4 * fontId))); + } + } else if (hw_model == MODEL_NANO_X) { + fontId -= 8; // BAGL_FONT_OPEN_SANS_EXTRABOLD_11px_1bpp + if (fontId >= NANO_NB_FONTS) { + return 0; + } else { + return *((unsigned int *)(NANOX_FONTS_ARRAY_ADDR + (4 * fontId))); + } } else { - return *((unsigned int *)(STAX_FONTS_ARRAY_ADDR + (4 * fontId))); + return 0; } } diff --git a/src/emulate_unified_sdk.c b/src/emulate_unified_sdk.c index b63e00e0..4eca22c7 100644 --- a/src/emulate_unified_sdk.c +++ b/src/emulate_unified_sdk.c @@ -73,7 +73,7 @@ int emulate_syscall_nbgl(unsigned long syscall, unsigned long *parameters, { (void)version; - if (model != MODEL_STAX) { + if ((model != MODEL_STAX) && (version < SDK_API_LEVEL_15)) { return SYSCALL_NOT_HANDLED; } diff --git a/src/fonts.h b/src/fonts.h index b4e13f5b..18abba54 100644 --- a/src/fonts.h +++ b/src/fonts.h @@ -5,9 +5,16 @@ // ============================================================================ #define STAX_FONTS_ARRAY_ADDR 0x00805000 -#define STAX_NB_FONTS 7 +// Up to API_LEVEL_14, 7 fonts +#define STAX_NB_FONTS_LEVEL_14 7 +// From API_LEVEL_15, 6 fonts +#define STAX_NB_FONTS 6 -#define MAX_NB_FONTS STAX_NB_FONTS +#define NANOSP_FONTS_ARRAY_ADDR 0x00805000 +#define NANOX_FONTS_ARRAY_ADDR 0x00205000 +#define NANO_NB_FONTS 3 + +#define MAX_NB_FONTS STAX_NB_FONTS_LEVEL_14 // ============================================================================ // BAGL font related structures diff --git a/src/launcher.c b/src/launcher.c index 4c831f8d..bcb44f46 100644 --- a/src/launcher.c +++ b/src/launcher.c @@ -441,7 +441,18 @@ static int load_fonts(char *fonts_path) int flags = MAP_PRIVATE | MAP_FIXED; int prot = PROT_READ; - int load_addr = STAX_FONTS_ARRAY_ADDR; + int load_addr = 0; + + if (hw_model == MODEL_STAX) { + load_addr = STAX_FONTS_ARRAY_ADDR; + } else if (hw_model == MODEL_NANO_SP) { + load_addr = NANOSP_FONTS_ARRAY_ADDR; + } else if (hw_model == MODEL_NANO_X) { + load_addr = NANOX_FONTS_ARRAY_ADDR; + } else { + warnx("hw_model %u not supported", hw_model); + return -1; + } void *p = mmap((void *)load_addr, load_size, prot, flags, fd, 0); fprintf(stderr, "[*] loaded fonts at %p\n", p); @@ -769,7 +780,8 @@ int main(int argc, char *argv[]) case MODEL_NANO_X: if (sdk_version != SDK_NANO_X_1_2 && sdk_version != SDK_NANO_X_2_0 && sdk_version != SDK_NANO_X_2_0_2 && sdk_version != SDK_API_LEVEL_1 && - sdk_version != SDK_API_LEVEL_5 && sdk_version != SDK_API_LEVEL_12) { + sdk_version != SDK_API_LEVEL_5 && sdk_version != SDK_API_LEVEL_12 && + sdk_version != SDK_API_LEVEL_15) { errx(1, "invalid SDK version for the Ledger Nano X"); } break; @@ -781,7 +793,7 @@ int main(int argc, char *argv[]) case MODEL_NANO_SP: if (sdk_version != SDK_NANO_SP_1_0 && sdk_version != SDK_NANO_SP_1_0_3 && sdk_version != SDK_API_LEVEL_1 && sdk_version != SDK_API_LEVEL_5 && - sdk_version != SDK_API_LEVEL_12) { + sdk_version != SDK_API_LEVEL_12 && sdk_version != SDK_API_LEVEL_15) { errx(1, "invalid SDK version for the Ledger NanoSP"); } break; @@ -791,7 +803,7 @@ int main(int argc, char *argv[]) sdk_version != SDK_API_LEVEL_8 && sdk_version != SDK_API_LEVEL_9 && sdk_version != SDK_API_LEVEL_10 && sdk_version != SDK_API_LEVEL_11 && sdk_version != SDK_API_LEVEL_12 && sdk_version != SDK_API_LEVEL_13 && - sdk_version != SDK_API_LEVEL_14) { + sdk_version != SDK_API_LEVEL_14 && sdk_version != SDK_API_LEVEL_15) { errx(1, "invalid SDK version for the Ledger Stax"); } break; @@ -818,7 +830,7 @@ int main(int argc, char *argv[]) init_environment(); - if (hw_model == MODEL_STAX && fonts_path) { + if (fonts_path) { if (load_fonts(fonts_path) != 0) { return 1; } diff --git a/src/sdk.h b/src/sdk.h index dd409b91..161f74a6 100644 --- a/src/sdk.h +++ b/src/sdk.h @@ -29,6 +29,7 @@ typedef enum { SDK_API_LEVEL_12, SDK_API_LEVEL_13, SDK_API_LEVEL_14, + SDK_API_LEVEL_15, SDK_COUNT } sdk_version_t; diff --git a/tests/c/test_environment.c b/tests/c/test_environment.c index 82c91a4a..4aa6dffa 100644 --- a/tests/c/test_environment.c +++ b/tests/c/test_environment.c @@ -60,12 +60,13 @@ static void check_is_default(field_e field) assert_memory_equal(&key[0], default_seed, MAX_SEED_SIZE); break; } - case FIELD_RNG: + case FIELD_RNG: { unsigned int now = time(NULL); // RNG is initialized in the past, not that long ago, but still // assert_int_equal(env_get_rng(), time(NULL)); can sometimes fail assert_in_range(env_get_rng(), now - 1, now); break; + } case FIELD_USER_KEY: { assert_memory_equal(env_get_user_private_key(1)->d, default_user_private_key,