cryptnox-pos 1.0.0
Standalone USDC payment terminal firmware (ESP32 + Cryptnox smart card)
Loading...
Searching...
No Matches
settings_rules.h
Go to the documentation of this file.
1/*
2 * SPDX-License-Identifier: LGPL-3.0-or-later
3 * Copyright (c) 2026 Cryptnox SA
4 */
5
17
18#ifndef SETTINGS_RULES_H
19#define SETTINGS_RULES_H
20
21#include <stdbool.h>
22#include <stddef.h>
23#include <stdint.h>
24#include <stdio.h>
25#include <string.h>
26
27#include "CW_Utils.h" /* secure_wipe (CODING_RULES §1.4) */
28#include "civil_time.h" /* CIVIL_DST__COUNT */
29#include "keccak256.h"
30#include "settings.h" /* TZ_OFFSET_MIN / _MAX, SETTINGS_PAYOUT_MAX */
31
32/******************************************************************
33 * Time zone
34 ******************************************************************/
35
36/* Minutes east of UTC are stored biased, so they fit the unsigned NVS helpers
37 * and a missing key reads as UTC rather than as UTC-12. */
38#define TZ_OFFSET_BIAS 720
39
41static inline bool tz_offset_valid(long minutes)
42{
43 return (minutes >= TZ_OFFSET_MIN) && (minutes <= TZ_OFFSET_MAX);
44}
45
47static inline uint32_t tz_offset_encode(int16_t minutes)
48{
49 return (uint32_t)((int32_t)minutes + TZ_OFFSET_BIAS);
50}
51
53static inline int16_t tz_offset_decode(uint32_t raw)
54{
55 if (raw > (uint32_t)(TZ_OFFSET_BIAS + TZ_OFFSET_MAX)) {
56 return 0;
57 }
58 return (int16_t)((int32_t)raw - TZ_OFFSET_BIAS);
59}
60
62static inline bool tz_dst_valid(long rule)
63{
64 return (rule >= 0) && (rule < (long)CIVIL_DST__COUNT);
65}
66
68static inline uint8_t tz_dst_decode(uint8_t r)
69{
70 return (r < (uint8_t)CIVIL_DST__COUNT) ? r : (uint8_t)CIVIL_DST_NONE;
71}
72
73/******************************************************************
74 * Gas fees
75 ******************************************************************/
76
77/* Bounds are the ones the panel's steppers used to enforce, so a stored value
78 * cannot become something the old UI could not express. */
79#define FEE_GWEI_MIN 1UL
80#define FEE_GWEI_MAX 500UL
81
88
90static inline fee_pair_t fee_pair_check(unsigned long max_gwei, unsigned long prio_gwei)
91{
92 if ((max_gwei < FEE_GWEI_MIN) || (max_gwei > FEE_GWEI_MAX) ||
93 (prio_gwei < FEE_GWEI_MIN) || (prio_gwei > FEE_GWEI_MAX)) {
95 }
96 if (prio_gwei > max_gwei) { return FEE_PAIR_TIP_ABOVE_MAX; }
97 return FEE_PAIR_OK;
98}
99
100/******************************************************************
101 * Admin code
102 ******************************************************************/
103
104#define ADMIN_SALT_LEN 16U
105#define ADMIN_HASH_LEN 32U
106/* Longest code that goes into the digest. Deliberately NOT ui.cpp's
107 * ADMIN_CODE_MAX (9) — same name, different layer. Anything past this is
108 * silently dropped from the hash, so keep it comfortably above the UI's cap. */
109#define ADMIN_CODE_HASH_MAX 32U
110
120static inline void admin_derive(const char *code, const uint8_t *salt,
121 uint8_t out[ADMIN_HASH_LEN])
122{
123 uint8_t buf[ADMIN_SALT_LEN + ADMIN_CODE_HASH_MAX];
124 const size_t clen = strnlen(code, ADMIN_CODE_HASH_MAX);
125
126 (void)memcpy(buf, salt, ADMIN_SALT_LEN);
127 (void)memcpy(buf + ADMIN_SALT_LEN, code, clen);
128 keccak256(buf, ADMIN_SALT_LEN + clen, out);
129 CW_Utils::secure_wipe(buf, sizeof(buf));
130}
131
132/******************************************************************
133 * Dual-stored addresses
134 ******************************************************************/
135
148static inline bool settings_addr_normalise(bool tron, const char *addr,
149 char norm[SETTINGS_PAYOUT_MAX])
150{
151 if ((addr == NULL) || (addr[0] == '\0')) { return false; }
152 if (strlen(addr) >= SETTINGS_PAYOUT_MAX) { return false; }
153
154 if (tron) {
155 (void)snprintf(norm, SETTINGS_PAYOUT_MAX, "%s", addr);
156 } else {
157 const bool prefixed = (addr[0] == '0') && ((addr[1] == 'x') || (addr[1] == 'X'));
158 (void)snprintf(norm, SETTINGS_PAYOUT_MAX, "0x%s", prefixed ? (addr + 2) : addr);
159 }
160 return true;
161}
162
163#endif /* SETTINGS_RULES_H */
TZ-independent calendar arithmetic and date-string parsing.
@ CIVIL_DST__COUNT
Definition civil_time.h:105
@ CIVIL_DST_NONE
Definition civil_time.h:100
void keccak256(const uint8_t *input, size_t length, uint8_t digest[32])
Compute the Keccak-256 digest of a buffer.
Original Keccak-256 digest as used by Ethereum.
Persistent device settings stored in NVS (backlight, Wi-Fi creds).
#define TZ_OFFSET_MIN
Widest real-world UTC offsets, in minutes: UTC-12:00 to UTC+14:00.
Definition settings.h:91
#define TZ_OFFSET_MAX
Definition settings.h:92
#define SETTINGS_PAYOUT_MAX
Longest payout address plus NUL — "0x" + 40 hex, or 34 base58 Tron.
Definition settings.h:214
static void admin_derive(const char *code, const uint8_t *salt, uint8_t out[ADMIN_HASH_LEN])
Derive the stored digest: a single keccak256 over salt || code.
static bool settings_addr_normalise(bool tron, const char *addr, char norm[SETTINGS_PAYOUT_MAX])
The form a payout address or contract is stored in: Tron as given, Ethereum "0x"-prefixed whichever w...
static uint32_t tz_offset_encode(int16_t minutes)
A valid offset in its stored, biased form.
#define FEE_GWEI_MIN
fee_pair_t
Verdict on a (max fee, tip) pair from the config page.
@ FEE_PAIR_OUT_OF_RANGE
@ FEE_PAIR_TIP_ABOVE_MAX
@ FEE_PAIR_OK
static bool tz_dst_valid(long rule)
true for a DST rule the clock knows.
#define ADMIN_CODE_HASH_MAX
static uint8_t tz_dst_decode(uint8_t r)
A stored DST rule, or no DST if it is not one the clock knows.
static int16_t tz_offset_decode(uint32_t raw)
The stored form back to minutes; nonsense in NVS is UTC, not a wild clock.
static bool tz_offset_valid(long minutes)
true for an offset the clock accepts (TZ_OFFSET_MIN .. _MAX).
#define ADMIN_SALT_LEN
#define TZ_OFFSET_BIAS
static fee_pair_t fee_pair_check(unsigned long max_gwei, unsigned long prio_gwei)
Check a (max fee, tip) pair in Gwei; the range is checked first.
#define ADMIN_HASH_LEN
#define FEE_GWEI_MAX