-
Notifications
You must be signed in to change notification settings - Fork 266
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Point out position of invalid characters in Bech32 addresses #537
Conversation
Approach NACK, I am a bit concerned about showing this to the user without them asking for it, as the error locations may not be correct. This may cause users that don't understand the error correction to try and brute-force the incorrect characters (which they can do easily with this approach), leading to loss of funds. Please add #536 as an alternative to the PR post. |
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ReviewsSee the guideline for information on the review process.
If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update. ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. |
The user asking for it doesn't make it any more likely to be correct or "safe". This has also been in Knots for nearly 2 years (since 0.19.1) with no reported issues. |
Concept ACK, but consider some sort of warning / restriction when there are more than 5(?) typos: #536 (comment) Instead of using a merge commit 7e96673, you could also rebase the |
Concept ACK, gave it a try and I prefer this over #536. I will review it shortly. @meshcollider maybe we could throttle validation to make "brute force" tedious? - if that's really a concern. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did some light testing and it works nicely.
Some things we could improve later (also affects the RPC): if you replace any character after the first 1
with a 1
it will just mark the whole thing as invalid (a mistake I've made with l
plenty of times). If you type a character not in the bech32(m) character set it marks the whole thing as invalid.
We could probably give some useful hints if the address starts with bc1q
and has the wrong length. For bc1p
we can warn if it's too short (but not if it's too long, because that might be valid in the future).
Update: see discussion in #536 (comment)
@luke-jr - you could calculate the "percentage" that the address is incorrect (2 chars ~ 6%, 3 chars ~ 10%, etc..) without specifying which chars are incorrect - You could create a tool tip pop up with the |
814182c
to
abae86d
Compare
Rebased |
abae86d
to
539beea
Compare
tACK All tests pass At first I thought this PR wasn't working, but then I realized you have to click outside the 'Pay To' box, in order for the red highlighting to appear, and the specific 'Yellow' highlighting showing where the error is. Up to two errors are shown, if there are more, there is just the red highlighting. I would suggest not requiring clicking outside the box. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concept ACK
- I agree with the idea of pointing out the positions of invalid characters.
- This would help the user know where they made a mistake while writing the address and save them some time finding the exact position of the invalid character.
- I prefer this implementation over Add address error location to GUI #536. Though I can understand @meshcollider's concern, I think hiding the feature behind a context menu won't prevent this from happening but will make using this feature slightly inconvenient.
- I verified that the PR works correctly on
Ubuntu 22.04
withQt version 5.15.3
. - By trial and error, I verified that the pointing out works when two characters are incorrect at max. Though sometimes the feature doesn't work even when only one character is wrong. I am not sure if this quirk could be avoided.
- One thing I want to point out is that this PR introduces a warning while compiling the gui.
Warning message:
In file included from qt/moc_bitcoinaddressvalidator.cpp:10:
./qt/bitcoinaddressvalidator.h:23:19: warning: ‘virtual QValidator::State BitcoinAddressEntryValidator::validate(QString&, int&) const’ was hidden [-Woverloaded-virtual]
23 | virtual State validate(QString &input, int &pos) const override;
| ^~~~~~~~
./qt/bitcoinaddressvalidator.h:35:11: note: by ‘virtual QValidator::State BitcoinAddressCheckValidator::validate(QString&, std::vector<int>&) const’
35 | State validate(QString &input, std::vector<int>&error_locations) const override;
| ^~~~~~~~
CXX qt/libbitcoinqt_a-moc_bitcoinamountfield.o
Suggestion:
- There are a few suggestions I would like to suggest. These are as per my understanding of the PR. But in case my observations are incorrect, please correct me,
- By my understanding, the use case of the
checkValidity()
function is not to check validity but to set it based on different circumstances. So I would suggest renaming this function tosetValidity()
. - As far as I understood the use case of
setValid()
, this function should be made a protected member of the class, as a function outside the class shouldn't be able to call it.
- By my understanding, the use case of the
I am attaching my notes along with this comment in case this might help other reviewers better understand the PR. In case my observations are erroneous, please do correct me.
Notes:
- The first commit allows checking for warnings and validating input.
- This is done by adding a function to check for the presence of warnings using
QValidator::validate
and using its results to select the appropriate StyleSheet in thesetValid()
function.
- This is done by adding a function to check for the presence of warnings using
- The second commit adds a validate function that allows finding and storing positions of all the invalid characters.
- This commits also make the class
BitcoinAddressCheckValidator
a child class ofBitcoinAddressEntryValidator
. This was done because they had the same parent class. This change eliminated redundancy in redefining the variant of thevalidate
function.
- This commits also make the class
- The third commit adds the code to find and colorize the invalid characters. This is done by:
- First, find the location of all the invalid characters in the checkValidity function and store them in an
error_locations
vector. - Second, use the values in the
error_locations
to find and appropriately style the incorrect characters in thesetValid()
function.
- First, find the location of all the invalid characters in the checkValidity function and store them in an
I agree with @meshcollider, I don't think we should show the user the incorrect characters in the main UI, especially without any warnings about the probability that the error location is correct. |
@achow101 What is the probability that the error location is correct? I agree with the idea of a warning |
@Rspigler If there are up to 2 substitution errors, it is 100% accurate. If there are more or other errors, it is certainly going to be wrong (if it locates at all). You cannot compute probabilities without having a model of what errors users are going to make. If the user just types uniformly random garbage (a very poor approximation for reality), then:
|
Then I don't see the issue with pointing out the position of two errors, and just highlighting the address if there are any more/different errors (such as done in #533) |
@Rspigler I don't see what these statistics have to do with that. If a user types an incorrect address, and it is more than 2 substitution errors, or a different kind of error (insertions/erasure e.g.), then if error locations are shown, they are certainly incorrect. I agree with the earlier comments that without precautions there is a risk the user will just go grind these positions, which would almost certainly cause loss of funds.
There is no way of knowing how many errors were actually made. |
Maybe I asked the wrong question. For the set of all possible 2 substitution errors, the algorithm is 100% correct in pointing out invalid characters. How often are there 3 or more substitution errors, that the algorithm thinks is 2 or less? Insertion/erasure errors can be solved by checking the length of the address. Concerns re: grinding can be fixed through the warning message. |
Depends on the model of actual errors, but likely close to 1 in 652 for P2WSH/P2TR addresses. It drops to 1 in 285 for longer ones.
Changing an address' length does not necessarily invalidate it, and you can have combinations of insertion and erasure too.
Possibly, yes. |
IMO it's far more likely users will enter an incorrect but valid address on the first try, than to grind a single character error. |
I prefer this approach over #536. Regarding the issue stated above, why not make it so users can only paste and clear this field and not allow character edits at all? Would avoid users being able to attempt brute forcing in the first place and in general would be good as manually typing an address in is bound to lead to error. I don't see much user benefit highlighting what parts of the address are invalid. Keeping it simple and binary is the better UX. Red if incorrect, without highlighting errors, green if correct (this is also a state that should be shown as it takes anxiety off users inputting invalid addresses). If you do want to highlight what parts are incorrect then this should be hidden from the primary view and be possible to be viewed in a manner similar to #536 in a modal of some sort. We have some content on this in the Bitcoin Design Guide: https://bitcoin.design/guide/glossary/address/#address-validation |
But there should still be a way to enter the address character by character, I think? It may be visually copied from another device, or dictated over voice or so. How do you permit entering, while disallowing editing? |
If you allow manual entry, then it makes sense to allow editing as well. It's much easier to ask someone to confirm the "middle" or "end" than to repeat the whole thing. Or to look closer at a specific character on your other device/paper. |
I was wondering if we could take a middle ground. We could have a toggle button saying something like "allow manual edits". Which, by default, will be off and would allow only copy/paste. When switched, it can display the risk associated with entering the wrong address and ask for user confirmation if they want to toggle it.
I am currently looking into ways to do so using Qt Widgets to ensure the feasibility of the above idea. |
I'm a soft NACK on the toggle, I feel like we have to allow manual edits, that'd be a big UX change. Soft NACK because it could be a good security improvement, that when off, it automatically points out positions of invalid characters. I'm more favorable towards just doing #536 |
What if we highlight 6 adjacent characters with a random offset? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd tend towards NACK here, this is too overwhelming for a user. I don't think we need to do this at all, just warn that the address is invalid.
If they're running into an issue with invalid characters, i don't see how this helps. Are they supposed to replace the wrong characters with the correct ones? That would not be advisable.
They can look at the writing they are transcribing, or perhaps call the recipient up on the phone to clarify the specific part that looks wrong. |
How is this scenario relevant? If a user types in random characters, then they are surely wanting to send funds to nowhere - we shouldn't make that difficult for them if this is their wish. Anyway, concept ACK - seems like a useful feature, and makes it easier for users to quickly see where an address is mistyped, without risking loss of funds (unless that is what the user wants). |
🐙 This pull request conflicts with the target branch and needs rebase. |
There hasn't been much activity lately and the patch still needs rebase. What is the status here?
|
Closing this due to lack of activity. Feel free to reopen. |
Highlighting adjacent characters is the best approach and should not be overlooked. We ran into similar issues over at BlockstreamResearch/codex32#58 and have some solutions that may apply here. • Visual Separation: As @Bosch-0 shared, visually spacing or separating each group of 4 characters in bech32 strings greatly enhances readability. Note that the spacing is for legibility, not part of the string itself. • Error Highlighting: We currently highlight error locations by turning the group(s) of 4 characters that may contain an error red. • Abuse Safe: Group error highlighting can't be abused by manual brute force due to 2^20 candidate corrections. • Simple Corrections: Easy-to-remember chunks. For instance, in a wpkh address with 11 groups, one could attempt a correction by saying ‘repeat group 8’ and be quickly understood by another party. • Allows Highlighting Deletions: How do you highlight something that's not there? Highlight the group where a suspected missing character belongs. • How to Safely Highlight Insertions: Character insertion error locations are dangerous to highlight because the abusive edit to "manually brute force" a valid string is one key stroke (with no detection guarantees). In fact, insertion errors MUST NEVER be identified as such, otherwise there aren't enough candidates to display them safely at all. Error type ambiguity protects the user. • Error Detection Warning: When a string with an invalid checksum is provided we MUST ask the user to check their source matches entirely their input before accepting the repairs. • Known Length Error Detection: For known (nearby) string length, like bech32, up to 3 insert and/or 2 delete errors can be checked to give error location suggestions. • Unknown Length Correction: For bech32m with many valid lengths, at most half the above (1 insert, 1 delete) can be checked in candidates. Attempts to submit an unusual length need a scary warning. Especially after repairing length errors. • Error Detection Warning: When a string with an invalid checksum is provided we MUST ask the user to check their source matches entirely their input before accepting their corrections. the user must always refer to the original source to determine the type of error to attempt a correction for an incorrect group or groups. I tested a Gtk dialog that highlights red groups of 4 containing substitutions, insertions, and deletions. And it is far more user-friendly to type fast from handwriting than no error highlighting or specific character highlighting. Single character highlighting is harder for the eye to locate in the source, groups are not. Especially if written down or printed in the same grouped structure. What looks at a glance like a compromise, ends up better for almost everything. |
fe7c81e qt: change QLineEdit error background (w0xlt) Pull request description: This PR proposes a small change in QLineEdit when there is an error in the input. master | --- | ![image](https://user-images.githubusercontent.com/94266259/154762427-b816267e-ec70-4a8f-a7fb-1317ebacf1a4.png) PR | --- | ![image](https://user-images.githubusercontent.com/94266259/154761933-15eb3d81-ca81-4498-b8ec-cf1139ae2f8a.png) | This also shows good results when combined with other open PRs. #537 | --- | ![image](https://user-images.githubusercontent.com/94266259/154763411-6266a283-2d8a-4365-b3f2-a5cb545e773e.png) #533 | --- | ![image](https://user-images.githubusercontent.com/94266259/154765638-f38b13d6-a4f8-4b46-a470-f882668239f3.png) | ACKs for top commit: GBKS: ACK fe7c81e jarolrod: ACK fe7c81e shaavan: ACK fe7c81e Tree-SHA512: eccc53f42d11291944ccb96efdbe460cb10af857f1d4fa9b5348ddcb0796c82faf1cdad9040aae7a25c5d8f4007d6284eba868d7af14acf56280f6acae170b91
Implements #527