Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
126 commits
Select commit Hold shift + click to select a range
693d737
release: open the 7.14.2 security line from the active release
BitHighlander Aug 17, 2026
01e9da4
chore(deps): pin device-protocol and python-keepkey to master for 7.14.2
BitHighlander Aug 17, 2026
12cbfda
fix(eip712): require a real confirmation before any EIP-712 signature
BitHighlander Aug 17, 2026
9707970
fix(evm): show the calldata disclosure for tokens outside the built-i…
BitHighlander Aug 17, 2026
efa18ad
fix(ton): stop displaying fields that are not bound to the signed raw_tx
BitHighlander Aug 17, 2026
06d3933
fix(solana): scale SPL amounts by the decimals inside the signed inst…
BitHighlander Aug 17, 2026
efacc79
fix(cosmos): display the IBC receiver that is actually signed
BitHighlander Aug 17, 2026
a84d62e
fix(osmosis): sign the denomination that was displayed
BitHighlander Aug 17, 2026
366edf1
fix(board): make silent confirmation truncation detectable
BitHighlander Aug 17, 2026
2e1de87
fix(eip712): bound the parseType appends by the destination, not the …
BitHighlander Aug 17, 2026
d674adf
fix(evm): refuse to clear-sign calldata that does not fit the initial…
BitHighlander Aug 17, 2026
b53b63b
fix(tron): stop displaying fields not bound to the signed raw_data, a…
BitHighlander Aug 17, 2026
a840824
fix(msg): disclose how much of a signed message was displayed
BitHighlander Aug 17, 2026
b1661f8
fix(evm): refuse to clear-sign calldata whose ABI encoding is not can…
BitHighlander Aug 17, 2026
354315c
fix(thorchain): bound the memo, and stop conflating a cancel with a p…
BitHighlander Aug 17, 2026
96e9578
docs(release): record what 7.14.2 deliberately does not fix
BitHighlander Aug 17, 2026
d2c5d68
style: clang-format the THORChain withdraw memo confirmation
BitHighlander Aug 17, 2026
feb36bc
ci: configure gitleaks so secret-scan reflects real risk
BitHighlander Aug 17, 2026
fd99fa7
fix(evm): gate the Uniswap clear-sign confirmations
BitHighlander Aug 17, 2026
5bccac0
fix(authenticator): honour the confirmation before mutating accounts
BitHighlander Aug 17, 2026
555bb31
fix(reset): disarm awaiting_entropy so an abandoned ceremony cannot b…
BitHighlander Aug 17, 2026
359b9b8
docs(release): add the three consent defects found by auditing this r…
BitHighlander Aug 17, 2026
0b2f081
fix(board): widen the confirm line counter so it cannot wrap
BitHighlander Aug 17, 2026
ae07558
fix(thorchain): use the real ABI minimum, not the old fixed-memo floor
BitHighlander Aug 17, 2026
b218fe9
ci: scope the gitleaks exemptions by path, not by secret pattern
BitHighlander Aug 17, 2026
db203f2
fix(json): balance the C++ guard in tiny-json.h
BitHighlander Aug 17, 2026
1e30736
fix(eip712): propagate a refusal from every typed-data review screen
BitHighlander Aug 17, 2026
d378df6
fix(coin): render signed message bytes, never a protobuf field as a C…
BitHighlander Aug 17, 2026
5805955
fix(solana): stop presenting a host-supplied token symbol as fact
BitHighlander Aug 17, 2026
bc34c63
docs(release): record the release gates and freeze unrelated changes
BitHighlander Aug 17, 2026
cf7a5be
fix(eip712): validate canonical contract addresses
BitHighlander Aug 17, 2026
30fbf94
fix(security): 7.14.3 security fixes for 9 audit findings (#430-#438)
BitHighlander Aug 17, 2026
6ed40b2
Merge pull request #439 from BitHighlander/agent/eip712-canonical-add…
BitHighlander Aug 17, 2026
d84066e
Merge PR #440: 7.14.3 security fixes for audit findings #430-#438
BitHighlander Aug 17, 2026
40c173a
docs(release): record that default-configuration Ethereum is now gated
BitHighlander Aug 17, 2026
424294c
fix(signing): exact-byte disclosure for every host-supplied signed pa…
BitHighlander Aug 17, 2026
dfad247
Merge release/7.14.2 into the signing-hardening work
BitHighlander Aug 17, 2026
4b52ace
docs(release): correct the breaking-change table after the pager landed
BitHighlander Aug 17, 2026
2135c3b
fix(evm): scope the 0x Exchange Proxy by chain allowlist, not a mainn…
BitHighlander Aug 17, 2026
1ebb1e4
fix: four blocking findings from the audit review
BitHighlander Aug 17, 2026
c89c7d0
ci: pin the builder image by digest and record it in provenance
BitHighlander Aug 17, 2026
7e99461
fix(setup): stage ceremony settings instead of writing them early (#429)
BitHighlander Aug 17, 2026
d1e31e0
chore(deps): pin python-keepkey to the on-screen disclosure tests
BitHighlander Aug 17, 2026
45bf78a
chore(deps): repin python-keepkey to include the screenshot registration
BitHighlander Aug 17, 2026
4406197
docs(release): reconcile every Closes trailer against the code
BitHighlander Aug 17, 2026
ee15ede
fix(rng): fail closed on build-source selection
BitHighlander Aug 17, 2026
885b485
fix(evm): reject a transaction that carries no chain_id
BitHighlander Aug 17, 2026
7e07b2d
fix(confirm): measure the body with the renderer, not a model of it
BitHighlander Aug 17, 2026
249f2d6
Merge pull request #443 from BitHighlander/fix/rng-build-guards
BitHighlander Aug 17, 2026
a34d053
docs(release): record measured gate status, not asserted status
BitHighlander Aug 17, 2026
d3be389
fix(evm): bind transformERC20 clear-signing to full calldata
BitHighlander Aug 17, 2026
7aae356
docs(release): record the 0x transformERC20 change as BREAKING
BitHighlander Aug 17, 2026
2d26377
Merge pull request #468 from BitHighlander/fix/transformerc20-tail-bi…
BitHighlander Aug 17, 2026
dea1cd7
fix(evm): clear-sign 0x only when both traded assets resolve
BitHighlander Aug 17, 2026
a866081
docs(release): the in-buffer residual is #473, not #414
BitHighlander Aug 17, 2026
d1475c8
Merge pull request #472 from BitHighlander/fix/0x-clear-sign-requires…
BitHighlander Aug 17, 2026
52a78b5
ci(secret-scan): allowlist pre-submodule test history, and pin gitleaks
BitHighlander Aug 17, 2026
4e8d746
ci: add an aggregate gate that fails on skipped or cancelled required…
BitHighlander Aug 17, 2026
fc19dda
Merge pull request #474 from BitHighlander/fix/secret-scan-historical…
BitHighlander Aug 17, 2026
b286dc0
fix(confirm): stop review() reporting success when the host took the …
BitHighlander Aug 17, 2026
bc8f1a8
ci(integration): bound every test, so a deadlock fails by name instea…
BitHighlander Aug 17, 2026
e017387
Merge pull request #475 from BitHighlander/fix/review-propagates-host…
BitHighlander Aug 17, 2026
1a6d889
Merge pull request #477 from BitHighlander/fix/integration-per-test-t…
BitHighlander Aug 17, 2026
36ccbfd
docs(release): make "disclosure never yields to a stale test" an inva…
BitHighlander Aug 17, 2026
862e261
Merge pull request #478 from BitHighlander/docs/release-invariant-dis…
BitHighlander Aug 17, 2026
d1204ed
docs(rc30): hardware verification plan for 862e2610f
BitHighlander Aug 17, 2026
b5defee
fix(board): do not consume a glyph the renderer refused to draw
BitHighlander Aug 18, 2026
e68bb15
Merge pull request #481 from BitHighlander/fix/draw-string-clipped-fi…
BitHighlander Aug 18, 2026
038a0c8
chore(deps): repin python-keepkey to the consolidated release PR
BitHighlander Aug 18, 2026
a9a0f22
fix(confirm): announce the Cut Off screen's hold on the wire
BitHighlander Aug 18, 2026
c750f74
chore(deps): repin python-keepkey to 6c4ad17
BitHighlander Aug 18, 2026
9804471
Merge pull request #482 from BitHighlander/fix/cutoff-announces-its-o…
BitHighlander Aug 18, 2026
23af308
Merge pull request #483 from BitHighlander/fix/repin-pyk-dress-rehearsal
BitHighlander Aug 18, 2026
df64c81
ci: fail when a test declares screens it never captures
BitHighlander Aug 20, 2026
75dccea
ci: stop guessing FW_VERSION, and stop guessing it wrong
BitHighlander Aug 20, 2026
b294e19
feat(confirm): page long bodies instead of promising to and not
BitHighlander Aug 20, 2026
30d6cdc
Merge pull request #487 from BitHighlander/fix/screenshot-audit-gate
BitHighlander Aug 20, 2026
818d8c8
Merge pull request #488 from BitHighlander/feat/485-page-long-bodies
BitHighlander Aug 20, 2026
c3cc832
docs(release): gate status after the rc30 hardware round
BitHighlander Aug 20, 2026
fc2c15a
fix(passphrase): keep the plaintext off the stack, and zero it
BitHighlander Aug 20, 2026
b2a39ec
Merge pull request #490 from BitHighlander/fix/release-doc-rc31
BitHighlander Aug 20, 2026
75f742b
Merge pull request #491 from BitHighlander/fix/476-passphrase-residue
BitHighlander Aug 20, 2026
f80eacb
fix(display): a nonzero transfer never renders as zero, and a NUL nev…
BitHighlander Aug 20, 2026
93709df
fix(thorchain): reject a NUL that hides a suffix, not one that ends t…
BitHighlander Aug 20, 2026
91660e3
Merge pull request #492 from BitHighlander/fix/audit-p1-p2
BitHighlander Aug 20, 2026
d676315
Merge pull request #418 from BitHighlander/release/7.14.2
BitHighlander Aug 20, 2026
ebb4217
fix(memo): refuse a length that misdescribes its own content, in both…
BitHighlander Aug 20, 2026
cdde688
Merge pull request #493 from BitHighlander/fix/nul-strict
BitHighlander Aug 20, 2026
bd3a1d6
Merge pull request #494 from BitHighlander/release/7.14.2
BitHighlander Aug 20, 2026
e8ade91
Merge 7.14.3 into develop
BitHighlander Aug 23, 2026
47c4781
feat(core): taproot, transport and board work for 7.14.2 through 7.15
BitHighlander Aug 23, 2026
e2ffeca
feat(chains): EVM disclosure, hive, TRON/TON messages, Tendermint policy
BitHighlander Aug 23, 2026
7c22083
feat(zcash): Orchard shielded signing, with the RNG gate it needs
BitHighlander Aug 23, 2026
0715928
feat(clearsign): describe what the device can verify, and attest schemas
BitHighlander Aug 23, 2026
d106436
feat(rng): auditable entropy source, on-device dice, seed-time gate
BitHighlander Aug 23, 2026
910e383
feat(storage): the version gate, the bitcoin-only band, and KDF harde…
BitHighlander Aug 23, 2026
a4e9d60
build: bitcoin-only variant, release infrastructure and CI gates
BitHighlander Aug 23, 2026
6f3becc
docs: release documentation for 7.14.2, 7.14.3 and 7.15
BitHighlander Aug 23, 2026
2593d25
build(deps): pin device-protocol and python-keepkey
BitHighlander Aug 23, 2026
b005778
docs(release): trim to what's current for the 7.15 merge
BitHighlander Aug 23, 2026
3f74217
Merge pull request #463 from BitHighlander/docs/trim-release-7.15
BitHighlander Aug 23, 2026
3c0a907
docs(release): drop remaining process/handoff docs
BitHighlander Aug 23, 2026
0588c8d
fix(zcash): derive the RedPallas nonce per the RedDSA spec
BitHighlander Aug 23, 2026
e23bcbd
fix(security): remediate the 7.15 audit findings
BitHighlander Aug 23, 2026
8661918
fix(signing): bound multisig signatures and stop writing past the field
BitHighlander Aug 23, 2026
a3da828
fix(signing): close audited disclosure and ZIP-229 gaps
BitHighlander Aug 23, 2026
9e4054d
fix(security): seed-backup clipping, session teardown, storage lock, …
BitHighlander Aug 23, 2026
effdcd9
revert(layout): do not page constant-power screens; keep the measurement
BitHighlander Aug 23, 2026
b7bada9
rehearsal: stage upstream 7.15 onto fork develop
BitHighlander Aug 26, 2026
41ec6ee
fix(release): close RNG and Bitcoin signing blockers
BitHighlander Aug 26, 2026
d866fa3
Merge pull request #604 from BitHighlander/release/7.14.3-bitcoin-only
BitHighlander Aug 26, 2026
400ef2c
Merge remote-tracking branch 'origin/develop' into rehearsal/7.15-to-…
BitHighlander Aug 26, 2026
021a53b
fix: close PR 604 security audit findings
BitHighlander Aug 26, 2026
3ee3535
fix(authenticator): preserve cleanup on validated inputs
BitHighlander Aug 26, 2026
c1b42f2
ci: preserve variant gates after 7.15 restack
BitHighlander Aug 26, 2026
23c10d5
fix(authenticator): use 7.15 cancellation result
BitHighlander Aug 26, 2026
b484078
fix(recovery): complete 7.15 security state port
BitHighlander Aug 26, 2026
4c7f7d6
test(rng): restore emulator fault-injection seam
BitHighlander Aug 26, 2026
bf88b95
test(rng): isolate boot-lifetime latch cases
BitHighlander Aug 26, 2026
1ace61e
fix(build): keep RNG test seam emulator-only
BitHighlander Aug 26, 2026
b5b3c9c
test(bitcoin-only): gate full-feature companion cases
BitHighlander Aug 26, 2026
c054665
test(report): validate the selected product variant
BitHighlander Aug 26, 2026
bcadb71
merge: carry current 7.14.3 into 7.15 review line
BitHighlander Aug 27, 2026
d206d25
fix(merge): reconcile 7.14.3 security contracts in 7.15
BitHighlander Aug 27, 2026
f5ede12
style: apply release formatting
BitHighlander Aug 27, 2026
9836fc0
fix(ethereum): restore native chain ticker labels
BitHighlander Aug 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
635 changes: 445 additions & 190 deletions .github/workflows/ci.yml

Large diffs are not rendered by default.

464 changes: 257 additions & 207 deletions .github/workflows/release.yml

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ build
.DS_Store
.vscode/

build-btconly-check/
135 changes: 124 additions & 11 deletions .gitleaks.toml
Original file line number Diff line number Diff line change
@@ -1,22 +1,135 @@
title = "KeepKey firmware gitleaks configuration"
title = "KeepKey firmware Gitleaks configuration"

[extend]
useDefault = true

# Published U2F attestation material and historical vendored test vectors.
[[allowlists]]
description = "Public device material and third-party historical fixtures"
description = "Published AES test vectors in current and historical trezor-crypto layouts"
targetRules = ["generic-api-key"]
condition = "AND"
regexTarget = "line"
paths = [
'''include/keepkey/firmware/u2f/trezordevkey\.pem''',
'''include/keepkey/firmware/u2f/u2f_keys\.h''',
'''^deps/''',
'''^tests/''',
'''^deps/crypto/trezor-firmware/crypto/aes/aestst\.c$''',
'''^deps/crypto/trezor-crypto/aes/aestst\.c$''',
]
regexes = ['''(?i)^[[:space:]]*//[[:space:]]*key[[:space:]]*=[[:space:]]*[0-9a-f]+[[:space:]]*$''']

[[allowlists]]
description = "Ed25519 C type names in current and historical trezor-crypto layouts"
targetRules = ["generic-api-key"]
condition = "AND"
regexTarget = "line"
paths = [
'''^deps/crypto/trezor-firmware/crypto/ed25519-donna/ed25519-(blake2b|keccak|sha3)\.h$''',
'''^deps/crypto/trezor-firmware/crypto/ed25519-donna/ed25519\.[ch]$''',
'''^deps/crypto/trezor-crypto/ed25519-donna/ed25519-(blake2b|keccak|sha3)\.h$''',
'''^deps/crypto/trezor-crypto/ed25519-donna/ed25519\.[ch]$''',
]
regexes = ['''ed25519.*secret_key.*signature''']

[[allowlists]]
description = "Documented python-keepkey commit pins"
description = "RC21 release provenance names an exact public python-keepkey git commit"
targetRules = ["generic-api-key"]
condition = "AND"
paths = ['''^docs/''']
regexes = ['''python-keepkey[^\n]{0,16}`[0-9a-f]{40}`''']
regexTarget = "match"
regexTarget = "line"
paths = ['''^docs/security/7\.15\.0-rc21-clearsign-release-control\.md$''']
regexes = ['''^[[:space:]]*-[[:space:]]*python-keepkey:[[:space:]]*`c406a1ba9120da410c356dbff7f4d4bd1e1758fa`\.[[:space:]]*$''']

# Converted from the deprecated singular [allowlist] to a fourth [[allowlists]]
# entry. gitleaks refuses to load a config containing both forms ("[allowlist] is
# deprecated, it cannot be used alongside [[allowlists]]"), which is what the
# alpha<-develop merge produced: alpha carried three [[allowlists]] and develop
# carried this one [allowlist]. The merge kept both and the scan died at config
# load, taking the whole build graph with it. Content is unchanged.
[[allowlists]]
description = """
Two U2F attestation artifacts are public by design and must not fail the scan.

1. include/keepkey/firmware/u2f/u2f_keys.h — U2F_ATT_PRIV_KEY[]

This is the FIDO U2F batch attestation key. The standard deliberately shares one
attestation key across a whole batch of devices, so that an attestation
certificate identifies a model rather than an individual unit. The key therefore
has to be present in every device: it is compiled into every firmware image and
is extractable from any public release binary. It authenticates nothing, protects
no user funds or data, and is not a wallet key or a code-signing key.

The certificate it accompanies is self-signed as CN=KeepKey U2F and expires
2028-10-01.

2. include/keepkey/firmware/u2f/trezordevkey.pem

An orphaned key file that corresponds to nothing the firmware ships. Its private
scalar does not match U2F_ATT_PRIV_KEY[], and its public key does not match the
public key in the compiled attestation certificate — verified by decoding both.
It is neither the attestation key nor the key that signed the attestation cert.

It is allowlisted rather than merely deleted because CI scans with fetch-depth 0,
so gitleaks reads full history and this file has been present since commit
fe3e5e001 (2019-04-27). Deleting it from the working tree would not clear the
historical finding, and rewriting published history to remove a key that secures
nothing is not a trade worth making.

Removing the dead file and correcting genkeys.sh — which regenerates the
certificate as CN="Trezor U2F" and would also swap in this non-shipping key — is
tracked separately.

3. deps/ — third-party and submodule content

CI checks out without submodules, but it scans with fetch-depth 0, and crypto
dependencies were vendored directly into this repository before they became
submodules. Every finding under deps/ is the generic-api-key rule firing on
high-entropy constants and test vectors in that vendored crypto — for example
the ed25519-donna headers and the AES self-test tables. None is a credential,
and none of it is KeepKey-authored code.

4. docs/ — prose and recorded submodule pins

The security documentation records exact submodule pins, and gitleaks scores a
40-character git commit SHA at entropy ~3.8 and reports it as a generic API key
(for example the python-keepkey pin in
docs/security/7.15.0-rc21-clearsign-release-control.md).

This is scoped by PATH rather than by a regex on the secret. An earlier version
of this file allowlisted the pattern \\b[0-9a-f]{40}\\b globally, which was
rightly flagged in review: that suppressed every 40-character lowercase hex
finding anywhere in the tree, including in source, not merely documented commit
hashes. Path scoping keeps the exemption where the false positives actually are.

Anything under docs/ is prose intended for publication. A credential must never
be committed there in the first place, and this exemption is not a licence to do
so — it is an acknowledgement that git SHAs in prose are not secrets.

5. tests/ — historical, pre-submodule test vectors

This path does not exist in the working tree. The python test suite lived at the
repository root before it became the deps/python-keepkey submodule, and CI scans
with fetch-depth 0, so gitleaks still reads those commits.

Every finding here is the generic-api-key rule firing on published BIP32 test
vectors — the flagged lines are WIF private keys printed next to their own address
and public key as documentation, e.g. tests/test_ecies.py (2014, inherited from
Trezor) and tests/test_msg_eos_signtx.py (2018). They are upstream test fixtures,
published for a decade, and secure nothing.

Scoped by path for the same reason as deps/: the secrets are real key material by
format, so a regex exemption would be dangerous, whereas the path is provably dead.

The cost of a path exemption, stated plainly: a genuine secret committed under
tests/ would NOT be caught. That is acceptable only while the directory does not
exist. If a tests/ tree is ever reintroduced at the repository root, remove this
exemption in the same commit — verified by negative control, a real EC private key
planted under tests/ is ignored, while the same key under lib/firmware/ is still
detected.

Scope note: every exemption is scoped by path and the default ruleset is otherwise
intact, so a genuine secret committed in source still fails the scan. Verified by
negative control: a planted EC private key under lib/firmware/ is still detected.
"""
paths = [
'''include/keepkey/firmware/u2f/trezordevkey\.pem''',
'''include/keepkey/firmware/u2f/u2f_keys\.h''',
'''^deps/''',
'''^docs/''',
'''^tests/''',
]
8 changes: 4 additions & 4 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
[submodule "deps/device-protocol"]
path = deps/device-protocol
url = https://github.com/keepkey/device-protocol.git
branch = master
url = https://github.com/keepkey/device-protocol.git
branch = up/release-protocol
[submodule "deps/trezor-firmware"]
path = deps/crypto/trezor-firmware
url = https://github.com/keepkey/trezor-firmware.git
url = https://github.com/BitHighlander/trezor-firmware.git
[submodule "googletest"]
path = deps/googletest
url = https://github.com/google/googletest.git
Expand All @@ -14,7 +14,7 @@ url = https://github.com/keepkey/code-signing-keys.git
[submodule "deps/python-keepkey"]
path = deps/python-keepkey
url = https://github.com/keepkey/python-keepkey.git
branch = master
branch = reconcile/upstream-sync
[submodule "deps/qrenc/QR-Code-generator"]
path = deps/qrenc/QR-Code-generator
url = https://github.com/keepkey/QR-Code-generator.git
Expand Down
67 changes: 61 additions & 6 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ endif()

project(
KeepKeyFirmware
VERSION 7.14.3
VERSION 7.15.0
LANGUAGES C CXX ASM)

set(BOOTLOADER_MAJOR_VERSION 2)
Expand All @@ -22,6 +22,16 @@ option(KK_DEBUG_LINK "Build with debug-link enabled" OFF)
option(KK_BUILD_FUZZERS "Build the fuzzers?" OFF)
option(KK_BITCOIN_ONLY "Build Bitcoin-only firmware (strip all non-BTC coins)"
OFF)
# Zcash shielded/Orchard support is part of the regular firmware. It is an
# internal compile selection, not a third release variant: bitcoin-only strips
# the Zcash coin and privacy engine; every regular device/emulator build ships
# both. The open constant-time Pallas audit finding remains a release gate for
# RC18, but it must not silently change the product being audited.
if(KK_BITCOIN_ONLY)
set(KK_ZCASH_PRIVACY OFF)
else()
set(KK_ZCASH_PRIVACY ON)
endif()

# When building the dylib, every static lib it links (kkfirmware, kkboard,
# trezorcrypto, kkrand, kktransport, qrcodegenerator, SecAESSTM32, ...) must
Expand Down Expand Up @@ -64,7 +74,7 @@ endif()
if(NOT EXISTS ${CMAKE_SOURCE_DIR}/deps/crypto/trezor-firmware/crypto/Makefile)
message(
FATAL_ERROR
" trezor-crypto missing. Need to 'git submodule update --init --recursive"
"trezor-crypto fork missing. Run 'git submodule update --init deps/crypto/trezor-firmware'"
)
endif()

Expand All @@ -86,6 +96,13 @@ endif()
if(${KK_EMULATOR})
add_definitions(-DEMULATOR)
add_definitions(-DCONFIDENTIAL=)
# macOS/BSD declare strlcpy/strlcat in <string.h>; glibc (Linux) and MinGW
# (Windows) do not. Force-include the prototypes so the ~20 call sites build
# without -Werror=implicit-function-declaration (definitions come from
# lib/board/strlcpy.c + strlcat.c). Apple already has them in <string.h>.
if(NOT APPLE)
add_compile_options(-include ${CMAKE_SOURCE_DIR}/include/keepkey/board/bsd_compat.h)
endif()
else()
add_definitions(-DCONFIDENTIAL=__attribute__\(\(section\("confidential"\)\)\))
endif()
Expand Down Expand Up @@ -115,6 +132,13 @@ add_definitions(-DUSE_CARDANO=0)
add_definitions(-DUSE_MONERO=0)
add_definitions(-DUSE_NEM=0)

# NOT a USE_* style on/off toggle despite sitting next to them: trezor-crypto's
# rand.c tests this macro with #ifndef, so only its *definedness* matters. The
# old -D...=0 spelling read as "off" while actually meaning "on", and the
# insecure LCG random32() stayed out of the build purely by that double
# negation. Define it bare, matching upstream trezor-core's SConscript.firmware,
# so a future cleanup of an apparent "=0 means unused" define cannot silently
# compile in the LCG. lib/rand/rng.c #errors if this ever goes missing.
# trezor-crypto's rand.c tests only whether this macro is defined. A value of
# zero therefore did not disable anything; it excluded the library's insecure
# test LCG by definedness. Use the upstream spelling so that intent is clear,
Expand All @@ -137,22 +161,37 @@ add_definitions(-DBIP39_WORDLIST_PADDED=1)

add_definitions(-DAES_128=1)

# NOTE: AES table size is selected per release product below. The regular
# image includes Zcash and its Pallas curve arithmetic, so it uses the smaller
# AES tables to preserve flash headroom. Bitcoin-only keeps FOUR_TABLES AES.

if(${KK_DEBUG_LINK})
add_definitions(-DDEBUG_LINK=1)
else()
add_definitions(-DDEBUG_LINK=0)
endif()

# Always defined, 0 or 1, and always tested with `#if BITCOIN_ONLY`. Device
# builds compile with -Wundef -Werror, so an undefined identifier inside `#if`
# is a hard error rather than a silent zero -- which is what we want, because
# a silently-zero guard would ship the coin engines into the stripped image.
# Value macros: always defined, 0 or 1, and always tested with `#if FLAG`.
# Device builds compile with -Wundef -Werror, so an undefined identifier inside
# `#if` is a hard error rather than a silent zero -- which is what we want,
# because a silently-zero guard would ship the coin engines into the stripped
# image.
if(${KK_BITCOIN_ONLY})
add_definitions(-DBITCOIN_ONLY=1)
else()
add_definitions(-DBITCOIN_ONLY=0)
endif()

if(${KK_ZCASH_PRIVACY})
add_definitions(-DZCASH_PRIVACY=1)
# The Orchard engine leaves the regular image tightest on flash; shrink the
# Gladman AES lookup tables from 4KB to 1KB each (-15,360 bytes ROM,
# slightly slower AES). Bitcoin-only keeps the fast FOUR_TABLES.
add_definitions(-DAES_SMALL_TABLES)
else()
add_definitions(-DZCASH_PRIVACY=0)
endif()

if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
add_definitions(-DDEBUG_ON)
add_definitions(-DMEMORY_PROTECT=0)
Expand Down Expand Up @@ -185,6 +224,12 @@ if(NOT ${KK_EMULATOR})
link_directories(${LIBOPENCM3_PATH}/lib)
include_directories(${LIBOPENCM3_PATH}/include)

# Emit per-function stack-frame sizes (.su files) on device builds. CI's
# SRAM budget gate (tools/check_sram_budget.py) reports the largest frames
# and fails when the linker-asserted stack reserve minus the largest frame
# leaves less than the configured margin. See tools/firmware/keepkey.ld.
add_compile_options(-fstack-usage)

# Dummy empty libraries for stack smashing protection support, since we
# implement __stack_chk_guard and __stack_chk_fail ourselves.
file(WRITE ${CMAKE_BINARY_DIR}/ssp.c "")
Expand Down Expand Up @@ -213,6 +258,10 @@ if(${KK_EMULATOR})
add_test(test-firmware ${CMAKE_BINARY_DIR}/bin/firmware-unit)
add_test(test-board ${CMAKE_BINARY_DIR}/bin/board-unit)
add_test(test-crypto ${CMAKE_BINARY_DIR}/bin/crypto-unit)
if(${KK_ZCASH_PRIVACY})
add_test(test-pallas-ct ${CMAKE_BINARY_DIR}/bin/pallas-ct-unit)
add_test(test-zcash-crypto ${CMAKE_BINARY_DIR}/bin/zcash-crypto-unit)
endif()

add_custom_target(
xunit
Expand All @@ -223,4 +272,10 @@ if(${KK_EMULATOR})
COMMAND ${CMAKE_BINARY_DIR}/bin/crypto-unit
--gtest_output=xml:${CMAKE_BINARY_DIR}/unittests/crypto.xml)

if(${KK_ZCASH_PRIVACY})
add_custom_command(TARGET xunit POST_BUILD
COMMAND ${CMAKE_BINARY_DIR}/bin/pallas-ct-unit
--gtest_output=xml:${CMAKE_BINARY_DIR}/unittests/pallas-ct.xml)
endif()

endif()
42 changes: 42 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Convenience targets — mirrors CI jobs so failures are caught locally.
#
# CI pins clang-format-20. Use that version if available, otherwise fall back.
# To install: brew install llvm@20 or apt-get install clang-format-20
CLANG_FORMAT ?= $(shell command -v clang-format-20 2>/dev/null || echo clang-format)

# Directories and exclusions must match .github/workflows/ci.yml lint-format job.
LINT_DIRS := include/keepkey lib/firmware lib/board lib/transport/src
LINT_SOURCES := $(shell find $(LINT_DIRS) -name '*.c' -o -name '*.h' 2>/dev/null \
| grep -v generated | grep -v '\.pb\.')

.PHONY: lint format help

## lint: Check formatting (same rules as CI). Exits non-zero on any violation.
lint:
@echo "clang-format version: $$($(CLANG_FORMAT) --version)"
@FAILED=0; \
for f in $(LINT_SOURCES); do \
if ! $(CLANG_FORMAT) --style=file --dry-run --Werror "$$f" 2>/dev/null; then \
echo " NEEDS FORMAT: $$f"; \
FAILED=1; \
fi; \
done; \
if [ "$$FAILED" = "1" ]; then \
echo ""; \
echo "Run 'make format' to fix all files."; \
exit 1; \
else \
echo "All files pass clang-format check."; \
fi

## format: Auto-fix formatting in-place for all source files.
format:
@echo "Formatting $(LINT_DIRS)..."
@for f in $(LINT_SOURCES); do \
$(CLANG_FORMAT) --style=file -i "$$f"; \
done
@echo "Done. Review changes with: git diff"

## help: List available targets.
help:
@grep -E '^## ' $(MAKEFILE_LIST) | sed 's/^## / make /'
9 changes: 8 additions & 1 deletion cmake/caches/device.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,14 @@ set(WARN_FLAGS
-Werror")


set(KK_C_FLAGS "${ARCH_FLAGS} -std=gnu99 ${WARN_FLAGS}" CACHE STRING "")
# Newlib's snprintf unconditionally links the float engine (_svfprintf_r,
# _dtoa_r, soft-double libgcc, malloc) — ~22 KB of ROM with zero %f users in
# the firmware. Route all callers to the integer-only siprintf family instead.
# %lld/%llu still work (this toolchain's libc.a compiles the integer engine
# with long-long support). Device builds only; host/emulator keep libc printf.
set(PRINTF_FLAGS "-Dsnprintf=sniprintf -Dvsnprintf=vsniprintf")

set(KK_C_FLAGS "${ARCH_FLAGS} -std=gnu99 ${WARN_FLAGS} ${PRINTF_FLAGS}" CACHE STRING "")
set(KK_CXX_FLAGS "${ARCH_FLAGS} -std=gnu++11 ${WARN_FLAGS} \
-fno-exceptions \
-fno-rtti \
Expand Down
Loading
Loading