Skip to content

Commit b4181f8

Browse files
jgriffithsko-matsu
andcommitted
Implement blech32m support
Co-authored-by: k-matsuzawa <[email protected]>
1 parent 8e4abd1 commit b4181f8

File tree

6 files changed

+112
-265
lines changed

6 files changed

+112
-265
lines changed

.gitignore

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,7 @@ src/stamp-h1
4040
src/test/Makefile
4141
src/test/Makefile.in
4242
src/wallycore.pc
43-
src/test_bech32*
44-
src/test_blech32*
45-
src/test_clear*
46-
src/test_tx*
47-
src/test_psbt*
48-
src/test_elements_tx*
43+
src/test_*
4944
src/test-suite.log
5045
src/swig_java/swig_java_wrap.c
5146
src/swig_java/*.java

include/wally_address.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ WALLY_CORE_API int wally_confidential_addr_from_addr(
261261
* Extract the segwit native address from a confidential address.
262262
*
263263
* :param address: The blech32 encoded confidential address to extract the address from.
264-
* :param confidential_addr_family: The confidential address family to generate.
264+
* :param confidential_addr_family: The confidential address family of ``address``.
265265
* :param addr_family: The address family to generate.
266266
* :param output: Destination for the resulting address string.
267267
*| The string returned should be freed using `wally_free_string`.
@@ -276,7 +276,7 @@ WALLY_CORE_API int wally_confidential_addr_to_addr_segwit(
276276
* Extract the blinding public key from a segwit confidential address.
277277
*
278278
* :param address: The blech32 encoded confidential address to extract the public key from.
279-
* :param confidential_addr_family: The confidential address prefix byte.
279+
* :param confidential_addr_family: The confidential address family of ``address``.
280280
* :param bytes_out: Destination for the public key.
281281
* :param len: The length of ``bytes_out`` in bytes. Must be ``EC_PUBLIC_KEY_LEN``.
282282
*/
@@ -287,7 +287,7 @@ WALLY_CORE_API int wally_confidential_addr_segwit_to_ec_public_key(
287287
size_t len);
288288

289289
/**
290-
* Create a confidential address from an segwit native and blinding public key.
290+
* Create a confidential address from a segwit native address and blinding public key.
291291
*
292292
* :param address: The bech32 encoded address to make confidential.
293293
* :param addr_family: The address family to generate.

src/Makefile.am

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -295,14 +295,6 @@ test_elements_tx_LDADD = $(lib_LTLIBRARIES) @CTEST_EXTRA_STATIC@
295295
if PYTHON_MANYLINUX
296296
test_elements_tx_LDADD += $(PYTHON_LIBS)
297297
endif
298-
TESTS += test_blech32
299-
noinst_PROGRAMS += test_blech32
300-
test_blech32_SOURCES = ctest/test_blech32.c
301-
test_blech32_CFLAGS = -I$(top_srcdir)/include $(AM_CFLAGS)
302-
test_blech32_LDADD = $(lib_LTLIBRARIES) @CTEST_EXTRA_STATIC@
303-
if PYTHON_MANYLINUX
304-
test_blech32_LDADD += $(PYTHON_LIBS)
305-
endif
306298
endif
307299

308300
check-local: $(SWIG_PYTHON_TEST_DEPS) $(SWIG_JAVA_TEST_DEPS)

src/blech32.c

Lines changed: 41 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@
2828

2929
#ifdef BUILD_ELEMENTS
3030

31+
#define CHECKSUM_BLECH32 0x1
32+
#define CHECKSUM_BLECH32M 0x455972a3350f7a1ull
33+
3134
static uint64_t blech32_polymod_step(uint64_t pre) {
3235
uint8_t b = pre >> 55;
3336
return ((pre & 0x7fffffffffffffULL) << 5) ^
@@ -53,7 +56,7 @@ static const int8_t blech32_charset_rev[128] = {
5356

5457
#define WALLY_BLECH32_MAXLEN ((size_t) 1000)
5558

56-
static int blech32_encode(char *output, const char *hrp, const uint8_t *data, size_t data_len, size_t max_input_len) {
59+
static int blech32_encode(char *output, const char *hrp, const uint8_t *data, size_t data_len, size_t max_input_len, bool is_blech32m) {
5760
uint64_t chk = 1;
5861
size_t i = 0;
5962
while (hrp[i] != 0) {
@@ -81,15 +84,15 @@ static int blech32_encode(char *output, const char *hrp, const uint8_t *data, si
8184
for (i = 0; i < 12; ++i) {
8285
chk = blech32_polymod_step(chk);
8386
}
84-
chk ^= 1;
87+
chk ^= is_blech32m ? CHECKSUM_BLECH32M : CHECKSUM_BLECH32;
8588
for (i = 0; i < 12; ++i) {
8689
*(output++) = blech32_charset[(chk >> ((11 - i) * 5)) & 0x1f];
8790
}
8891
*output = 0;
8992
return 1;
9093
}
9194

92-
static int blech32_decode(char *hrp, uint8_t *data, size_t *data_len, const char *input, size_t max_input_len) {
95+
static int blech32_decode(char *hrp, uint8_t *data, size_t *data_len, const char *input, size_t max_input_len, bool *is_blech32m) {
9396
uint64_t chk = 1;
9497
size_t i;
9598
size_t input_len = strlen(input);
@@ -143,7 +146,8 @@ static int blech32_decode(char *hrp, uint8_t *data, size_t *data_len, const char
143146
if (have_lower && have_upper) {
144147
return 0;
145148
}
146-
return chk == 1;
149+
*is_blech32m = chk == CHECKSUM_BLECH32M;
150+
return chk == CHECKSUM_BLECH32 || chk == CHECKSUM_BLECH32M;
147151
}
148152

149153
static int blech32_convert_bits(uint8_t *out, size_t *outlen, int outbits, const uint8_t *in, size_t inlen, int inbits, int pad) {
@@ -168,28 +172,31 @@ static int blech32_convert_bits(uint8_t *out, size_t *outlen, int outbits, const
168172
return 1;
169173
}
170174

171-
static int blech32_addr_encode(char *output, const char *hrp, int witver, const uint8_t *witprog, size_t witprog_len) {
175+
static int blech32_addr_encode(char *output, const char *hrp, uint8_t witver, const uint8_t *witprog, size_t witprog_len) {
172176
uint8_t data[WALLY_BLECH32_MAXLEN];
173177
size_t datalen = 0;
174-
if (witver < 0 || witver > 16) goto fail;
178+
if (witver > 16) goto fail;
175179
if (witver == 0 && witprog_len != 53 && witprog_len != 65) goto fail;
176180
if (witprog_len < 2 || witprog_len > 65) goto fail;
177181
data[0] = witver;
178182
blech32_convert_bits(data + 1, &datalen, 5, witprog, witprog_len, 8, 1);
179183
++datalen;
180-
return blech32_encode(output, hrp, data, datalen, WALLY_BLECH32_MAXLEN);
184+
return blech32_encode(output, hrp, data, datalen, WALLY_BLECH32_MAXLEN, witver != 0);
181185
fail:
182186
wally_clear_2(data, sizeof(data), (void *)witprog, witprog_len);
183187
return 0;
184188
}
185189

186-
static int blech32_addr_decode(int *witver, uint8_t *witdata, size_t *witdata_len, const char *hrp, const char *addr) {
190+
static int blech32_addr_decode(uint8_t *witver, uint8_t *witdata, size_t *witdata_len, const char *hrp, const char *addr) {
187191
uint8_t data[WALLY_BLECH32_MAXLEN];
188192
char hrp_actual[WALLY_BLECH32_MAXLEN];
189193
size_t data_len;
190-
if (!blech32_decode(hrp_actual, data, &data_len, addr, WALLY_BLECH32_MAXLEN)) goto fail;
194+
bool is_blech32m = false;
195+
if (!blech32_decode(hrp_actual, data, &data_len, addr, WALLY_BLECH32_MAXLEN, &is_blech32m)) goto fail;
191196
if (data_len == 0 || data_len > (WALLY_BLECH32_MAXLEN - 4)) goto fail;
192197
if (strncmp(hrp, hrp_actual, WALLY_BLECH32_MAXLEN - 5) != 0) goto fail;
198+
if (data[0] == 0 && is_blech32m) goto fail;
199+
if (data[0] != 0 && !is_blech32m) goto fail;
193200
if (data[0] > 16) goto fail;
194201
*witdata_len = 0;
195202
if (!blech32_convert_bits(witdata, witdata_len, 8, data + 1, data_len - 1, 5, 0)) goto fail;
@@ -210,9 +217,9 @@ int wally_confidential_addr_to_addr_segwit(
210217
{
211218
unsigned char buf[WALLY_BLECH32_MAXLEN];
212219
unsigned char *hash_bytes_p = &buf[EC_PUBLIC_KEY_LEN - 2];
213-
int witver = 0;
214220
size_t written = 0;
215221
int ret;
222+
uint8_t witver;
216223

217224
if (output)
218225
*output = NULL;
@@ -222,11 +229,11 @@ int wally_confidential_addr_to_addr_segwit(
222229

223230
if (!blech32_addr_decode(&witver, buf, &written, confidential_addr_family, address))
224231
ret = WALLY_EINVAL;
225-
else if (witver != 0 || (written != 53 && written != 65))
226-
ret = WALLY_EINVAL; /* Only v0 witness programs are currently allowed */
232+
else if (written != 53 && written != 65)
233+
ret = WALLY_EINVAL;
227234
else {
228235
written = written - EC_PUBLIC_KEY_LEN + 2;
229-
hash_bytes_p[0] = (unsigned char) witver;
236+
hash_bytes_p[0] = value_to_op_n(witver);
230237
hash_bytes_p[1] = (unsigned char) (written - 2);
231238
ret = wally_addr_segwit_from_bytes(hash_bytes_p, written,
232239
addr_family, 0, output);
@@ -243,17 +250,16 @@ int wally_confidential_addr_segwit_to_ec_public_key(
243250
size_t len)
244251
{
245252
unsigned char buf[WALLY_BLECH32_MAXLEN];
246-
int witver = 0;
247253
size_t written = 0;
248254
int ret = WALLY_OK;
255+
uint8_t witver;
249256

250257
if (!address || !bytes_out || !confidential_addr_family || len != EC_PUBLIC_KEY_LEN)
251258
return WALLY_EINVAL;
252259

253-
/* Only v0 witness programs are currently allowed */
254260
if (!blech32_addr_decode(&witver, buf, &written, confidential_addr_family, address))
255261
ret = WALLY_EINVAL;
256-
else if (witver != 0 || (written != 53 && written != 65))
262+
else if (written != 53 && written != 65)
257263
ret = WALLY_EINVAL;
258264
else
259265
memcpy(bytes_out, buf, EC_PUBLIC_KEY_LEN);
@@ -275,6 +281,7 @@ int wally_confidential_addr_from_addr_segwit(
275281
unsigned char *hash_bytes_p = &buf[EC_PUBLIC_KEY_LEN - 2];
276282
size_t written = SHA256_LEN + 2;
277283
int ret;
284+
size_t witver;
278285

279286
if (output)
280287
*output = NULL;
@@ -284,25 +291,32 @@ int wally_confidential_addr_from_addr_segwit(
284291
strlen(confidential_addr_family) >= WALLY_BLECH32_MAXLEN)
285292
return WALLY_EINVAL;
286293

287-
/* get v0 witness programs script */
294+
/* get witness program's script */
288295
ret = wally_addr_segwit_to_bytes(address, addr_family, 0,
289296
hash_bytes_p, written, &written);
290297
if (ret == WALLY_OK) {
291-
if ((written != (HASH160_LEN + 2)) && (written != (SHA256_LEN + 2)))
298+
if ((written != (HASH160_LEN + 2)) && (written != (SHA256_LEN + 2))) {
292299
ret = WALLY_EINVAL;
293-
else {
294-
/* Copy the confidentialKey / v0 witness programs */
295-
memcpy(buf, pub_key, pub_key_len);
296-
written -= 2; /* ignore witnessVersion & hashSize */
297-
written += EC_PUBLIC_KEY_LEN;
298-
if (!blech32_addr_encode(result, confidential_addr_family, 0, buf, written))
299-
return WALLY_ERROR;
300+
goto done;
301+
}
300302

301-
*output = wally_strdup(result);
302-
ret = (*output) ? WALLY_OK : WALLY_ENOMEM;
303+
if (!script_is_op_n(hash_bytes_p[0], true, &witver)) {
304+
ret = WALLY_EINVAL;
305+
goto done;
303306
}
307+
308+
/* Copy the confidentialKey / witness program */
309+
memcpy(buf, pub_key, pub_key_len);
310+
written -= 2; /* ignore witnessVersion & hashSize */
311+
written += EC_PUBLIC_KEY_LEN;
312+
if (!blech32_addr_encode(result, confidential_addr_family, witver & 0xff, buf, written))
313+
return WALLY_ERROR;
314+
315+
*output = wally_strdup(result);
316+
ret = (*output) ? WALLY_OK : WALLY_ENOMEM;
304317
}
305318

319+
done:
306320
wally_clear(buf, sizeof(buf));
307321
wally_clear(result, sizeof(result));
308322
return ret;

0 commit comments

Comments
 (0)