Skip to content

Commit

Permalink
update checksum create/validate code based on Pieter Wuille's recent …
Browse files Browse the repository at this point in the history
…research
  • Loading branch information
danpape committed Jan 7, 2020
1 parent 08ab17f commit 698cd6d
Show file tree
Hide file tree
Showing 10 changed files with 428 additions and 54 deletions.
60 changes: 60 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,63 @@ sudo make install

Now you can again try to build libbech32.

### C++ Usage Example

```cpp
#include "libbech32.h"
#include <iostream>
#include <cassert>

int main() {
// simple human readable part with some data
std::string hrp = "hello";
std::vector<unsigned char> data = {14, 15, 3, 31, 13};

// encode
std::string bstr = bech32::encode(hrp, data);

// prints "hello1w0rldcs7fw6" : "hello" + Bech32.separator + encoded data + 6 char checksum
std::cout << bstr << std::endl;

// decode
bech32::HrpAndDp hd = bech32::decode(bstr);

assert(hrp == hd.hrp);
assert(data == hd.dp);
}
```

### C Usage Example

```C
#include "libbech32.h"
#include <string.h>
#include <stdio.h>
#include <assert.h>

int main() {
// simple human readable part with some data
char hrp[] = "hello";
unsigned char dp[] = {14, 15, 3, 31, 13};

// create output array for bech32 string
char bstr[sizeof(hrp) + 1 + sizeof(dp) + 6] = {0};

// encode
assert(bech32_encode(bstr, sizeof(bstr), hrp, sizeof(hrp), dp, sizeof(dp)) == E_BECH32_SUCCESS);

// prints "hello1w0rldcs7fw6" : "hello" + Bech32.separator + encoded data + 6 char checksum
printf("bech32 encoding of human-readable part \'hello\' and data part \'[14, 15, 3, 31, 13]\' is:\n");
printf("%s\n", bstr);

// allocate memory for decoded data
bech32_HrpAndDp * hrpdp = create_HrpAndDp_storage(bstr);

// decode
assert(bech32_decode(hrpdp, bstr, sizeof(bstr)) == E_BECH32_SUCCESS);
assert(strcmp(hrpdp->hrp, "hello") == 0);

// free memory
free_HrpAndDp_storage(hrpdp);
}
```
20 changes: 20 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,30 @@ set_target_properties(bech32_cpp_example PROPERTIES CXX_EXTENSIONS OFF)

target_link_libraries(bech32_cpp_example bech32)

##

add_executable(bech32_cpp_usage_example cpp_usage_example.cpp)

target_compile_features(bech32_cpp_usage_example PRIVATE cxx_std_11)
target_compile_options(bech32_cpp_usage_example PRIVATE ${DCD_CXX_FLAGS})
set_target_properties(bech32_cpp_usage_example PROPERTIES CXX_EXTENSIONS OFF)

target_link_libraries(bech32_cpp_usage_example bech32)

##

add_executable(bech32_c_example c_example.c)

target_compile_features(bech32_c_example PRIVATE c_std_99)
set_target_properties(bech32_c_example PROPERTIES C_EXTENSIONS OFF)

target_link_libraries(bech32_c_example bech32)

##

add_executable(bech32_c_usage_example c_usage_example.c)

target_compile_features(bech32_c_usage_example PRIVATE c_std_99)
set_target_properties(bech32_c_usage_example PROPERTIES C_EXTENSIONS OFF)

target_link_libraries(bech32_c_usage_example bech32)
67 changes: 65 additions & 2 deletions examples/c_example.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#undef NDEBUG
#include <assert.h>

int main() {
void encodeAndDecode() {

// hrp and data to encode
char hrp[] = "example";
Expand All @@ -16,7 +16,7 @@ int main() {
char bstr[sizeof(hrp) + 1 + sizeof(dp) + 6] = {0};

// expected bech32 string output
char expected[] = "example1qpzry9x8gvmqvdw";
char expected[] = "example1qpzry9x8gnylnjs";

// encode
assert(bech32_encode(bstr, sizeof(bstr), hrp, sizeof(hrp), dp, sizeof(dp)) == E_BECH32_SUCCESS);
Expand All @@ -38,3 +38,66 @@ int main() {
free_HrpAndDp_storage(hrpdp);

}

void decodeAndEncode() {

// bech32 string with extra invalid characters
char bstr[] = " example1:qpz!r--y9#x8&%&%gn-y-lnjs ";
// expected bech32 string output
char expected[] = "example1qpzry9x8gnylnjs";

// strip unwanted chars from bstr
bech32_stripUnknownChars(bstr, sizeof(bstr), bstr, sizeof(bstr));

// allocate memory for decoded data
bech32_HrpAndDp * hrpdp = create_HrpAndDp_storage(bstr);

// decode
assert(bech32_decode(hrpdp, bstr, sizeof(bstr)) == E_BECH32_SUCCESS);
assert(strcmp(hrpdp->hrp, "example") == 0);
assert(hrpdp->dp[0] == 0);
assert(hrpdp->dp[8] == 8);

// free memory
free_HrpAndDp_storage(hrpdp);

}

void badEncoding() {

// hrp and data to encode
char hrp[] = "example";
unsigned char dp[] = {0, 1, 2, 3, 4, 5, 6, 7, 33};

// create output array for bech32 string
char bstr[sizeof(hrp) + 1 + sizeof(dp) + 6] = {0};

// encode
assert(bech32_encode(bstr, sizeof(bstr), hrp, sizeof(hrp), dp, sizeof(dp)) == E_BECH32_UNKNOWN_ERROR);

}

void badDecoding() {

// bech32 string with extra invalid characters
char bstr[] = "example1qpzry9x8gnylnjs";
// simulate corrupted data--checksum verification will fail
bstr[10] = 'x';

// allocate memory for decoded data
bech32_HrpAndDp * hrpdp = create_HrpAndDp_storage(bstr);

// decode
assert(bech32_decode(hrpdp, bstr, sizeof(bstr)) == E_BECH32_INVALID_CHECKSUM);

// free memory
free_HrpAndDp_storage(hrpdp);

}

int main() {
encodeAndDecode();
decodeAndEncode();
badEncoding();
badDecoding();
}
33 changes: 33 additions & 0 deletions examples/c_usage_example.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#include "libbech32.h"
#include <string.h>
#include <stdio.h>

// make sure we can check these examples even when building a release version
#undef NDEBUG
#include <assert.h>

int main() {
// simple human readable part with some data
char hrp[] = "hello";
unsigned char dp[] = {14, 15, 3, 31, 13};

// create output array for bech32 string
char bstr[sizeof(hrp) + 1 + sizeof(dp) + 6] = {0};

// encode
assert(bech32_encode(bstr, sizeof(bstr), hrp, sizeof(hrp), dp, sizeof(dp)) == E_BECH32_SUCCESS);

// prints "hello1w0rldcs7fw6" : "hello" + Bech32.separator + encoded data + 6 char checksum
printf("bech32 encoding of human-readable part \'hello\' and data part \'[14, 15, 3, 31, 13]\' is:\n");
printf("%s\n", bstr);

// allocate memory for decoded data
bech32_HrpAndDp * hrpdp = create_HrpAndDp_storage(bstr);

// decode
assert(bech32_decode(hrpdp, bstr, sizeof(bstr)) == E_BECH32_SUCCESS);
assert(strcmp(hrpdp->hrp, "hello") == 0);

// free memory
free_HrpAndDp_storage(hrpdp);
}
65 changes: 54 additions & 11 deletions examples/cpp_example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,36 +15,79 @@ void encodeAndDecode() {
// encode
std::string bstr = bech32::encode(hrp, data);

// will print "example1qpzry9x8gvmqvdw" ... last 6 characters are the checksum
// will print "example1qpzry9x8gnylnjs" ... last 6 characters are the checksum
std::cout << R"(bech32 encoding of human-readable part 'example' and data part '[0, 1, 2, 3, 4, 5, 6, 7, 8]' is:)" << std::endl;
std::cout << bstr << std::endl;

// decode
bech32::HrpAndDp b = bech32::decode(bstr);
bech32::HrpAndDp hd = bech32::decode(bstr);

assert(hrp == b.hrp);
assert(data == b.dp);
assert(hrp == hd.hrp);
assert(data == hd.dp);
}

void decodeAndEncode() {

// bech32 string with extra invalid characters
std::string bstr = "tx1:yjk!0-uq#ay-z%u4x-nk6u&-pc";
std::string expected = "tx1yjk0uqayzu4xnk6upc";
std::string bstr = " example1:qpz!r--y9#x8&%&%gn-y-lnjs ";
std::string expected = "example1qpzry9x8gnylnjs";
// decode - make sure to strip invalid characters before trying to decode
bech32::HrpAndDp b = bech32::decode(bech32::stripUnknownChars(bstr));
bech32::HrpAndDp hd = bech32::decode(bech32::stripUnknownChars(bstr));

// verify decoding
assert(!hd.hrp.empty() && !hd.dp.empty());

// encode
bstr = bech32::encode(b.hrp, b.dp);
bstr = bech32::encode(hd.hrp, hd.dp);

// encoding of "cleaned" decoded data should match expected string
assert(bstr == expected);

// simulate corrupted data--checksum verification will fail
bstr[10] = 'x';

// decode - make sure to strip invalid characters before trying to decode
hd = bech32::decode(bech32::stripUnknownChars(bstr));

// verify decoding failed
assert(hd.hrp.empty() && hd.dp.empty());

}

int main() {
void badEncoding() {

encodeAndDecode();
// human-readable part
std::string hrp = "example";
// data values can be 0-31
std::vector<unsigned char> data = {0, 1, 2, 3, 4, 5, 6, 7, 33};

decodeAndEncode();
// encode
try {
std::string bstr = bech32::encode(hrp, data);
}
catch (std::exception &e) {
assert(strcmp(e.what(), "data value is out of range") == 0);
}
}

void badDecoding() {

// valid bech32 string
std::string bstr = "example1qpzry9x8gnylnjs";
// simulate corrupted data--checksum verification will fail
bstr[10] = 'x';

// decode
bech32::HrpAndDp hd = bech32::decode(bstr);

// verify decoding failed
assert(hd.hrp.empty() && hd.dp.empty());

}

int main() {
encodeAndDecode();
decodeAndEncode();
badEncoding();
badDecoding();
}
25 changes: 25 additions & 0 deletions examples/cpp_usage_example.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include "libbech32.h"
#include <iostream>

// make sure we can check these examples even when building a release version
#undef NDEBUG
#include <cassert>

int main() {
// simple human readable part with some data
std::string hrp = "hello";
std::vector<unsigned char> data = {14, 15, 3, 31, 13};

// encode
std::string bstr = bech32::encode(hrp, data);

// prints "hello1w0rldcs7fw6" : "hello" + Bech32.separator + encoded data + 6 char checksum
std::cout << R"(bech32 encoding of human-readable part 'hello' and data part '[14, 15, 3, 31, 13]' is:)" << std::endl;
std::cout << bstr << std::endl;

// decode
bech32::HrpAndDp hd = bech32::decode(bstr);

assert(hrp == hd.hrp);
assert(data == hd.dp);
}
1 change: 1 addition & 0 deletions include/libbech32/libbech32.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ typedef enum bech32_error_e
E_BECH32_UNKNOWN_ERROR,
E_BECH32_NULL_ARGUMENT,
E_BECH32_LENGTH_TOO_SHORT,
E_BECH32_INVALID_CHECKSUM,
E_BECH32_MAX_ERROR
} bech32_error;

Expand Down
Loading

0 comments on commit 698cd6d

Please sign in to comment.