Skip to content

Ack/dev - #5

Merged
Acktarius merged 9 commits into
mainfrom
ack/dev
Aug 27, 2026
Merged

Ack/dev#5
Acktarius merged 9 commits into
mainfrom
ack/dev

Conversation

@Acktarius

Copy link
Copy Markdown
Member

No description provided.

Acktarius and others added 9 commits August 18, 2026 13:38
Update the react-native peer dependency requirement from a fixed
tilde range (~0.82.0) to a wider compatible range (>=0.81.0 <0.83.0)
to allow for more flexible versioning within the supported major
versions.
<utility> is already compiled into this Android target via
Cryptonote/Varint.h (included by crypto.cpp), so there is no build
risk in re-adding it here. Moving the already-normalized local string
into the vector avoids an unnecessary copy per word on every decode.

Co-authored-by: Cursor <cursoragent@cursor.com>
The header declares std::string parameters/returns but only compiled
because <string> was pulled in transitively via includes in
Mnemonics.cpp. Include it directly so the header is self-contained.

Co-authored-by: Cursor <cursoragent@cursor.com>
Every other header under cpp/ uses #pragma once. Mnemonics.h lacked
one, leaving it vulnerable to multiple-inclusion/redefinition errors.

Co-authored-by: Cursor <cursoragent@cursor.com>
@Acktarius
Acktarius merged commit d82688a into main Aug 27, 2026
2 checks passed
@roomote-conceal-network

roomote-conceal-network Bot commented Aug 27, 2026

Copy link
Copy Markdown

1 issue outstanding. See task

  • Add regression coverage for mixed-case mnemonic decode (cpp/Mnemonics/Mnemonics.cpp:32-43)

Review of 7be6a81 (PR is already merged, so this is post-merge follow-up input)

Verified clean:

  • Mnemonics casing fix (correct and important): I compiled Mnemonics.cpp standalone against both base and head. On base, a phrase with a miscased word (e.g. unUsual) passed the checksum — which only hashes the first 3 chars of each word — and the val % wlLen == w1 check, silently decoding a wrong private key (a fund-loss-class bug). On head, the same phrase decodes to the correct key, and negative cases (unknown word, swapped checksum words) are still rejected. All downstream consumers (hasValidChecksum, getWordIndexes, the loop) now use the normalized vector consistently, and mn_decode reaches the fix via the string overload.
  • Mnemonics.h: #pragma once + direct #include <string> are correct; matches the convention of every other header under cpp/. clang-format --dry-run --Werror passes on both changed C++ files.
  • Peer dependency changes: react ^19.1.1 → ^19.1.0 and react-native ~0.82.0 → >=0.81.0 <0.83.0 are pure broadenings, consistent between package.json and package-lock.json, and don't conflict with devDependencies.

One low-severity follow-up: the repo has no tests at all, and a fix of this severity should get a regression test (details in the inline comment).

Reviewed 7be6a81

Comment on lines +32 to +43
/* Normalize to lower case up front so word validation, checksum
derivation, and word list index lookups all operate on the same
casing; otherwise a mixed-case phrase can pass validation while
the index lookup misses and decodes a wrong private key */
std::vector<std::string> normalizedWords;
normalizedWords.reserve(words.size());

for (const auto &word : words) {
std::string lowerWord = word;
std::transform(lowerWord.begin(), lowerWord.end(), lowerWord.begin(), ::tolower);
normalizedWords.push_back(std::move(lowerWord));
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Low: no regression coverage for the mixed-case mnemonic fix

I verified this fix empirically: on main before this PR, a phrase with a miscased word in position 2/3 of a word triple (e.g. unUsual) passed the checksum and the val % wlLen == w1 check, silently decoding a wrong private key (bytes 8–10 differed from the lowercase decode — a fund-loss-class bug). With this normalization the same phrase decodes correctly, and invalid words / tampered checksums are still rejected.

Given that severity, the fix deserves a regression test so it can't be reintroduced. The repo currently has no test script at all; even a small standalone C++ roundtrip check (compilable in CI with just g++, no JS test framework needed) would lock this behavior in:

Suggested change
/* Normalize to lower case up front so word validation, checksum
derivation, and word list index lookups all operate on the same
casing; otherwise a mixed-case phrase can pass validation while
the index lookup misses and decodes a wrong private key */
std::vector<std::string> normalizedWords;
normalizedWords.reserve(words.size());
for (const auto &word : words) {
std::string lowerWord = word;
std::transform(lowerWord.begin(), lowerWord.end(), lowerWord.begin(), ::tolower);
normalizedWords.push_back(std::move(lowerWord));
}
/* Regression-tested: a miscased word previously bypassed the checksum
(first 3 chars) and word-index lookups here, silently producing a
wrong private key; normalization must run before every consumer. */
std::vector<std::string> normalizedWords;

Example invariant to test: mnemonicToPrivateKey(privateKeyToMnemonic(k)) equals mnemonicToPrivateKey(mixedCaseVariantOfThatPhrase) equals k, for variants that uppercase any character at any position, plus negative cases (unknown word, swapped words).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants