include node_modules so release .zip is deployable
This commit is contained in:
+62
@@ -0,0 +1,62 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
The project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## 0.2.1 - 2022-09-27
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix encoding with uppercase prefix. Previously, such prefixes led to incorrect
|
||||
checksum. With the fix, the prefix case is retained for the encoded string.
|
||||
|
||||
## 0.2.0 - 2021-11-21
|
||||
|
||||
No substantial changes compared to the 0.2.0-rc.0 release.
|
||||
|
||||
## 0.2.0-rc.0 - 2021-11-07
|
||||
|
||||
### Added
|
||||
|
||||
- Support [Bech32m encoding] for arbitrary data and Bitcoin addresses.
|
||||
The new functionality is available on [the demo web page](https://slowli.github.io/bech32-buffer/).
|
||||
|
||||
## 0.1.3 - 2021-05-10
|
||||
|
||||
### Added
|
||||
|
||||
- Document TypeScript typings.
|
||||
|
||||
- Update readme to better document main package APIs.
|
||||
|
||||
### Internal improvements
|
||||
|
||||
- Update dev dependencies.
|
||||
|
||||
- Update Bootstrap / JS dependencies for the demo page.
|
||||
|
||||
## 0.1.2 - 2018-12-23
|
||||
|
||||
### Added
|
||||
|
||||
- Add TypeScript typings for the package.
|
||||
|
||||
### Internal improvements
|
||||
|
||||
- Update dev dependencies.
|
||||
|
||||
## 0.1.1 - 2018-12-15
|
||||
|
||||
### Added
|
||||
|
||||
- Test browser support and add a browser version of the package in the `dist` directory.
|
||||
|
||||
- Support Bitcoin addresses via `BitcoinAddress` class.
|
||||
|
||||
## 0.1.0 - 2017-07-23
|
||||
|
||||
The initial release of `bech32-buffer`.
|
||||
|
||||
[Bech32m encoding]: https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki
|
||||
+202
@@ -0,0 +1,202 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
+185
@@ -0,0 +1,185 @@
|
||||
# Bech32(m) Encoding for Arbitrary Buffers
|
||||
|
||||
[![Build status][workflow-image]][workflow-url]
|
||||
[![Code coverage][coveralls-image]][coveralls-url]
|
||||
[![Demo][demo-image]][demo-url]
|
||||
|
||||
[workflow-image]: https://github.com/slowli/bech32-buffer/workflows/Node.js%20CI/badge.svg?branch=master
|
||||
[workflow-url]: https://github.com/slowli/bech32-buffer/actions
|
||||
[coveralls-image]: https://img.shields.io/coveralls/slowli/bech32-buffer.svg
|
||||
[coveralls-url]: https://coveralls.io/github/slowli/bech32-buffer
|
||||
[demo-image]: https://img.shields.io/badge/demo-live-blue.svg
|
||||
[demo-url]: https://slowli.github.io/bech32-buffer/
|
||||
|
||||
**Bech32** is a Bitcoin address format specified in [BIP 173][bip-173] and [BIP 350][bip-350].
|
||||
Among its advantages are: better adaptability to QR codes and in voice conversations,
|
||||
and improved error detection. This library generalizes Bech32 and its modified version
|
||||
(Bech32m) to encode any reasonably short byte buffers.
|
||||
|
||||
## Usage
|
||||
|
||||
### Encoding data
|
||||
|
||||
```typescript
|
||||
declare function encode(
|
||||
prefix: string,
|
||||
data: Uint8Array,
|
||||
encoding: 'bech32' | 'bech32m' = 'bech32'
|
||||
): string;
|
||||
```
|
||||
|
||||
Encodes binary `data` with the specified human-readable `prefix` into a Bech32(m) string.
|
||||
The case is preserved: if the prefix is uppercase, then the output will be uppercase
|
||||
as well; otherwise, the output will be lowercase (including the case when the prefix does
|
||||
not contain any letters).
|
||||
|
||||
#### Arguments
|
||||
|
||||
- **prefix:** string
|
||||
Human-readable prefix to hint what kind of data Bech32 encodes. Must contain
|
||||
ASCII chars in the range 33-126
|
||||
- **data:** Uint8Array
|
||||
Binary data to encode
|
||||
- **encoding:** `bech32` or `bech32m`
|
||||
Specifies whether to use the original Bech32 encoding from [BIP 173][bip-173]
|
||||
or the modified encoding from [BIP 350][bip-350]; they differ
|
||||
in how a checksum is computed. If omitted, the original encoding is used.
|
||||
|
||||
#### Return value
|
||||
|
||||
String containing:
|
||||
|
||||
1. `prefix`
|
||||
2. `'1'` separator char
|
||||
3. `data` encoded with the variant of base32 encoding used by Bech32, and
|
||||
4. 6-char checksum calculated based on `prefix` and `data`
|
||||
|
||||
#### Example
|
||||
|
||||
```javascript
|
||||
const bech32 = require('bech32-buffer');
|
||||
const data = new Uint8Array(20);
|
||||
bech32.encode('test', data);
|
||||
// 'test1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqql6aptf'
|
||||
```
|
||||
|
||||
### Decoding data
|
||||
|
||||
```typescript
|
||||
declare function decode(message: string): {
|
||||
prefix: string,
|
||||
encoding: 'bech32' | 'bech32m',
|
||||
data: Uint8Array
|
||||
};
|
||||
```
|
||||
|
||||
Extracts human-readable prefix and binary data from the Bech32-encoded string.
|
||||
|
||||
#### Arguments
|
||||
|
||||
- **data:** string
|
||||
String to decode
|
||||
|
||||
#### Return value
|
||||
|
||||
An object with the following fields:
|
||||
|
||||
- **prefix:** string
|
||||
Human-readable prefix
|
||||
- **encoding:** `bech32` or `bech32m`
|
||||
Encoding variant inferred from the checksum.
|
||||
- **data:** Uint8Array
|
||||
Binary data encoded into the input string
|
||||
|
||||
Decoding may fail for a variety of reasons (e.g., invalid checksum, or invalid
|
||||
chars in the input). In this case, `decode()` throws an exception
|
||||
with a descriptive message.
|
||||
|
||||
#### Example
|
||||
|
||||
```javascript
|
||||
const bech32 = require('bech32-buffer');
|
||||
const data = 'lost1qsyq7yqh9gk0szs5';
|
||||
bech32.decode(data);
|
||||
// {
|
||||
// prefix: 'lost',
|
||||
// encoding: 'bech32',
|
||||
// data: Uint8Array([ 4, 8, 15, 16, 23, 42 ])
|
||||
// }
|
||||
```
|
||||
|
||||
### Bitcoin addresses
|
||||
|
||||
```typescript
|
||||
declare class BitcoinAddress {
|
||||
prefix: 'bc' | 'tb';
|
||||
scriptVersion: number;
|
||||
data: Uint8Array;
|
||||
|
||||
static decode(message: string): BitcoinAddress;
|
||||
constructor(prefix: 'bc' | 'tb', scriptVersion: number, data: Uint8Array);
|
||||
encode(): string;
|
||||
type(): void | 'p2wsh' | 'p2wpkh';
|
||||
}
|
||||
```
|
||||
|
||||
Provides basic functionality to work with Bech32 encoding of Bitcoin addresses.
|
||||
Addresses can be `decode`d from strings and `encode`d into strings.
|
||||
It is also possible to check the `type` of an address. P2WSH and P2WPKH address
|
||||
types are defined per [BIP 141]. Encoding constraints are defined per [BIP 173][bip-173]
|
||||
and [BIP 350][bip-350].
|
||||
|
||||
#### Example
|
||||
|
||||
```javascript
|
||||
const { BitcoinAddress } = require('bech32-buffer');
|
||||
const address = BitcoinAddress.decode('BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4');
|
||||
// address.prefix === 'bc'
|
||||
// address.scriptVersion === 0
|
||||
// address.data.length === 20
|
||||
// address.type() === 'p2wpkh'
|
||||
```
|
||||
|
||||
## Use in Browsers
|
||||
|
||||
Use `dist/bech32-buffer.min.js` from the package distribution
|
||||
or your favorite browserifier. In the first case,
|
||||
the library will be available as a `bech32` global variable:
|
||||
|
||||
```html
|
||||
<script src="bech32-buffer.min.js"></script>
|
||||
<!-- later -->
|
||||
<script>
|
||||
bech32.encode('test', new Uint8Array(20));
|
||||
</script>
|
||||
```
|
||||
|
||||
Check out [the web demo](https://slowli.github.io/bech32-buffer/) to see how
|
||||
**bech32-buffer** works in browser. It is also available in the `examples`
|
||||
directory of the package.
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
[BIP 173][bip-173] is authored by Pieter Wuille and Greg Maxwell and is licensed
|
||||
under the 2-clause BSD license.
|
||||
[BIP 350][bip-350] is authored by Pieter Wuille and is licensed
|
||||
under the 2-clause BSD license.
|
||||
|
||||
There are at least 2 existing implementations of Bech32 for JavaScript:
|
||||
|
||||
- [The reference implementation][ref] by Pieter Wuille
|
||||
- [Another implementation][bech32] available as the [`bech32` package][bech32-pkg]
|
||||
|
||||
Both implementations are Bitcoin-specific, and the reference implementation
|
||||
is also not in the Npm / yarn package manager.
|
||||
|
||||
## License
|
||||
|
||||
**bech32-buffer** is available under [Apache-2.0 license](LICENSE).
|
||||
|
||||
[bip-173]: https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki
|
||||
[bip-350]: https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki
|
||||
[ref]: https://github.com/sipa/bech32/tree/master/ref/javascript
|
||||
[bech32]: https://github.com/bitcoinjs/bech32
|
||||
[bech32-pkg]: https://www.npmjs.com/package/bech32
|
||||
[BIP 141]: https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.bech32 = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
|
||||
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.createBitArray=createBitArray,exports.fromBits=fromBits,exports.toBits=toBits;function toBitArrayUnchecked(a){return a}function createBitArray(a){return toBitArrayUnchecked(new Uint8Array(a))}function convert(a,c,d,e,f){var g=(1<<e)-1,h=0,i=0,j=0;if(a.forEach(function(a){for(h=(h<<c)+a,i+=c;i>=e;)i-=e,d[j]=h>>i&g,j+=1}),f)0<i&&(d[j]=h<<e-i&g);else{if(i>=c)throw new Error("Excessive padding: ".concat(i," (max ").concat(c-1," allowed)"));if(0!=h%(1<<i))throw new Error("Non-zero padding")}}function toBits(a,b,c){if(8<b||1>b)throw new RangeError("Invalid bits per element; 1 to 8 expected");return convert(toBitArrayUnchecked(a),8,c,b,!0),c}function fromBits(a,b,c){if(8<b||1>b)throw new RangeError("Invalid bits per element; 1 to 8 expected");return convert(a,b,toBitArrayUnchecked(c),8,!1),c}
|
||||
|
||||
},{}],2:[function(require,module,exports){
|
||||
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.CHECKSUM_LENGTH=void 0,exports.createChecksum=createChecksum,exports.decode=decode,exports.decodeWithPrefix=decodeWithPrefix,exports.detectCase=detectCase,exports.encode=encode,exports.expandPrefix=expandPrefix,exports.verifyChecksum=verifyChecksum;var _bitConverter=require("./bit-converter"),CHARSET="qpzry9x8gf2tvdw0s3jn54khce6mua7l",BECH32M_CHECKSUM=734539939,MIN_CHAR_CODE=33,MAX_CHAR_CODE=126,CHECKSUM_LENGTH=6;exports.CHECKSUM_LENGTH=CHECKSUM_LENGTH;var CHAR_LOOKUP=function(){for(var a=new Map,b=0;b<CHARSET.length;b+=1)a.set(CHARSET[b],b);return a}(),GEN=[996825010,642813549,513874426,1027748829,705979059];function polymod(a){return a.reduce(function(a,b){return GEN.reduce(function(b,c,d){return 0==(1&a>>25>>d)?b:b^c},(33554431&a)<<5^b)},1)}function expandPrefix(a,b){for(var c,d=0;d<a.length;d+=1)c=a.charCodeAt(d),b[d]=c>>5,b[d+a.length+1]=31&c;b[a.length]=0}function verifyChecksum(a){switch(polymod(a)){case 1:return"bech32";case BECH32M_CHECKSUM:return"bech32m";default:}}function createChecksum(a,b){var c;switch(b){case"bech32":c=1;break;case"bech32m":c=BECH32M_CHECKSUM;break;default:throw Error("Invalid encoding value: ".concat(b,"; expected bech32 or bech32m"));}for(var d,e=polymod(a)^c,f=0;f<CHECKSUM_LENGTH;f+=1)d=5*(5-f),a[a.length-CHECKSUM_LENGTH+f]=31&e>>d}function encode(a){return a.reduce(function(a,b){return a+CHARSET[b]},"")}function decode(a,b){for(var c,d=b||(0,_bitConverter.createBitArray)(a.length),e=0;e<a.length;e+=1){if(c=CHAR_LOOKUP.get(a[e]),void 0===c)throw new Error("Invalid char in message: ".concat(a[e]));d[e]=c}return d}function decodeWithPrefix(a,b){var c=b.length+2*a.length+1,d=(0,_bitConverter.createBitArray)(c);return expandPrefix(a,d.subarray(0,2*a.length+1)),decode(b,d.subarray(2*a.length+1)),d}function detectCase(a){for(var b,c=1<arguments.length&&void 0!==arguments[1]?arguments[1]:"message",d=!1,e=!1,f=0;f<a.length;f+=1){if(b=a.charCodeAt(f),b<MIN_CHAR_CODE||b>MAX_CHAR_CODE)throw new TypeError("Invalid char in ".concat(c,": ").concat(b,"; ")+"should be in ASCII range ".concat(MIN_CHAR_CODE,"-").concat(MAX_CHAR_CODE));e=e||65<=b&&90>=b,d=d||97<=b&&122>=b}if(d&&e)throw new TypeError("Mixed-case ".concat(c));else return e?"upper":d?"lower":null}
|
||||
|
||||
},{"./bit-converter":1}],3:[function(require,module,exports){
|
||||
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.BitcoinAddress=void 0,exports.decode=decode,exports.decodeTo5BitArray=decodeTo5BitArray,exports.encode=encode,exports.encode5BitArray=encode5BitArray,exports.from5BitArray=from5BitArray,exports.to5BitArray=to5BitArray;var _bitConverter=require("./bit-converter"),_encoding=require("./encoding");function _classCallCheck(a,b){if(!(a instanceof b))throw new TypeError("Cannot call a class as a function")}function _defineProperties(a,b){for(var c,d=0;d<b.length;d++)c=b[d],c.enumerable=c.enumerable||!1,c.configurable=!0,"value"in c&&(c.writable=!0),Object.defineProperty(a,c.key,c)}function _createClass(a,b,c){return b&&_defineProperties(a.prototype,b),c&&_defineProperties(a,c),Object.defineProperty(a,"prototype",{writable:!1}),a}var MAX_ENC_LENGTH=90;function to5BitArray(a,b){var c=Math.ceil(8*a.length/5),d=b||(0,_bitConverter.createBitArray)(c);return(0,_bitConverter.toBits)(a,5,d)}function from5BitArray(a,b){var c=Math.floor(5*a.length/8),d=b||new Uint8Array(c);return(0,_bitConverter.fromBits)(a,5,d)}function encode5BitArray(a,b){var c,d=2<arguments.length&&void 0!==arguments[2]?arguments[2]:"bech32",e=2*a.length+1+b.length+_encoding.CHECKSUM_LENGTH;if(e-a.length>MAX_ENC_LENGTH)throw new Error("Message to be produced is too long (max ".concat(MAX_ENC_LENGTH," supported)"));var f=null!==(c=(0,_encoding.detectCase)(a,"prefix"))&&void 0!==c?c:"lower",g=(0,_bitConverter.createBitArray)(e);(0,_encoding.expandPrefix)(a.toLowerCase(),g.subarray(0,2*a.length+1));var h=g.subarray(2*a.length+1,g.length-_encoding.CHECKSUM_LENGTH);h.set(b),(0,_encoding.createChecksum)(g,d);var i=(0,_encoding.encode)(g.subarray(2*a.length+1));return"upper"===f&&(i=i.toUpperCase()),"".concat(a,"1").concat(i)}function encode(a,b){var c=2<arguments.length&&arguments[2]!==void 0?arguments[2]:"bech32";return encode5BitArray(a,to5BitArray(b),c)}function decodeTo5BitArray(a){if(a.length>MAX_ENC_LENGTH)throw new TypeError("Message too long; max ".concat(MAX_ENC_LENGTH," expected"));(0,_encoding.detectCase)(a);var b=a.toLowerCase(),c=b.lastIndexOf("1");if(0>c)throw new Error("No separator char (\"1\") found");if(c>a.length-_encoding.CHECKSUM_LENGTH-1)throw new Error("Data part of the message too short (at least ".concat(_encoding.CHECKSUM_LENGTH," chars expected)"));var d=b.substring(0,c),e=(0,_encoding.decodeWithPrefix)(d,b.substring(c+1)),f=(0,_encoding.verifyChecksum)(e);if(f===void 0)throw new Error("Invalid checksum");return{prefix:d,encoding:f,data:e.subarray(2*d.length+1,e.length-_encoding.CHECKSUM_LENGTH)}}function decode(a){var b=decodeTo5BitArray(a),c=b.prefix,d=b.encoding,e=b.data;return{prefix:c,encoding:d,data:from5BitArray(e)}}var BitcoinAddress=function(){var a=Math.ceil;function b(a,c,d){if(_classCallCheck(this,b),"bc"!==a&&"tb"!==a)throw new Error("Invalid human-readable prefix, \"bc\" or \"tb\" expected");if(0>c||16<c)throw new RangeError("Invalid scriptVersion, value in range [0, 16] expected");if(2>d.length||40<d.length)throw new RangeError("Invalid script length: expected 2 to 40 bytes");if(0===c&&20!==d.length&&32!==d.length)throw new Error("Invalid v0 script length: expected 20 or 32 bytes");this.prefix=a,this.scriptVersion=c,this.data=d}return _createClass(b,[{key:"type",value:function type(){if(0===this.scriptVersion)switch(this.data.length){case 20:return"p2wpkh";case 32:return"p2wsh";default:}}},{key:"encode",value:function(){var b=a(8*this.data.length/5),c=(0,_bitConverter.createBitArray)(b+1);c[0]=this.scriptVersion,to5BitArray(this.data,c.subarray(1));var d=0===this.scriptVersion?"bech32":"bech32m";return encode5BitArray(this.prefix,c,d)}}],[{key:"decode",value:function(a){var b=decodeTo5BitArray(a),c=b.prefix,d=b.data,e=b.encoding;if("bc"!==c&&"tb"!==c)throw new Error("Invalid human-readable prefix, \"bc\" or \"tb\" expected");var f=d[0];if(0===f&&"bech32"!==e)throw Error("Unexpected encoding ".concat(e," used for version 0 script"));if(0<f&&"bech32m"!==e)throw Error("Unexpected encoding ".concat(e," used for version ").concat(f," script"));return new this(c,f,from5BitArray(d.subarray(1)))}}]),b}();exports.BitcoinAddress=BitcoinAddress;
|
||||
|
||||
},{"./bit-converter":1,"./encoding":2}]},{},[3])(3)
|
||||
});
|
||||
+346
@@ -0,0 +1,346 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no">
|
||||
<meta name="keywords" content="bech32, base32, bitcoin">
|
||||
<meta name="description" content="Demo of bech32-buffer package capabilities">
|
||||
|
||||
<title>Bech32 Demo</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-wEmeIV1mKuiNpC+IOBjI7aAzPcEZeedi5yW5f2yOq55WWLwNGmvvx4Um1vskeMj0" crossorigin="anonymous">
|
||||
<style>
|
||||
textarea {
|
||||
resize: none;
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
input[type=number] {
|
||||
max-width: 5rem;
|
||||
}
|
||||
|
||||
.content {
|
||||
max-width: 1080px;
|
||||
margin: 0 auto;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.body-header {
|
||||
padding: 1rem;
|
||||
background: #f4f4f4;
|
||||
border-bottom: 1px solid #eee;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.page-footer {
|
||||
margin: 4rem -0.5rem 0 -0.5rem;
|
||||
padding: 2rem 0 1.5rem;
|
||||
border-top: 1px solid rgba(0,0,0,0.15);
|
||||
}
|
||||
|
||||
.align-height {
|
||||
min-height: 152px;
|
||||
}
|
||||
.card-header.align-header-height {
|
||||
height: 49px;
|
||||
}
|
||||
|
||||
.qr-placeholder {
|
||||
display: inline-block;
|
||||
width: 132px;
|
||||
height: 132px;
|
||||
background: rgba(0,0,0,0.15);
|
||||
color: white;
|
||||
}
|
||||
.qr-placeholder:before {
|
||||
content: '?';
|
||||
font-size: 72px;
|
||||
line-height: 1;
|
||||
height: 72px;
|
||||
position: relative;
|
||||
top: 50%;
|
||||
margin-top: -36px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#encode:after {
|
||||
content: ' ↓';
|
||||
}
|
||||
#decode:after {
|
||||
content: ' ↑';
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
#encode:after {
|
||||
content: ' →';
|
||||
}
|
||||
#decode:after {
|
||||
content: ' ←';
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header class="body-header">
|
||||
<div class="content">
|
||||
<h1>bech32-buffer</h1>
|
||||
<p class="lead">Bech32 is a Bitcoin address format proposed by Pieter Wuille and Greg Maxwell in <a href="https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki">BIP 173</a> and later amended by <a href="https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki">BIP 350</a>.
|
||||
Besides Bitcoin addresses, Bech32 can encode any short binary data.</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="content">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3 mb-md-0">
|
||||
<div class="card">
|
||||
<div class="card-header align-header-height">
|
||||
<ul class="nav nav-tabs card-header-tabs">
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link active" id="encode-btc-tab" data-bs-toggle="tab" data-bs-target="#encode-btc" type="button" role="tab" aria-controls="home" aria-selected="true">BTC Address</button>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<button class="nav-link" id="encode-data-tab" data-bs-toggle="tab" data-bs-target="#encode-data" type="button" role="tab" aria-controls="home" aria-selected="false">Data</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="card-block p-2">
|
||||
<form>
|
||||
<div class="align-height tab-content">
|
||||
<div class="tab-pane" id="encode-data" role="tabpanel" aria-labelledby="encode-data-tab">
|
||||
<div class="mb-3 row">
|
||||
<label for="hrp" class="col-3 col-form-label">Tag</label>
|
||||
<div class="col-9">
|
||||
<input type="text" id="hrp" class="form-control" placeholder="Tag"/>
|
||||
</div>
|
||||
<div class="col-12 form-text text-muted small">A short tag describing what a Bech32-encoded string is used for.</div>
|
||||
</div>
|
||||
<div class="mb-3 row">
|
||||
<label class="col-3 col-form-label">Encoding</label>
|
||||
<div class="col-9">
|
||||
<div class="btn-group" role="group">
|
||||
<input type="radio" class="btn-check" name="encoding-options" id="encoding-bech32" autocomplete="off">
|
||||
<label for="encoding-bech32" class="btn btn-outline-primary" title="Original encoding proposed in BIP 173">Bech32</label>
|
||||
<input type="radio" class="btn-check" name="encoding-options" id="encoding-bech32m" autocomplete="off" checked>
|
||||
<label for="encoding-bech32m" class="btn btn-outline-primary" title="Amended encoding from BIP 350">Bech32m</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane active" id="encode-btc" role="tabpanel" aria-labelledby="encode-btc-tab">
|
||||
<div class="mb-3 row">
|
||||
<label class="col-3 col-form-label">Network</label>
|
||||
<div class="col-9">
|
||||
<div class="btn-group" role="group">
|
||||
<input type="radio" class="btn-check" name="btc-network-options" id="btc-mainnet" autocomplete="off" checked>
|
||||
<label for="btc-mainnet" class="btn btn-outline-primary">Mainnet</label>
|
||||
<input type="radio" class="btn-check" name="btc-network-options" id="btc-testnet" autocomplete="off">
|
||||
<label for="btc-testnet" class="btn btn-outline-primary">Testnet</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3 row">
|
||||
<label for="script-version" class="col-3 col-form-label">Script ver.</label>
|
||||
<div class="col-9">
|
||||
<input type="number" id="script-version" min="0" max="16" size="6" value="0">
|
||||
</div>
|
||||
<div class="col-12 form-text">Note that version 0 scripts should have length 20 or 32 bytes.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<label for="data" class="form-label">Data</label>
|
||||
<textarea id="data" class="form-control" placeholder="Hex data"></textarea>
|
||||
<div class="form-text text-muted small">Binary data (in hex) to be encoded into Bech32.</div>
|
||||
</div>
|
||||
|
||||
<button type="button" id="encode" class="btn btn-primary" data-container="body" data-toggle="popover" data-placement="bottom" data-content="">Encode</button>
|
||||
<a id="random" title="Generate random data" class="ms-3" href="#">Random data</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<h3 class="card-header align-header-height">Bech32</h3>
|
||||
<div id="qrcode" class="card-img-top text-center py-2 align-height" title="QR code with the latest encoded or decoded message"><div class="qr-placeholder"></div></div>
|
||||
<div class="card-block p-2">
|
||||
<form>
|
||||
<div class="mb-4">
|
||||
<label for="encoded" class="form-label">Encoded data</label>
|
||||
<textarea id="encoded" class="form-control" placeholder="Bech32 string"></textarea>
|
||||
<div class="form-text text-muted small">Encoded Bech32 string.</div>
|
||||
</div>
|
||||
|
||||
<button type="button" id="decode" class="btn btn-primary" data-container="body" data-toggle="popover" data-placement="top" data-content="">Decode</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer class="page-footer small text-muted">
|
||||
<span class="copyright">© 2021 Alex Ostrovski</span>
|
||||
<div class="float-none float-sm-end">
|
||||
<a href="https://github.com/slowli/bech32-buffer">GitHub</a> •
|
||||
<a href="https://npmjs.com/package/bech32-buffer">Npm</a> •
|
||||
<a href="../dist/bech32-buffer.min.js" download="bech32-buffer.min.js">Browser version</a>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.slim.min.js" integrity="sha256-u7e5khyithlIdTpu22PHhENmPcRdFiHRjhAuHcs05RI=" crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-p34f1UUtsS3wqzfto5wAAmdvj+osOnFyQFpp4Ua3gs/ZVWx6oOypYoCJhGGScy+8" crossorigin="anonymous"></script>
|
||||
|
||||
<script src="qrcode.min.js"></script>
|
||||
<script src="../dist/bech32-buffer.min.js"></script>
|
||||
|
||||
<script>
|
||||
/* eslint-env browser, jquery */
|
||||
/* global bech32 */
|
||||
(function () {
|
||||
/**
|
||||
* Converts a byte array into a hex string.
|
||||
*/
|
||||
function toHexString(buffer) {
|
||||
return buffer.reduce((s, byte) => {
|
||||
let hex = byte.toString(16);
|
||||
if (hex.length === 1) hex = '0' + hex;
|
||||
return s + hex;
|
||||
}, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a hex string into a byte array.
|
||||
*
|
||||
* @returns {?Uint8Array}
|
||||
* decoded array, or `null` if the supplied string is not a valid hex string
|
||||
*/
|
||||
function fromHexString(str) {
|
||||
if (str.length % 2 !== 0 || !/^[0-9a-f]+$/i.test(str)) {
|
||||
return null;
|
||||
}
|
||||
let buffer = new Uint8Array(str.length / 2);
|
||||
for (let i = 0; i < buffer.length; i++) {
|
||||
buffer[i] = parseInt(str.substr(2 * i, 2), 16);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
const hrp = $('#hrp');
|
||||
const data = $('#data');
|
||||
const encoded = $('#encoded');
|
||||
const encodeBtn = $('#encode');
|
||||
const decodeBtn = $('#decode');
|
||||
const randomBtn = $('#random');
|
||||
const scriptVersion = $('#script-version');
|
||||
|
||||
const timeouts = {};
|
||||
|
||||
function report(type, btn, message) {
|
||||
const id = btn[0].id;
|
||||
const timeout = timeouts[id];
|
||||
if (timeout) clearTimeout(timeout);
|
||||
|
||||
btn.attr('data-bs-content', '<span class="text-' + type + '">' + message + '</span>');
|
||||
btn[0].popover.show();
|
||||
timeouts[id] = setTimeout(function() {
|
||||
btn[0].popover.hide();
|
||||
delete timeouts[id];
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
encodeBtn.click(function() {
|
||||
let enc;
|
||||
const btc = $('#encode-btc').hasClass('active');
|
||||
|
||||
try {
|
||||
const buffer = fromHexString(data.val());
|
||||
if (!buffer) throw new TypeError('Invalid hex encoding of data');
|
||||
|
||||
if (btc) {
|
||||
const prefix = $('#btc-mainnet').prop('checked') ? 'bc' : 'tb';
|
||||
const version = parseInt(scriptVersion.val());
|
||||
const btcAddress = new bech32.BitcoinAddress(prefix, version, buffer);
|
||||
enc = btcAddress.encode();
|
||||
} else {
|
||||
const encoding = $('#encoding-bech32').prop('checked') ? 'bech32' : 'bech32m';
|
||||
enc = bech32.encode(hrp.val(), buffer, encoding);
|
||||
}
|
||||
encoded.val(enc);
|
||||
} catch (e) {
|
||||
report('danger', encodeBtn, 'Error: ' + e.message);
|
||||
return;
|
||||
}
|
||||
|
||||
report('success', encodeBtn, 'Data encoded (' + enc.length + ' chars)');
|
||||
const qr = qrcode(0, 'M');
|
||||
qr.addData(enc.toUpperCase(), 'Alphanumeric');
|
||||
qr.make();
|
||||
$('#qrcode').html(qr.createSvgTag(4, 0));
|
||||
});
|
||||
|
||||
decodeBtn.click(function() {
|
||||
let dec;
|
||||
const btc = $('#encode-btc').hasClass('active');
|
||||
|
||||
try {
|
||||
if (btc) {
|
||||
dec = bech32.BitcoinAddress.decode(encoded.val());
|
||||
scriptVersion.val(dec.scriptVersion);
|
||||
|
||||
var selectedNetwork = (dec.prefix === 'bc') ? $('#btc-mainnet') : $('#btc-testnet');
|
||||
$('input[name=btc-network-options]').parent().removeClass('active');
|
||||
selectedNetwork.prop('checked', true);
|
||||
selectedNetwork.parent().addClass('active');
|
||||
} else {
|
||||
dec = bech32.decode(encoded.val());
|
||||
hrp.val(dec.prefix);
|
||||
|
||||
var selectedEncoding = (dec.encoding === 'bech32') ? $('#encoding-bech32') : $('#encoding-bech32m');
|
||||
$('input[name=encoding-options]').parent().removeClass('active');
|
||||
selectedEncoding.prop('checked', true);
|
||||
selectedEncoding.parent().addClass('active');
|
||||
}
|
||||
data.val(toHexString(dec.data));
|
||||
} catch (e) {
|
||||
report('danger', decodeBtn, 'Error: ' + e.message);
|
||||
return;
|
||||
}
|
||||
|
||||
report('success', decodeBtn, 'Data decoded (' + dec.data.length + ' bytes)');
|
||||
const qr = qrcode(0, 'M');
|
||||
qr.addData(encoded.val().toUpperCase(), 'Alphanumeric');
|
||||
qr.make();
|
||||
$('#qrcode').html(qr.createSvgTag(4, 0));
|
||||
});
|
||||
|
||||
$('#encode,#decode').each(function () {
|
||||
this.popover = new bootstrap.Popover(this, {
|
||||
trigger: 'manual',
|
||||
html: true
|
||||
});
|
||||
});
|
||||
|
||||
randomBtn.click(function(e) {
|
||||
e.preventDefault();
|
||||
const btc = $('#encode-btc').hasClass('active');
|
||||
|
||||
// Not secure! Don't use in production.
|
||||
const length = (btc && parseInt(scriptVersion.val()) === 0)
|
||||
? (Math.random() > 0.5 ? 32 : 20)
|
||||
: 8 + Math.floor(Math.random() * 32);
|
||||
const buffer = new Uint8Array(length);
|
||||
for (let i = 0; i < length; i++) {
|
||||
buffer[i] = Math.floor(Math.random() * 256);
|
||||
}
|
||||
data.val(toHexString(buffer));
|
||||
});
|
||||
|
||||
scriptVersion.change(function() {
|
||||
const version = parseInt(scriptVersion.val());
|
||||
if (version < 0) scriptVersion.val(0);
|
||||
if (version > 16) scriptVersion.val(16);
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
+1991
File diff suppressed because it is too large
Load Diff
+180
@@ -0,0 +1,180 @@
|
||||
/**
|
||||
* Virtual type for an array in which each element represents 5 bits.
|
||||
*/
|
||||
export declare type FiveBitArray = Uint8Array;
|
||||
// As TypeScript (unlike Flow) always uses structural typing for determining type compatibility,
|
||||
// there seems to be no way to express this better.
|
||||
|
||||
/**
|
||||
* Encoding from the Bech32 family used during encoding / decoding.
|
||||
*/
|
||||
export declare type Encoding = 'bech32' | 'bech32m';
|
||||
|
||||
/**
|
||||
* Converts a Uint8Array into a Uint8Array variant, in which each element
|
||||
* encodes 5 bits of the original byte array.
|
||||
*
|
||||
* @param src
|
||||
* Input to convert
|
||||
* @param dst
|
||||
* Optional output buffer. If specified, the sequence of 5-bit chunks will be written there;
|
||||
* if not specified, the output buffer will be created from scratch. The length
|
||||
* of `outBuffer` is not checked.
|
||||
* @returns
|
||||
* Output buffer consisting of 5-bit chunks
|
||||
*/
|
||||
export declare function to5BitArray(src: Uint8Array, dst?: FiveBitArray): FiveBitArray;
|
||||
|
||||
/**
|
||||
* Converts a sequence of 5-bit chunks into an ordinary Uint8Array.
|
||||
*
|
||||
* @param src
|
||||
* Input to convert
|
||||
* @param dst
|
||||
* Optional output buffer. If specified, the converted bytes will be written there;
|
||||
* if not specified, the output buffer will be created from scratch. The length
|
||||
* of `outBuffer` is not checked.
|
||||
* @returns
|
||||
* Output buffer
|
||||
*/
|
||||
export declare function from5BitArray(src: FiveBitArray, dst?: Uint8Array): Uint8Array;
|
||||
|
||||
/**
|
||||
* Encodes binary data into Bech32 encoding.
|
||||
*
|
||||
* The case is preserved: if the prefix is uppercase, then the output will be uppercase
|
||||
* as well; otherwise, the output will be lowercase (including the case when the prefix does
|
||||
* not contain any letters).
|
||||
*
|
||||
* Ordinarily, you may want to use `encode` because it converts
|
||||
* binary data to an array of 5-bit integers automatically.
|
||||
*
|
||||
* @param prefix
|
||||
* Human-readable prefix to place at the beginning of the encoding
|
||||
* @param data
|
||||
* Array of 5-bit integers with data to encode
|
||||
* @param encoding
|
||||
* Encoding to use; influences the checksum computation. If not specified,
|
||||
* Bech32 encoding will be used.
|
||||
* @returns
|
||||
* Bech32(m) encoding of data in the form `<prefix>1<base32 of data><checksum>`
|
||||
* @throws If the prefix is mixed-case or contains chars that are not eligible for Bech32 encoding
|
||||
*/
|
||||
export declare function encode5BitArray(
|
||||
prefix: string,
|
||||
data: FiveBitArray,
|
||||
encoding?: Encoding
|
||||
): string;
|
||||
|
||||
/**
|
||||
* Result of a decoding operation.
|
||||
*/
|
||||
export interface DecodeResult<T = Uint8Array> {
|
||||
/** Human-readable prefix. */
|
||||
prefix: string;
|
||||
/** Variation of the Bech32 encoding inferred from the checksum. */
|
||||
encoding: Encoding;
|
||||
/** Decoded data. */
|
||||
data: T;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes data from Bech32 encoding into an array of 5-bit integers.
|
||||
*
|
||||
* Ordinarily, you may want to use `decode` because it automatically
|
||||
* converts the array of 5-bit integers into an ordinary `Uint8Array`.
|
||||
*
|
||||
* @param message
|
||||
* Bech32-encoded message
|
||||
* @returns
|
||||
* Decoded object with `prefix` and `data` fields, which contain the human-readable
|
||||
* prefix and the array of 5-bit integers respectively.
|
||||
*/
|
||||
export declare function decodeTo5BitArray(message: string): DecodeResult<FiveBitArray>;
|
||||
|
||||
/**
|
||||
* Encodes binary data into Bech32 encoding.
|
||||
*
|
||||
* The case is preserved: if the prefix is uppercase, then the output will be uppercase
|
||||
* as well; otherwise, the output will be lowercase (including the case when the prefix does
|
||||
* not contain any letters).
|
||||
*
|
||||
* @param prefix
|
||||
* Human-readable prefix to place at the beginning of the encoding
|
||||
* @param data
|
||||
* Binary data to encode
|
||||
* @param encoding
|
||||
* Encoding to use; influences the checksum computation. If not specified,
|
||||
* Bech32 encoding will be used.
|
||||
* @returns
|
||||
* Bech32 encoding of data in the form `<prefix>1<base32 of data><checksum>`
|
||||
* @throws If the prefix is mixed-case or contains chars that are not eligible for Bech32 encoding
|
||||
*/
|
||||
export declare function encode(
|
||||
prefix: string,
|
||||
data: Uint8Array,
|
||||
encoding?: Encoding
|
||||
): string;
|
||||
|
||||
/**
|
||||
* Decodes data from Bech32 encoding into an array of 5-bit integers.
|
||||
*
|
||||
* @param message
|
||||
* Bech32-encoded message
|
||||
* @returns
|
||||
* Decoded object with `prefix` and `data` fields, which contain the human-readable
|
||||
* prefix and the decoded binary data respectively.
|
||||
*/
|
||||
export declare function decode(message: string): DecodeResult;
|
||||
|
||||
/**
|
||||
* Bitcoin address.
|
||||
*/
|
||||
export declare class BitcoinAddress {
|
||||
/**
|
||||
* Human-readable prefix. Equals `'bc'` (for mainnet addresses)
|
||||
* or `'tb'` (for testnet addresses).
|
||||
*/
|
||||
prefix: 'bc' | 'tb';
|
||||
/**
|
||||
* Script version. An integer between 0 and 16 (inclusive).
|
||||
*/
|
||||
scriptVersion: number;
|
||||
/**
|
||||
* Script data. A byte string with length 2 to 40 (inclusive).
|
||||
*/
|
||||
data: Uint8Array;
|
||||
|
||||
/**
|
||||
* Decodes a Bitcoin address from a Bech32 string.
|
||||
* As per BIP 350, the original encoding is expected for version 0 scripts, while
|
||||
* other script versions expect the modified encoding.
|
||||
*
|
||||
* This method does not check whether the address is well-formed;
|
||||
* use `type()` method on returned address to find that out.
|
||||
*/
|
||||
static decode(message: string): BitcoinAddress;
|
||||
|
||||
/**
|
||||
* Creates a new address based on provided data.
|
||||
*
|
||||
* Validation is performed on the fields as specified in their description (e.g.,
|
||||
* it is checked that `scriptVersion` is between 0 and 16). Additionally,
|
||||
* for `scriptVersion == 0` it is checked that `data` is either 20 or 32 bytes long.
|
||||
*
|
||||
* @throws {Error} If provided fields do not pass validation.
|
||||
*/
|
||||
constructor(prefix: 'bc' | 'tb', scriptVersion: number, data: Uint8Array);
|
||||
|
||||
/**
|
||||
* Encodes this address in Bech32 or Bech32m format, depending on the script version.
|
||||
* Version 0 scripts are encoded using original Bech32 encoding as per BIP 173,
|
||||
* while versions 1-16 are encoded using the modified encoding as per BIP 350.
|
||||
*/
|
||||
encode(): string;
|
||||
|
||||
/**
|
||||
* Guesses the address type based on its internal structure.
|
||||
*/
|
||||
type(): void | 'p2wsh' | 'p2wpkh';
|
||||
}
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.createBitArray = createBitArray;
|
||||
exports.fromBits = fromBits;
|
||||
exports.toBits = toBits;
|
||||
|
||||
/* eslint-disable no-unused-vars */
|
||||
|
||||
/**
|
||||
* Virtual type for bit arrays, i.e., arrays in which each element contains
|
||||
* an integer in range `[0, 1 << L)`, where `1 <= L <= 8`.
|
||||
*/
|
||||
|
||||
/* eslint-enable no-unused-vars */
|
||||
|
||||
/**
|
||||
* Performs unchecked conversion from `Uint8Array` to `BitArray`.
|
||||
* This function is translated as the indentity operation by Babel; it's needed purely
|
||||
* for Flow type checks.
|
||||
*
|
||||
* @param {Uint8Array} src
|
||||
* array to convert
|
||||
* @returns {Uint8Array}
|
||||
* `src` interpreted as a `BitArray` with the specified bitness
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
function toBitArrayUnchecked(src) {
|
||||
return src;
|
||||
}
|
||||
/**
|
||||
* Creates a new array with specified bitness.
|
||||
*
|
||||
* @param {number} len
|
||||
* length of the created array
|
||||
* @returns {Uint8Array}
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
|
||||
function createBitArray(len) {
|
||||
return toBitArrayUnchecked(new Uint8Array(len));
|
||||
}
|
||||
/**
|
||||
* Converts an array from one number of bits per element to another.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
|
||||
function convert(src, srcBits, dst, dstBits, pad) {
|
||||
var mask = (1 << dstBits) - 1;
|
||||
var acc = 0;
|
||||
var bits = 0;
|
||||
var pos = 0;
|
||||
src.forEach(function (b) {
|
||||
// Pull next bits from the input buffer into accumulator.
|
||||
acc = (acc << srcBits) + b;
|
||||
bits += srcBits; // Push into the output buffer while there are enough bits in the accumulator.
|
||||
|
||||
while (bits >= dstBits) {
|
||||
bits -= dstBits;
|
||||
dst[pos] = acc >> bits & mask;
|
||||
pos += 1;
|
||||
}
|
||||
});
|
||||
|
||||
if (pad) {
|
||||
if (bits > 0) {
|
||||
// `dstBits - rem.bits` is the number of trailing zero bits needed to be appended
|
||||
// to accumulator bits to get the trailing bit group.
|
||||
dst[pos] = acc << dstBits - bits & mask;
|
||||
}
|
||||
} else {
|
||||
// Truncate the remaining padding, but make sure that it is zeroed and not
|
||||
// overly long first.
|
||||
if (bits >= srcBits) {
|
||||
throw new Error("Excessive padding: ".concat(bits, " (max ").concat(srcBits - 1, " allowed)"));
|
||||
}
|
||||
|
||||
if (acc % (1 << bits) !== 0) {
|
||||
throw new Error('Non-zero padding');
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Encodes a `Uint8Array` buffer as an array with a lesser number of bits per element.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
|
||||
function toBits(src, bits, dst) {
|
||||
if (bits > 8 || bits < 1) {
|
||||
throw new RangeError('Invalid bits per element; 1 to 8 expected');
|
||||
} // `BitArray<8>` is equivalent to `Uint8Array`; unfortunately, Flow
|
||||
// has problems expressing this, so the explicit conversion is performed here.
|
||||
|
||||
|
||||
convert(toBitArrayUnchecked(src), 8, dst, bits, true);
|
||||
return dst;
|
||||
}
|
||||
|
||||
function fromBits(src, bits, dst) {
|
||||
if (bits > 8 || bits < 1) {
|
||||
throw new RangeError('Invalid bits per element; 1 to 8 expected');
|
||||
}
|
||||
|
||||
convert(src, bits, toBitArrayUnchecked(dst), 8, false);
|
||||
return dst;
|
||||
}
|
||||
+217
@@ -0,0 +1,217 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.CHECKSUM_LENGTH = void 0;
|
||||
exports.createChecksum = createChecksum;
|
||||
exports.decode = decode;
|
||||
exports.decodeWithPrefix = decodeWithPrefix;
|
||||
exports.detectCase = detectCase;
|
||||
exports.encode = encode;
|
||||
exports.expandPrefix = expandPrefix;
|
||||
exports.verifyChecksum = verifyChecksum;
|
||||
|
||||
var _bitConverter = require("./bit-converter");
|
||||
|
||||
// Alphabet for Bech32
|
||||
var CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l'; // Checksum constant for Bech32m.
|
||||
|
||||
var BECH32M_CHECKSUM = 0x2bc830a3; // Minimum char code that could be present in the encoded message
|
||||
|
||||
var MIN_CHAR_CODE = 33; // Maximum char code that could be present in the encoded message
|
||||
|
||||
var MAX_CHAR_CODE = 126;
|
||||
var CHECKSUM_LENGTH = 6; // Reverse lookup for characters
|
||||
|
||||
exports.CHECKSUM_LENGTH = CHECKSUM_LENGTH;
|
||||
|
||||
var CHAR_LOOKUP = function () {
|
||||
var lookup = new Map();
|
||||
|
||||
for (var i = 0; i < CHARSET.length; i += 1) {
|
||||
lookup.set(CHARSET[i], i);
|
||||
}
|
||||
|
||||
return lookup;
|
||||
}(); // Poly generators
|
||||
|
||||
|
||||
var GEN = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3];
|
||||
|
||||
function polymod(values) {
|
||||
return values.reduce(function (checksum, value) {
|
||||
var bits = checksum >> 25;
|
||||
var newChecksum = (checksum & 0x1ffffff) << 5 ^ value;
|
||||
return GEN.reduce(function (chk, gen, i) {
|
||||
return (bits >> i & 1) === 0 ? chk : chk ^ gen;
|
||||
}, newChecksum);
|
||||
},
|
||||
/* initial checksum */
|
||||
1);
|
||||
}
|
||||
/**
|
||||
* Expands a prefix into the specified output buffer.
|
||||
*/
|
||||
|
||||
|
||||
function expandPrefix(prefix, outBuffer) {
|
||||
for (var i = 0; i < prefix.length; i += 1) {
|
||||
var code = prefix.charCodeAt(i);
|
||||
outBuffer[i] = code >> 5;
|
||||
outBuffer[i + prefix.length + 1] = code & 31;
|
||||
}
|
||||
|
||||
outBuffer[prefix.length] = 0;
|
||||
}
|
||||
/**
|
||||
* Verifies the checksum for a particular buffer.
|
||||
*/
|
||||
|
||||
|
||||
function verifyChecksum(buffer) {
|
||||
switch (polymod(buffer)) {
|
||||
case 1:
|
||||
return 'bech32';
|
||||
|
||||
case BECH32M_CHECKSUM:
|
||||
return 'bech32m';
|
||||
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Creates a checksum for a buffer and writes it to the last 6 5-bit groups
|
||||
* of the buffer.
|
||||
*/
|
||||
|
||||
|
||||
function createChecksum(buffer, encoding) {
|
||||
var checksumConstant;
|
||||
|
||||
switch (encoding) {
|
||||
case 'bech32':
|
||||
checksumConstant = 1;
|
||||
break;
|
||||
|
||||
case 'bech32m':
|
||||
checksumConstant = BECH32M_CHECKSUM;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw Error("Invalid encoding value: ".concat(encoding, "; expected bech32 or bech32m"));
|
||||
}
|
||||
|
||||
var mod = polymod(buffer) ^ checksumConstant;
|
||||
|
||||
for (var i = 0; i < CHECKSUM_LENGTH; i += 1) {
|
||||
var shift = 5 * (5 - i);
|
||||
buffer[buffer.length - CHECKSUM_LENGTH + i] = mod >> shift & 31;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Encodes an array of 5-bit groups into a string.
|
||||
*
|
||||
* @param {Uint8Array} buffer
|
||||
* @returns {string}
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
|
||||
function encode(buffer) {
|
||||
return buffer.reduce(function (acc, bits) {
|
||||
return acc + CHARSET[bits];
|
||||
}, '');
|
||||
}
|
||||
/**
|
||||
* Decodes a string into an array of 5-bit groups.
|
||||
*
|
||||
* @param {string} message
|
||||
* @param {Uint8Array} [dst]
|
||||
* Optional array to write the output to. If not specified, the array is created.
|
||||
* @returns {Uint8Array}
|
||||
* Array with the result of decoding
|
||||
*
|
||||
* @throws {Error}
|
||||
* if there are characters in `message` not present in the encoding alphabet
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
|
||||
function decode(message, dst) {
|
||||
var realDst = dst || (0, _bitConverter.createBitArray)(message.length);
|
||||
|
||||
for (var i = 0; i < message.length; i += 1) {
|
||||
var idx = CHAR_LOOKUP.get(message[i]);
|
||||
|
||||
if (idx === undefined) {
|
||||
throw new Error("Invalid char in message: ".concat(message[i]));
|
||||
}
|
||||
|
||||
realDst[i] = idx;
|
||||
}
|
||||
|
||||
return realDst;
|
||||
}
|
||||
/**
|
||||
* Decodes a string and a human-readable prefix into an array of 5-bit groups.
|
||||
* The prefix is expanded as specified by Bech32.
|
||||
*
|
||||
* @param {string} prefix
|
||||
* @param {string} message
|
||||
* @returns {Uint8Array}
|
||||
* Array with the result of decoding
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
|
||||
function decodeWithPrefix(prefix, message) {
|
||||
var len = message.length + 2 * prefix.length + 1;
|
||||
var dst = (0, _bitConverter.createBitArray)(len);
|
||||
expandPrefix(prefix, dst.subarray(0, 2 * prefix.length + 1));
|
||||
decode(message, dst.subarray(2 * prefix.length + 1));
|
||||
return dst;
|
||||
}
|
||||
/**
|
||||
* Detects the character case used in `message`. If the message doesn't
|
||||
* contain either lower-case or upper-case chars, returns `null`.
|
||||
*
|
||||
* @param {string} message
|
||||
* @param {string} messageDescription
|
||||
* Human-readable description of the message to put into an error message, should any occur
|
||||
* @returns {'lower'|'upper'|null}
|
||||
* @throws if the message contains both lowercase and uppercase chars,
|
||||
* or contains chars not valid for Bech32(m) encoding
|
||||
*/
|
||||
|
||||
|
||||
function detectCase(message) {
|
||||
var messageDescription = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'message';
|
||||
var hasLowerCase = false;
|
||||
var hasUpperCase = false;
|
||||
|
||||
for (var i = 0; i < message.length; i += 1) {
|
||||
var ord = message.charCodeAt(i); // 3. Allowed chars in the encoding
|
||||
|
||||
if (ord < MIN_CHAR_CODE || ord > MAX_CHAR_CODE) {
|
||||
throw new TypeError("Invalid char in ".concat(messageDescription, ": ").concat(ord, "; ") + "should be in ASCII range ".concat(MIN_CHAR_CODE, "-").concat(MAX_CHAR_CODE));
|
||||
}
|
||||
|
||||
hasUpperCase = hasUpperCase || ord >= 65 && ord <= 90;
|
||||
hasLowerCase = hasLowerCase || ord >= 97 && ord <= 122;
|
||||
}
|
||||
|
||||
if (hasLowerCase && hasUpperCase) {
|
||||
throw new TypeError("Mixed-case ".concat(messageDescription));
|
||||
} else if (hasUpperCase) {
|
||||
return 'upper';
|
||||
} else if (hasLowerCase) {
|
||||
return 'lower';
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+349
@@ -0,0 +1,349 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.BitcoinAddress = void 0;
|
||||
exports.decode = decode;
|
||||
exports.decodeTo5BitArray = decodeTo5BitArray;
|
||||
exports.encode = encode;
|
||||
exports.encode5BitArray = encode5BitArray;
|
||||
exports.from5BitArray = from5BitArray;
|
||||
exports.to5BitArray = to5BitArray;
|
||||
|
||||
var _bitConverter = require("./bit-converter");
|
||||
|
||||
var _encoding = require("./encoding");
|
||||
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||
|
||||
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
||||
|
||||
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
|
||||
|
||||
// Maximum encoded message length
|
||||
var MAX_ENC_LENGTH = 90;
|
||||
|
||||
/**
|
||||
* Converts a Uint8Array into a Uint8Array variant, in which each element
|
||||
* encodes 5 bits of the original byte array.
|
||||
*
|
||||
* @param {Uint8Array} src
|
||||
* Input to convert
|
||||
* @param {?Uint8Array} dst
|
||||
* Optional output buffer. If specified, the sequence of 5-bit chunks will be written there;
|
||||
* if not specified, the output buffer will be created from scratch. The length
|
||||
* of `outBuffer` is not checked.
|
||||
* @returns {Uint8Array}
|
||||
* Output buffer consisting of 5-bit chunks
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
function to5BitArray(src, dst) {
|
||||
var len = Math.ceil(src.length * 8 / 5);
|
||||
var realDst = dst || (0, _bitConverter.createBitArray)(len);
|
||||
return (0, _bitConverter.toBits)(src, 5, realDst);
|
||||
}
|
||||
|
||||
function from5BitArray(src, dst) {
|
||||
var len = Math.floor(src.length * 5 / 8);
|
||||
var realDst = dst || new Uint8Array(len);
|
||||
return (0, _bitConverter.fromBits)(src, 5, realDst);
|
||||
}
|
||||
/**
|
||||
* Encodes binary data into Bech32 encoding.
|
||||
*
|
||||
* The case is preserved: if the prefix is uppercase, then the output will be uppercase
|
||||
* as well; otherwise, the output will be lowercase (including the case when the prefix does
|
||||
* not contain any letters).
|
||||
*
|
||||
* Ordinarily, you may want to use [`encode`](#encode) because it converts
|
||||
* binary data to an array of 5-bit integers automatically.
|
||||
*
|
||||
* @param {string} prefix
|
||||
* Human-readable prefix to place at the beginning of the encoding
|
||||
* @param {Uint8Array} data
|
||||
* Array of 5-bit integers with data to encode
|
||||
* @param {Encoding} encoding
|
||||
* Encoding to use; influences the checksum computation. If not specified,
|
||||
* Bech32 encoding will be used.
|
||||
* @returns {string}
|
||||
* Bech32 encoding of data in the form `<prefix>1<base32 of data><checksum>`
|
||||
* @throws If the prefix is mixed-case or contains chars that are not eligible for Bech32 encoding
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
|
||||
function encode5BitArray(prefix, data) {
|
||||
var _detectCase;
|
||||
|
||||
var encoding = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'bech32';
|
||||
// 1. Allocate buffer for all operations
|
||||
var len = 2 * prefix.length + 1 // expanded prefix
|
||||
+ data.length // five-bit data encoding
|
||||
+ _encoding.CHECKSUM_LENGTH; // checksum
|
||||
|
||||
if (len - prefix.length > MAX_ENC_LENGTH) {
|
||||
throw new Error("Message to be produced is too long (max ".concat(MAX_ENC_LENGTH, " supported)"));
|
||||
}
|
||||
|
||||
var prefixCase = (_detectCase = (0, _encoding.detectCase)(prefix, 'prefix')) !== null && _detectCase !== void 0 ? _detectCase : 'lower';
|
||||
var buffer = (0, _bitConverter.createBitArray)(len); // 2. Expand the human-readable prefix into the beginning of the buffer
|
||||
|
||||
(0, _encoding.expandPrefix)(prefix.toLowerCase(), buffer.subarray(0, 2 * prefix.length + 1)); // 3. Copy `data` into the output
|
||||
|
||||
var dataBuffer = buffer.subarray(2 * prefix.length + 1, buffer.length - _encoding.CHECKSUM_LENGTH);
|
||||
dataBuffer.set(data); // 4. Create the checksum
|
||||
|
||||
(0, _encoding.createChecksum)(buffer, encoding); // 5. Convert into string
|
||||
|
||||
var encoded = (0, _encoding.encode)(buffer.subarray(2 * prefix.length + 1));
|
||||
|
||||
if (prefixCase === 'upper') {
|
||||
encoded = encoded.toUpperCase();
|
||||
}
|
||||
|
||||
return "".concat(prefix, "1").concat(encoded);
|
||||
}
|
||||
/**
|
||||
* Encodes binary data into Bech32 encoding.
|
||||
*
|
||||
* The case is preserved: if the prefix is uppercase, then the output will be uppercase
|
||||
* as well; otherwise, the output will be lowercase (including the case when the prefix does
|
||||
* not contain any letters).
|
||||
*
|
||||
* @param {string} prefix
|
||||
* Human-readable prefix to place at the beginning of the encoding
|
||||
* @param {Uint8Array} data
|
||||
* Binary data to encode
|
||||
* @param {Encoding} encoding
|
||||
* Encoding to use; influences the checksum computation. If not specified,
|
||||
* Bech32 encoding will be used.
|
||||
* @returns {string}
|
||||
* Bech32 encoding of data in the form `<prefix>1<base32 of data><checksum>`
|
||||
* @throws If the prefix is mixed-case or contains chars that are not eligible for Bech32 encoding
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
|
||||
function encode(prefix, data) {
|
||||
var encoding = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'bech32';
|
||||
return encode5BitArray(prefix, to5BitArray(data), encoding);
|
||||
}
|
||||
/**
|
||||
* Decodes data from Bech32 encoding into an array of 5-bit integers.
|
||||
*
|
||||
* Ordinarily, you may want to use [`decode`](#decode) because it automatically
|
||||
* converts the array of 5-bit integers into an ordinary `Uint8Array`.
|
||||
*
|
||||
* @param {string} message
|
||||
* Bech32-encoded message
|
||||
* @returns {DecodeResult<FiveBitArray>}
|
||||
* Decoded object with `prefix` and `data` fields, which contain the human-readable
|
||||
* prefix and the array of 5-bit integers respectively.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
|
||||
function decodeTo5BitArray(message) {
|
||||
// Check preconditions
|
||||
// 1. Message length
|
||||
if (message.length > MAX_ENC_LENGTH) {
|
||||
throw new TypeError("Message too long; max ".concat(MAX_ENC_LENGTH, " expected"));
|
||||
} // 2. Mixed case
|
||||
|
||||
|
||||
(0, _encoding.detectCase)(message); // we don't care about the result, only about checks.
|
||||
|
||||
var lowerCaseMsg = message.toLowerCase(); // 4. Existence of the separator char
|
||||
|
||||
var sepIdx = lowerCaseMsg.lastIndexOf('1');
|
||||
|
||||
if (sepIdx < 0) {
|
||||
throw new Error('No separator char ("1") found');
|
||||
} // 5. Placing of the separator char in the message
|
||||
|
||||
|
||||
if (sepIdx > message.length - _encoding.CHECKSUM_LENGTH - 1) {
|
||||
throw new Error("Data part of the message too short (at least ".concat(_encoding.CHECKSUM_LENGTH, " chars expected)"));
|
||||
}
|
||||
|
||||
var prefix = lowerCaseMsg.substring(0, sepIdx); // Checked within `decodeWithPrefix`:
|
||||
// 6. Invalid chars in the data part of the message
|
||||
|
||||
var bitArray = (0, _encoding.decodeWithPrefix)(prefix, lowerCaseMsg.substring(sepIdx + 1)); // 7. Checksum
|
||||
|
||||
var encoding = (0, _encoding.verifyChecksum)(bitArray);
|
||||
|
||||
if (encoding === undefined) {
|
||||
throw new Error('Invalid checksum');
|
||||
}
|
||||
|
||||
return {
|
||||
prefix: prefix,
|
||||
encoding: encoding,
|
||||
// Strip off the prefix from the front and the checksum from the end
|
||||
data: bitArray.subarray(2 * prefix.length + 1, bitArray.length - _encoding.CHECKSUM_LENGTH)
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Decodes data from Bech32 encoding into an array of 5-bit integers.
|
||||
*
|
||||
* @param {string} message
|
||||
* Bech32-encoded message
|
||||
* @returns {DecodeResult}
|
||||
* Decoded object with `prefix` and `data` fields, which contain the human-readable
|
||||
* prefix and the decoded binary data respectively.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
|
||||
function decode(message) {
|
||||
var _decodeTo5BitArray = decodeTo5BitArray(message),
|
||||
prefix = _decodeTo5BitArray.prefix,
|
||||
encoding = _decodeTo5BitArray.encoding,
|
||||
bitArray = _decodeTo5BitArray.data;
|
||||
|
||||
return {
|
||||
prefix: prefix,
|
||||
encoding: encoding,
|
||||
data: from5BitArray(bitArray)
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Bitcoin address.
|
||||
*/
|
||||
|
||||
|
||||
var BitcoinAddress = /*#__PURE__*/function () {
|
||||
function BitcoinAddress(prefix, scriptVersion, data) {
|
||||
_classCallCheck(this, BitcoinAddress);
|
||||
|
||||
if (prefix !== 'bc' && prefix !== 'tb') {
|
||||
throw new Error('Invalid human-readable prefix, "bc" or "tb" expected');
|
||||
}
|
||||
|
||||
if (scriptVersion < 0 || scriptVersion > 16) {
|
||||
throw new RangeError('Invalid scriptVersion, value in range [0, 16] expected');
|
||||
}
|
||||
|
||||
if (data.length < 2 || data.length > 40) {
|
||||
throw new RangeError('Invalid script length: expected 2 to 40 bytes');
|
||||
}
|
||||
|
||||
if (scriptVersion === 0 && data.length !== 20 && data.length !== 32) {
|
||||
throw new Error('Invalid v0 script length: expected 20 or 32 bytes');
|
||||
}
|
||||
|
||||
this.prefix = prefix;
|
||||
this.scriptVersion = scriptVersion;
|
||||
this.data = data;
|
||||
}
|
||||
/**
|
||||
* Guesses the address type based on its internal structure.
|
||||
*
|
||||
* @returns {void | 'p2wpkh' | 'p2wsh'}
|
||||
*/
|
||||
|
||||
|
||||
_createClass(BitcoinAddress, [{
|
||||
key: "type",
|
||||
value: function type() {
|
||||
if (this.scriptVersion !== 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
switch (this.data.length) {
|
||||
case 20:
|
||||
return 'p2wpkh';
|
||||
|
||||
case 32:
|
||||
return 'p2wsh';
|
||||
// should be unreachable, but it's JS, so you never know
|
||||
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Encodes this address in Bech32 or Bech32m format, depending on the script version.
|
||||
* Version 0 scripts are encoded using original Bech32 encoding as per BIP 173,
|
||||
* while versions 1-16 are encoded using the modified encoding as per BIP 350.
|
||||
*
|
||||
* @returns {string}
|
||||
* Bech32(m)-encoded address
|
||||
*/
|
||||
|
||||
}, {
|
||||
key: "encode",
|
||||
value: function encode() {
|
||||
// Bitcoin addresses use Bech32 in a peculiar way - script version is
|
||||
// not a part of the serialized binary data, but is rather prepended as 5-bit value
|
||||
// before the rest of the script. This necessitates some plumbing here.
|
||||
var len = Math.ceil(this.data.length * 8 / 5);
|
||||
var converted = (0, _bitConverter.createBitArray)(len + 1);
|
||||
converted[0] = this.scriptVersion;
|
||||
to5BitArray(this.data, converted.subarray(1));
|
||||
var encoding = this.scriptVersion === 0 ? 'bech32' : 'bech32m';
|
||||
return encode5BitArray(this.prefix, converted, encoding);
|
||||
}
|
||||
}], [{
|
||||
key: "decode",
|
||||
value:
|
||||
/**
|
||||
* Human-readable prefix. Equal to `'bc'` (for mainnet addresses)
|
||||
* or `'tb'` (for testnet addresses).
|
||||
*/
|
||||
|
||||
/**
|
||||
* Script version. An integer between 0 and 16 (inclusive).
|
||||
*/
|
||||
|
||||
/**
|
||||
* Script data. A byte string with length 2 to 40 (inclusive).
|
||||
*/
|
||||
|
||||
/**
|
||||
* Decodes a Bitcoin address from a Bech32(m) string.
|
||||
* As per BIP 350, the original encoding is expected for version 0 scripts, while
|
||||
* other script versions expect the modified encoding.
|
||||
*
|
||||
* This method does not check whether the address is well-formed;
|
||||
* use `type()` method on returned address to find that out.
|
||||
*
|
||||
* @param {string} message
|
||||
* @returns {BitcoinAddress}
|
||||
*/
|
||||
function decode(message) {
|
||||
var _decodeTo5BitArray2 = decodeTo5BitArray(message),
|
||||
prefix = _decodeTo5BitArray2.prefix,
|
||||
data = _decodeTo5BitArray2.data,
|
||||
encoding = _decodeTo5BitArray2.encoding; // Extra check to satisfy Flow.
|
||||
|
||||
|
||||
if (prefix !== 'bc' && prefix !== 'tb') {
|
||||
throw new Error('Invalid human-readable prefix, "bc" or "tb" expected');
|
||||
}
|
||||
|
||||
var scriptVersion = data[0];
|
||||
|
||||
if (scriptVersion === 0 && encoding !== 'bech32') {
|
||||
throw Error("Unexpected encoding ".concat(encoding, " used for version 0 script"));
|
||||
}
|
||||
|
||||
if (scriptVersion > 0 && encoding !== 'bech32m') {
|
||||
throw Error("Unexpected encoding ".concat(encoding, " used for version ").concat(scriptVersion, " script"));
|
||||
}
|
||||
|
||||
return new this(prefix, scriptVersion, from5BitArray(data.subarray(1)));
|
||||
}
|
||||
}]);
|
||||
|
||||
return BitcoinAddress;
|
||||
}();
|
||||
|
||||
exports.BitcoinAddress = BitcoinAddress;
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
{
|
||||
"name": "bech32-buffer",
|
||||
"version": "0.2.1",
|
||||
"description": "Bech32(m) encoding for byte buffers",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/slowli/bech32-buffer.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/slowli/bech32-buffer/issues"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"main": "lib/index.js",
|
||||
"files": [
|
||||
"lib",
|
||||
"dist",
|
||||
"examples",
|
||||
"index.d.ts",
|
||||
"CHANGELOG.md"
|
||||
],
|
||||
"types": "index.d.ts",
|
||||
"scripts": {
|
||||
"test": "mocha -r @babel/register",
|
||||
"test-browser": "karma start",
|
||||
"cover": "cross-env NODE_ENV=test nyc mocha",
|
||||
"report-cover": "nyc report",
|
||||
"browser": "mkdirp dist && cross-env BABEL_ENV=browser browserify src/index.js -t [ babelify ] --standalone bech32 -o dist/bech32-buffer.min.js",
|
||||
"minify-qr": "cross-env BABEL_ENV=browser browserify node_modules/qrcode-generator/qrcode.js -t [ babelify ] --standalone qrcode -o examples/qrcode.min.js",
|
||||
"compile": "babel src/ -d lib/",
|
||||
"prepare": "npm run compile && npm run browser",
|
||||
"lint": "eslint --ignore-path .gitignore . && flow check",
|
||||
"test-ts": "npm run compile && tsc -p test && node test/types.js"
|
||||
},
|
||||
"keywords": [
|
||||
"bech32",
|
||||
"bech32m",
|
||||
"base32",
|
||||
"bitcoin"
|
||||
],
|
||||
"author": "Alex Ostrovski <ostrovski.alex@gmail.com>",
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.18.6",
|
||||
"@babel/core": "^7.19.1",
|
||||
"@babel/eslint-parser": "^7.19.1",
|
||||
"@babel/preset-env": "^7.19.1",
|
||||
"@babel/preset-flow": "^7.18.6",
|
||||
"@babel/register": "^7.18.6",
|
||||
"@types/chai": "^4.2.22",
|
||||
"babel-plugin-istanbul": "^6.0.0",
|
||||
"babel-preset-minify": "^0.5.1",
|
||||
"babelify": "^10.0.0",
|
||||
"browserify": "^17.0.0",
|
||||
"chai": "^4.3.4",
|
||||
"chai-bytes": "^0.1.2",
|
||||
"cross-env": "^7.0.3",
|
||||
"dirty-chai": "^2.0.1",
|
||||
"eslint": "^8.24.0",
|
||||
"eslint-config-airbnb-base": "^15.0.0",
|
||||
"eslint-plugin-import": "^2.24.2",
|
||||
"flow-bin": "^0.187.1",
|
||||
"karma": "^6.4.0",
|
||||
"karma-browserify": "^8.0.0",
|
||||
"karma-chrome-launcher": "^3.1.0",
|
||||
"karma-firefox-launcher": "^2.1.1",
|
||||
"karma-mocha": "^2.0.1",
|
||||
"karma-mocha-reporter": "^2.2.3",
|
||||
"mkdirp": "^1.0.4",
|
||||
"mocha": "^10.0.0",
|
||||
"nyc": "^15.1.0",
|
||||
"qrcode-generator": "^1.4.4",
|
||||
"typescript": "^4.8.2"
|
||||
},
|
||||
"nyc": {
|
||||
"require": [
|
||||
"@babel/register"
|
||||
],
|
||||
"exclude": [
|
||||
"lib",
|
||||
"test"
|
||||
],
|
||||
"sourceMap": false,
|
||||
"instrument": false
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user