@bsv/sdk 1.1.1 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/package.json +1 -1
- package/package.json +1 -1
- package/src/transaction/__tests/Transaction.test.ts +2 -2
- package/docs/concepts/42.md +0 -35
- package/docs/concepts/BEEF.md +0 -38
- package/docs/concepts/CHAIN_SPV.md +0 -38
- package/docs/concepts/FEE.md +0 -35
- package/docs/concepts/HASHES.md +0 -19
- package/docs/concepts/HOW_TX.md +0 -60
- package/docs/concepts/OP.md +0 -38
- package/docs/concepts/README.md +0 -14
- package/docs/concepts/TEMPLATES.md +0 -42
- package/docs/concepts/TX_SIG.md +0 -34
- package/docs/concepts/TX_VALID.md +0 -35
- package/docs/examples/EXAMPLE_BUILDING_CUSTOM_TX_BROADCASTER.md +0 -91
- package/docs/examples/EXAMPLE_COMPLEX_TX.md +0 -162
- package/docs/examples/EXAMPLE_ECIES.md +0 -37
- package/docs/examples/EXAMPLE_ENCRYPT_DECRYPT_MESSAGE.md +0 -52
- package/docs/examples/EXAMPLE_FEE_MODELING.md +0 -199
- package/docs/examples/EXAMPLE_HD_WALLETS.md +0 -71
- package/docs/examples/EXAMPLE_MESSAGE_SIGNING.md +0 -63
- package/docs/examples/EXAMPLE_SCRIPT_TEMPLATES.md +0 -170
- package/docs/examples/EXAMPLE_SIMPLE_TX.md +0 -145
- package/docs/examples/EXAMPLE_TYPE_42.md +0 -108
- package/docs/examples/EXAMPLE_UTXOS_TX.md +0 -85
- package/docs/examples/EXAMPLE_VERIFYING_BEEF.md +0 -62
- package/docs/examples/EXAMPLE_VERIFYING_ROOTS.md +0 -97
- package/docs/examples/EXAMPLE_VERIFYING_SPENDS.md +0 -69
- package/docs/examples/GETTING_STARTED_NODE_CJS.md +0 -71
- package/docs/examples/GETTING_STARTED_REACT.md +0 -119
- package/docs/examples/README.md +0 -19
- package/docs/low-level/AES_SYMMETRIC_ENCRYPTION.md +0 -40
- package/docs/low-level/ECDH.md +0 -64
- package/docs/low-level/NUMBERS_POINTS.md +0 -116
- package/docs/low-level/README.md +0 -13
- package/docs/low-level/TX_SIG.md +0 -132
- package/docs/low-level/TYPE_42.md +0 -53
- package/docs/low-level/USING_ECDSA.md +0 -30
- package/docs/low-level/USING_HASHES_AND_HMACS.md +0 -79
- package/docs/low-level/USING_PRIVATE_PUBLIC_KEYS.md +0 -70
- package/docs/low-level/USING_SCRIPTS.md +0 -71
- package/docs/low-level/images/symmetric_encryption_diagram.png +0 -0
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
# Example: Verifying Spends with Script Intrepreter
|
|
2
|
-
|
|
3
|
-
The SDK comes with a script interpreter that allows you to verify the chain of spends within Bitcoin. When coins are spent from one transaction to another, the process is carried out between a particular output of the source transaction and a particular input of the spending transaction. The `Spend` class sets up the necessary contextual information for this process, and then evaluates the scripts to determine if the transfer is legitimate.
|
|
4
|
-
|
|
5
|
-
This guide will walk you through the verification of a real spend, with real data. You can apply this code to your own transactions to ensure the transfer of coins from one state into the next is legitimate.
|
|
6
|
-
|
|
7
|
-
## Pre-requisites
|
|
8
|
-
|
|
9
|
-
We will need two transactions: a source transaction and a spending transaction, in order to set up the `Spend` context in which the transfer of coins occurs between them. When you construct an instance of the `Spend` class, you'll need to provide this information in the correct format. In a new file, let's set up som basic things we'll need:
|
|
10
|
-
|
|
11
|
-
```typescript
|
|
12
|
-
import { Spend, LockingScript, UnlockingScript } from '@bsv/sdk'
|
|
13
|
-
|
|
14
|
-
const spend = new Spend({
|
|
15
|
-
|
|
16
|
-
// Replace with the TXID of the transaction where you are spending from
|
|
17
|
-
sourceTXID: '0000000000000000000000000000000000000000000000000000000000000000',
|
|
18
|
-
|
|
19
|
-
// Replace with the output index you are redeeming
|
|
20
|
-
sourceOutputIndex: 0,
|
|
21
|
-
|
|
22
|
-
// Replace with the number of satoshis in the output you are redeeming
|
|
23
|
-
sourceSatoshis: 1,
|
|
24
|
-
|
|
25
|
-
// Replace with the locking script you are spending
|
|
26
|
-
lockingScript: LockingScript.fromASM('OP_3 OP_ADD OP_7 OP_EQUAL'),
|
|
27
|
-
|
|
28
|
-
// Replace with the version of the new spending transaction
|
|
29
|
-
transactionVersion: 1,
|
|
30
|
-
|
|
31
|
-
// Other inputs from the spending transaction that are needed for verification.
|
|
32
|
-
// The SIGHASH flags used in signatures may not require this (if SIGHASH_ANYONECANPAY was used).
|
|
33
|
-
// This is an ordered array of TransactionInputs with the input whose script we're currently evaluating missing.
|
|
34
|
-
otherInputs: [],
|
|
35
|
-
|
|
36
|
-
// TransactionOutputs from the spending transaction that are needed for verification.
|
|
37
|
-
// The SIGHASH flags used in signatures may nnt require this (if SIGHASH_NONE was used).
|
|
38
|
-
// If SIGHASH_SINGLE is used, it's possible for this to be a sparse array, with only the index corresponding to
|
|
39
|
-
// the inputIndex populated.
|
|
40
|
-
outputs: [],
|
|
41
|
-
|
|
42
|
-
// This is the index of the input whose script we are currently evaluating.
|
|
43
|
-
inputIndex: 0,
|
|
44
|
-
|
|
45
|
-
// This is the unlocking script that we are evaluating, to see if it unlocks the source output.
|
|
46
|
-
unlockingScript: UnlockingScript.fromASM('OP_4'),
|
|
47
|
-
|
|
48
|
-
// This is the sequence number of the input whose script we are currently evaluating.
|
|
49
|
-
inputSequence: 0xffffffff,
|
|
50
|
-
|
|
51
|
-
// This is the lock time of the spending transaction.
|
|
52
|
-
lockTime: 0
|
|
53
|
-
})
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
Once you've provided the context and constructed the Spend, you should have a new spend instance ready for verification.
|
|
57
|
-
|
|
58
|
-
## Validating the Spend
|
|
59
|
-
|
|
60
|
-
You can use the `validate()` method to run the scripts and validate the spend, as follows:
|
|
61
|
-
|
|
62
|
-
```typescript
|
|
63
|
-
const validated = spend.validate()
|
|
64
|
-
// console.log(validated) => true
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
The result will be a boolean indicating the result of the script. If there is an error thrown, or if the boolean is false, the script is not valid. If the boolean is true, the spend is considered valid.
|
|
68
|
-
|
|
69
|
-
Errors from the spend will contain useful information, such as the specific opcode and context in which the error occurred (in either the locking or unlocking script).
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
# Getting Started with BSV SDK in NodeJS (CommonJS)
|
|
2
|
-
|
|
3
|
-
Welcome to the BSV SDK! This guide is tailored for developers working in a NodeJS environment, specifically those who are using the CommonJS module system. We'll walk you through the installation process and show you how to get started with creating and signing a Bitcoin SV transaction using the SDK. Whether you're building on BSV for the first time or transitioning an existing project to use the SDK, this guide is for you.
|
|
4
|
-
|
|
5
|
-
## Prerequisites
|
|
6
|
-
|
|
7
|
-
Before we begin, make sure you have Node.js installed on your system. You can download and install Node.js from [nodejs.org](https://nodejs.org/). This guide assumes you have basic knowledge of JavaScript and the Node.js environment.
|
|
8
|
-
|
|
9
|
-
## Installation
|
|
10
|
-
|
|
11
|
-
First, you'll need to install the BSV SDK package in your project. Open your terminal, navigate to your project directory, and run the following command:
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
npm install @bsv/sdk
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
This command installs the BSV SDK in your project, making it ready for use. There are no external runtime dependencies.
|
|
18
|
-
|
|
19
|
-
## Requiring the SDK
|
|
20
|
-
|
|
21
|
-
To use the BSV SDK in a NodeJS project with CommonJS, you'll import modules using the `require` syntax. Here's how you set up a basic script to use the BSV SDK:
|
|
22
|
-
|
|
23
|
-
1. Create a new JavaScript file in your project. For example, `index.js`.
|
|
24
|
-
2. At the top of your file, require the SDK modules you plan to use. For instance:
|
|
25
|
-
|
|
26
|
-
```javascript
|
|
27
|
-
const { PrivateKey, P2PKH, Transaction, ARC } = require('@bsv/sdk');
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
## Creating and Signing a Transaction
|
|
31
|
-
|
|
32
|
-
Now, let's create and sign a transaction. We'll follow the example provided in the README. This example demonstrates how to create a transaction from a source to a recipient, including calculating fees, signing the transaction, and broadcasting it to ARC.
|
|
33
|
-
|
|
34
|
-
Copy and paste the following code into your `index.js` file below your `require` statement:
|
|
35
|
-
|
|
36
|
-
```javascript
|
|
37
|
-
const privKey = PrivateKey.fromWif('...')
|
|
38
|
-
|
|
39
|
-
const sourceTransaction = Transaction.fromHex('...')
|
|
40
|
-
|
|
41
|
-
const version = 1
|
|
42
|
-
const input = {
|
|
43
|
-
sourceTransaction,
|
|
44
|
-
sourceOutputIndex: 0,
|
|
45
|
-
unlockingScriptTemplate: new P2PKH().unlock(privKey),
|
|
46
|
-
}
|
|
47
|
-
const output = {
|
|
48
|
-
lockingScript: new P2PKH().lock(privKey.toPublicKey().toHash()),
|
|
49
|
-
change: true
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const tx = new Transaction(version, [input], [output])
|
|
53
|
-
await tx.fee()
|
|
54
|
-
await tx.sign()
|
|
55
|
-
|
|
56
|
-
await tx.broadcast()
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
This script demonstrates the entire process of creating a transaction, from initializing keys to signing and broadcast. When you run this script using Node.js (replacing the source transaction, private key, and ARC credentials), the spend will be signed and broadcast to the BSV network.
|
|
60
|
-
|
|
61
|
-
## Running Your Script
|
|
62
|
-
|
|
63
|
-
To run your script, simply execute the following command in your terminal:
|
|
64
|
-
|
|
65
|
-
```bash
|
|
66
|
-
node index.js
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
## Conclusion
|
|
70
|
-
|
|
71
|
-
Congratulations! You've successfully installed the BSV SDK in your NodeJS project and created a signed transaction. This guide covered the basics to get you started, but the BSV SDK is capable of much more. Explore the SDK documentation for detailed information on all the features and functionalities available to build scalable applications with the BSV blockchain.
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
Getting Started with BSV SDK using React and TypeScript
|
|
2
|
-
=======================================================
|
|
3
|
-
|
|
4
|
-
Welcome to the guide! This guide is designed for developers working in a React environment using TypeScript. We'll walk through the installation process and show you how to create and broadcast a Bitcoin SV transaction using the BSV SDK. Whether you're freshly starting on BSV or transitioning an existing project to use the SDK, this would be your go-to guide.
|
|
5
|
-
|
|
6
|
-
Prerequisites
|
|
7
|
-
-------------
|
|
8
|
-
|
|
9
|
-
Ensure that you have Node.js installed on your system. You can download and install Node.js from [nodejs.org](https://nodejs.org/). Basic knowledge of JavaScript, React and TypeScript is recommended for this guide.
|
|
10
|
-
|
|
11
|
-
Setting Up
|
|
12
|
-
----------
|
|
13
|
-
|
|
14
|
-
Begin by creating a new project using Create React App with the TypeScript template:
|
|
15
|
-
|
|
16
|
-
```bash
|
|
17
|
-
npx create-react-app my-bsv-app --template typescript
|
|
18
|
-
cd my-bsv-app
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
Next, install the BSV SDK package in your project:
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
npm install @bsv/sdk
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
Writing the Component
|
|
28
|
-
---------------------
|
|
29
|
-
|
|
30
|
-
Let's now create a Button component that builds and broadcasts a transaction when clicked.
|
|
31
|
-
|
|
32
|
-
1. Create a new file in your project, such as `src/components/BsvButton.tsx`.
|
|
33
|
-
2. At the top of your component file, import the necessary modules from the BSV SDK:
|
|
34
|
-
|
|
35
|
-
```
|
|
36
|
-
import React from 'react';
|
|
37
|
-
import { PrivateKey, Transaction, ARC, P2PKH } from '@bsv/sdk';
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
3. Define a new component function, `BsvButton`, that handles the creation and broadcast of a transaction upon a button click:
|
|
41
|
-
|
|
42
|
-
```typescript
|
|
43
|
-
const BsvButton: React.FC = () => {
|
|
44
|
-
const handleClick = async () => {
|
|
45
|
-
const privKey = PrivateKey.fromWif('...')
|
|
46
|
-
const sourceTransaction = Transaction.fromHex('...') // your source transaction goes here
|
|
47
|
-
|
|
48
|
-
const version = 1
|
|
49
|
-
const input = {
|
|
50
|
-
sourceTransaction,
|
|
51
|
-
sourceOutputIndex: 0,
|
|
52
|
-
unlockingScriptTemplate: new P2PKH().unlock(privKey),
|
|
53
|
-
}
|
|
54
|
-
const output = {
|
|
55
|
-
lockingScript: new P2PKH().lock(privKey.toPublicKey().toHash()),
|
|
56
|
-
change: true
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const tx = new Transaction(version, [input], [output])
|
|
60
|
-
await tx.fee()
|
|
61
|
-
await tx.sign()
|
|
62
|
-
|
|
63
|
-
await tx.broadcast()
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return (
|
|
67
|
-
<button onClick={handleClick}>
|
|
68
|
-
Create Transaction
|
|
69
|
-
</button>
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
4. Finally, export the `BsvButton` component:
|
|
75
|
-
|
|
76
|
-
```typescript
|
|
77
|
-
export default BsvButton;
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
Integrating into Application
|
|
81
|
-
----------------------------
|
|
82
|
-
|
|
83
|
-
Now, let's integrate our `BsvButton` component into our app:
|
|
84
|
-
|
|
85
|
-
1. Open `src/App.tsx`.
|
|
86
|
-
2. Delete all of its content and replace it with the following:
|
|
87
|
-
|
|
88
|
-
```typescript
|
|
89
|
-
import React from 'react';
|
|
90
|
-
import BsvButton from './components/BsvButton';
|
|
91
|
-
|
|
92
|
-
function App() {
|
|
93
|
-
return (
|
|
94
|
-
<div className="App">
|
|
95
|
-
<header className="App-header">
|
|
96
|
-
<BsvButton />
|
|
97
|
-
</header>
|
|
98
|
-
</div>
|
|
99
|
-
);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
export default App;
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
Running the App
|
|
106
|
-
---------------
|
|
107
|
-
|
|
108
|
-
To run your application, just type the following command in your terminal:
|
|
109
|
-
|
|
110
|
-
```bash
|
|
111
|
-
npm run start
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
Now when you click the button, a transaction will be created, signed, and broadcast to the BSV network.
|
|
115
|
-
|
|
116
|
-
Conclusion
|
|
117
|
-
----------
|
|
118
|
-
|
|
119
|
-
Congratulations! You've successfully integrated the BSV SDK into your TypeScript & React application and created a button which broadcasts a bitcoin transaction on click. This guide covered the basic steps needed to get you started, but the BSV SDK can do a lot more. Explore the SDK documentation to dive deep into all the features and functionalities available to build scalable applications on the BSV blockchain.
|
package/docs/examples/README.md
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# Examples
|
|
2
|
-
|
|
3
|
-
Here, you will find documentation for common example usages of the library.
|
|
4
|
-
|
|
5
|
-
- [Getting Started (Node, CommonJS)](./GETTING_STARTED_NODE_CJS.md)
|
|
6
|
-
- [Getting Started (React)](./GETTING_STARTED_REACT.md)
|
|
7
|
-
- [Example: Creating a Simple Transaction](EXAMPLE_SIMPLE_TX.md)
|
|
8
|
-
- [Example: Verifying a BEEF Structure](EXAMPLE_VERIFYING_BEEF.md)
|
|
9
|
-
- [Example: Creating Transactions with Inputs, Outputs and Templates](EXAMPLE_COMPLEX_TX.md)
|
|
10
|
-
- [Example: Creating the R-puzzle Script Template](EXAMPLE_SCRIPT_TEMPLATES.md)
|
|
11
|
-
- [Example: Message Encryption and Decryption](EXAMPLE_ENCRYPT_DECRYPT_MESSAGE.md)
|
|
12
|
-
- [Example: Message Signing](EXAMPLE_MESSAGE_SIGNING.md)
|
|
13
|
-
- [Example: Building a Custom Transaction Broadcast Client](EXAMPLE_BUILDING_CUSTOM_TX_BROADCASTER.md)
|
|
14
|
-
- [Example: Verifying Spends with Script Intrepreter](EXAMPLE_VERIFYING_SPENDS.md)
|
|
15
|
-
- [Example: BIP32 Key Derivation with HD Wallets](EXAMPLE_HD_WALLETS.md)
|
|
16
|
-
- [Example: Using Type 42 Key Derivation for Bitcoin Wallet Management](EXAMPLE_TYPE_42.md)
|
|
17
|
-
- [Example: Creating a Custom Transaction Fee Model](EXAMPLE_FEE_MODELING.md)
|
|
18
|
-
- [Example: Building a Pulse Block Headers Client](EXAMPLE_PULSE_HEADERS.md)
|
|
19
|
-
- [Example: Using ECIES Encryption](EXAMPLE_ECIES.md)
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
# Using AES for the Symmetric Encryption of Data
|
|
2
|
-
|
|
3
|
-
The goal of this tutorial is to explore the encryption of data using symmetric keys with the Advanced Encryption Standard (AES). We will make use of the functions provided by the SDK in order to encrypt data with a key, and then decrypt it again.
|
|
4
|
-
|
|
5
|
-
<img src="./images/symmetric_encryption_diagram.png" width="600" alt=""/>
|
|
6
|
-
|
|
7
|
-
If you would like to learn more about AES encryption, here are some general resources that may help:
|
|
8
|
-
|
|
9
|
-
- [AES - Wiki](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard)
|
|
10
|
-
- [GCM - Wiki](https://en.wikipedia.org/wiki/Galois/Counter_Mode)
|
|
11
|
-
|
|
12
|
-
The library supports GCM, a specific counter mode of AES that works well in many applications. The library also handles initialization vectors, automatically prepending them to ciphertext and removing them in the decryption process. Now that you know the basics, let's get started!
|
|
13
|
-
|
|
14
|
-
## Getting Started
|
|
15
|
-
|
|
16
|
-
First, let's import the `SymmetricKey` class from the SDK, and we'll also use `Utils` for human-readable messages.
|
|
17
|
-
|
|
18
|
-
```ts
|
|
19
|
-
import { SymmetricKey, Utils } from '@bsv/sdk'
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
Next, we wil define the keys to be used and the data to encrypt. They `.encrypt()` method expects a parameter of type `number[]` so we will use the Utils `toArray` function to convert the UTF8 message to the correct type.
|
|
23
|
-
|
|
24
|
-
```ts
|
|
25
|
-
const symmetricKey = SymmetricKey.fromRandom()
|
|
26
|
-
const messageToEncrypt = 'Hello Alice, this is Bob!'
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
### Encrypting and Decrypting
|
|
30
|
-
|
|
31
|
-
When you encrypt a message, an initialization vector is prepended to the message to prevent potential key re-use attacks. Conversely, when decrypting, the initialization vector that was initially added is spliced out and used in the AES-GSM decryption processes.
|
|
32
|
-
|
|
33
|
-
We will use the `encrypt` and `decrypt` methods of the SymmetricKey class to transform the message.
|
|
34
|
-
|
|
35
|
-
```ts
|
|
36
|
-
const encryptedMessage = SymmetricKey.encrypt(messageToEncrypt)
|
|
37
|
-
const plaintext = SymmetricKey.decrypt(encryptedMessage, 'utf8')
|
|
38
|
-
// console.log(plaintext) --> 'Hello Alice, this is Bob!'
|
|
39
|
-
|
|
40
|
-
This is just a basic demonstration of symmetric encryption/decryption using the BSV SDK, however the possibilities of what you can do are endless once you understand these fundamentals.
|
package/docs/low-level/ECDH.md
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
# ECDH (Elliptic Curve Diffie-Hallman)
|
|
2
|
-
|
|
3
|
-
The process of ECDH enables two parties to agree on a common shared secret. Then, messages can be exchanged using this common secret. This guide provides a conceptual example, then delves into a practical example.
|
|
4
|
-
|
|
5
|
-
## The Setup
|
|
6
|
-
|
|
7
|
-
Each party randomly generates a private key, then sends the associated public key to the other party. In order to compute the public key from the private key, they multiply the private key by a generator point on an elliptic curve, using point multiplication.
|
|
8
|
-
|
|
9
|
-
```
|
|
10
|
-
Alice = random()
|
|
11
|
-
AlicePub = Alice * GeneratorPoint
|
|
12
|
-
Bob = random()
|
|
13
|
-
BobPub = Bob * GeneratorPoint
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
Then, the parties use Elliptic Curve Diffie-Hallman (ECDH) to derive a shared secret. The way this works is that the first party, let's call her Alice, uses her private key combined with the second user's (call him Bob) public key to compute a secret. Meanwhile, Bob can use his private key and Alice's public key to compute the same secret:
|
|
17
|
-
|
|
18
|
-
```
|
|
19
|
-
AliceSecret = Alice * BobPub
|
|
20
|
-
BobSecret = Bob * AlicePub
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
These secrets are equal because:
|
|
24
|
-
|
|
25
|
-
```
|
|
26
|
-
AlicePub (Alice * GeneratorPoint) * Bob = BobPub (Bob * GeneratorPoint) * Alice
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
Put more simply:
|
|
30
|
-
|
|
31
|
-
```
|
|
32
|
-
Alice * Bob * GeneratorPoint
|
|
33
|
-
Bob * Alice * GeneratorPoint
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
Because multiplication is easy but division is practically impossible in elliptic curve math, the system is secure even though both parties generate the same shared secret. Also, no third party can generate the shared secret. Alice can't learn Bob's private key and Bob can't learn Alice's private key.
|
|
37
|
-
|
|
38
|
-
## Practical Demonstration
|
|
39
|
-
|
|
40
|
-
The BSV SDK enables the computation of a shared secret as follows:
|
|
41
|
-
|
|
42
|
-
```ts
|
|
43
|
-
import { PrivateKey } from '@bsv/sdk'
|
|
44
|
-
|
|
45
|
-
const alice = PrivateKey.fromRandom()
|
|
46
|
-
const alicePub = alice.toPublicKey()
|
|
47
|
-
|
|
48
|
-
const bob = PrivateKey.fromRandom()
|
|
49
|
-
const bobPub = bob.toPublicKey()
|
|
50
|
-
|
|
51
|
-
// Alice derives the secret with Bob's public key
|
|
52
|
-
// She does not need his private key.
|
|
53
|
-
const aliceSecret = alice.deriveSharedSecret(bobPub).toString()
|
|
54
|
-
|
|
55
|
-
// Bob derives the secret with Alice's public key
|
|
56
|
-
// He does not need her private key.
|
|
57
|
-
const bobSecret = bob.deriveSharedSecret(alicePub).toString()
|
|
58
|
-
|
|
59
|
-
// We've converted these secrets into hex and now we can see if they are equal
|
|
60
|
-
console.log(aliceSecret === bobSecret)
|
|
61
|
-
// true
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
You can then use the secret to encrypt data or otherwise communicate securely between the two parties.
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
# Numbers and Points
|
|
2
|
-
|
|
3
|
-
At the base of both symmetric and asymmetric algorithms lie the concept of numbers, large enough to represent a key that can be used in various operations. Further, asymmetric systems based in elliptic curves rely on a way to represent the points on these curves. Both numbers and points have various mathematical operations that enable these algorithms, and this guide will provide an overview of the SDK's implementations of each.
|
|
4
|
-
|
|
5
|
-
## Big Numbers
|
|
6
|
-
|
|
7
|
-
In JavaScript and TypeScript, natural numbers are limited to 53 bits of precision. This means that it's not possible to have numbers larger than 2 to the power of 53. However, the keys used in secure algorithms, such as those used in Bitcoin, are on the order of 256 bits in length. This means that we need a specialized representation of these large numbers, and the necessary mathematical operations on them.
|
|
8
|
-
|
|
9
|
-
The SDK's `BigNumber` class provides this capability. Here's a simple example:
|
|
10
|
-
|
|
11
|
-
```ts
|
|
12
|
-
import { BigNumber, Random } from '@bsv/sdk'
|
|
13
|
-
|
|
14
|
-
const bn1 = new BigNumber(7)
|
|
15
|
-
const bn2 = new BigNumber(4)
|
|
16
|
-
const bn3 = bn1.add(bn2)
|
|
17
|
-
console.log(bn3.toNumber())
|
|
18
|
-
// 11
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
Here, we're creating two "big" numbers and adding them together. These numbers aren't actually very large, but they illustrate the point. We can use larger numbers, generating them randomly, and convert them into hex:
|
|
22
|
-
|
|
23
|
-
```ts
|
|
24
|
-
// Generate a BigNumber from 32 random bytes (256 bits, like Bitcoin private keys)
|
|
25
|
-
const bn1 = new BigNumber(Random(32))
|
|
26
|
-
console.log(bn1.toHex())
|
|
27
|
-
// 31af7e86775fbbab9b8618eaad8d9782251cc67ff7366d7f59aee5455119c44f
|
|
28
|
-
|
|
29
|
-
// Multiply this number by 65536
|
|
30
|
-
const bn2 = bn1.muln(65536)
|
|
31
|
-
|
|
32
|
-
// Printed on the screen, this should be two bytes shfted over in hex
|
|
33
|
-
// This amounts to four extra zeroes at the end
|
|
34
|
-
console.log(bn2.toHex())
|
|
35
|
-
// 31af7e86775fbbab9b8618eaad8d9782251cc67ff7366d7f59aee5455119c44f0000
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
It's also possible to do many othe operations, like subtraction, division, and conversion into various formats:
|
|
39
|
-
|
|
40
|
-
```ts
|
|
41
|
-
const bn1 = new BigNumber(21)
|
|
42
|
-
const bn2 = new BigNumber(5)
|
|
43
|
-
|
|
44
|
-
console.log(bn1.sub(bn2).toNumber()) // 16
|
|
45
|
-
|
|
46
|
-
// Note that decimal numbers are not supported.
|
|
47
|
-
// For division, we are expecting a whole number.
|
|
48
|
-
console.log(bn1.div(bn2).toNumber()) // 4
|
|
49
|
-
|
|
50
|
-
// We can get the remainder with the modulous function.
|
|
51
|
-
console.log(bn1.mod(bn2).toNumber()) // 1
|
|
52
|
-
|
|
53
|
-
// BigNumbers can be imported and exported to various formats
|
|
54
|
-
const bn3 = new BigNumber(Random(6))
|
|
55
|
-
console.log(bn3.toHex()) // e09bcaeda91c
|
|
56
|
-
console.log(bn3.toBitArray()) // binary value
|
|
57
|
-
console.log(bn3.toArray()) // [ 224, 155, 202, 237, 169, 28 ]
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
Private keys and symmetric keys are just an extension of the `BigNumber` class, enabling access to various specialized algorithms like digital signatures and encryption, respectively. When considering public keys, we need to go further and talk about elliptic curves and points.
|
|
61
|
-
|
|
62
|
-
## Curves and Points
|
|
63
|
-
|
|
64
|
-
An elliptic curve has various properties and mathematical primitives. The curve used in Bitcoin is called `secp256k1`, and the SDK provides an implementation in the `Curve` class. In order to get started using a curve, you will need the generator point. The generator point can be multiplied with a private key in order to get a corresponding public key.
|
|
65
|
-
|
|
66
|
-
Let's start by importing the `Curve` class, generating a private key (a random number), and multiplying it by the generator point (called `G`) to get a point representing the corresponding public key:
|
|
67
|
-
|
|
68
|
-
```ts
|
|
69
|
-
import { Curve, BigNumber, Random } from '@bsv/sdk'
|
|
70
|
-
|
|
71
|
-
const curve = new Curve()
|
|
72
|
-
const privateKey = new BigNumber(Random(32))
|
|
73
|
-
const G = curve.g
|
|
74
|
-
const publicPoint = G.mul(privateKey)
|
|
75
|
-
console.log(`Private key: ${privateKey.toHex()}`)
|
|
76
|
-
// Private key: fd026136e9803295655bb342553ab8ad3260bd5e1a73ca86a7a92de81d9cee78
|
|
77
|
-
|
|
78
|
-
console.log(`Public key: ${publicPoint.toString()}`)
|
|
79
|
-
// Public key: 028908061925dac16b651e814995cba3dac8acbf8cf1bade40920a31a1611e6970
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
Now, the public key can be shared with the world, and the private key remains secure. This is because the process of point multiplication is impractical to reverse (there is no "point division" or "dividing by the generator point").
|
|
83
|
-
|
|
84
|
-
## Point Addition and Multiplication
|
|
85
|
-
|
|
86
|
-
Points are represented (wrapped) at a higher level by the SDK's `PublicKey` class, which simply adds some extra helper functions. Conversely, the SDK wraps Big Numbers with the `PrivateKey` class to extend their functionality.
|
|
87
|
-
|
|
88
|
-
When dealing with points, we can perform other useful operations. For example, the [type 42 scheme](./TYPE_42.md) talks about adding one point to another. We will demonstrate, and then we'll go further to show the multiplication of a point by a number, to show the process behind [ECDH](./ECDH.md):
|
|
89
|
-
|
|
90
|
-
```ts
|
|
91
|
-
import { Curve, BigNumber, Random } from '@bsv/sdk'
|
|
92
|
-
|
|
93
|
-
const curve = new Curve()
|
|
94
|
-
const G = curve.g
|
|
95
|
-
|
|
96
|
-
const key1 = new BigNumber(Random(32))
|
|
97
|
-
const pubpoint1 = G.mul(key1)
|
|
98
|
-
|
|
99
|
-
const key2 = new BigNumber(Random(32))
|
|
100
|
-
const pubpoint2 = G.mul(key2)
|
|
101
|
-
|
|
102
|
-
// two points can be added together
|
|
103
|
-
const added1and2 = pubpoint1.add(pubpoint2)
|
|
104
|
-
console.log(`${pubpoint1.toString()} + ${pubpoint2.toString()} = ${added1and2.toString()}`)
|
|
105
|
-
// 0280879ebda787e241ecaf27e29b0539e7a1d3895ee6c881b6e5b3c4468f379bd1 + 03ffd671622049d8f6ccb11f17dcf88fcd43d0916d9698b3d338bb9360e24d48ec = 0254b1a5132c040688f7b85a4ef56cc968c87552222d5ebeefca13f65b88790eb1
|
|
106
|
-
|
|
107
|
-
// (A * BG) = (B * AG) (this demonstrates why ECDH works)
|
|
108
|
-
const mul1and2 = pubpoint1.mul(key2)
|
|
109
|
-
console.log(`${pubpoint1.toString()} * ${key2.toHex()} = ${mul1and2.toString()}`)
|
|
110
|
-
const mul2and1 = pubpoint2.mul(key1)
|
|
111
|
-
console.log(`${pubpoint2.toString()} * ${key1.toHex()} = ${mul2and1.toString()}`)
|
|
112
|
-
// 0280879ebda787e241ecaf27e29b0539e7a1d3895ee6c881b6e5b3c4468f379bd1 * 695a2ce8dbf5f1889eac7a5c3711d01e3b863df8ef530b9319924a354e5c20dd = 03f3c29024e3ada33a5ea2258544c63108a8c060378dcd5a69ef69851a8a25ad1f
|
|
113
|
-
// 03ffd671622049d8f6ccb11f17dcf88fcd43d0916d9698b3d338bb9360e24d48ec * b329e4c294d2b04b3d6907492a0e471255d93d06472fcb2b1228d6f364c25940 = 03f3c29024e3ada33a5ea2258544c63108a8c060378dcd5a69ef69851a8a25ad1f
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
These lower-level constructs are useful when dealing with key derivation schemes, or when you need to perform specific mathematical operations on public, private or symmetric keys. Keep in mind that because public keys are an extension of `Point`, and because private and symmetric keys extend `BigNumber`, all of the low-level tools from these powerful base classes are always available for your use.
|
package/docs/low-level/README.md
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
# Low-Level Constructs
|
|
2
|
-
|
|
3
|
-
These documents cover the lower level functionalities of the BSV library. Generally, these are more advanced use-cases:
|
|
4
|
-
|
|
5
|
-
- [Numbers and Points](NUMBERS_POINTS.md)
|
|
6
|
-
- [Public and Private Keys](USING_PRIVATE_PUBLIC_KEYS.md)
|
|
7
|
-
- [AES Symmetric Encryption](AES_SYMMETRIC_ENCRYPTION.md)
|
|
8
|
-
- [ECDSA Digital Signature Algorithm](USING_ECDSA.md)
|
|
9
|
-
- [ECDH (Elliptic Curve Diffie-Hallman)](ECDH.md)
|
|
10
|
-
- [Hashes and HMAC Functions](USING_HASHES_AND_HMAC.md)
|
|
11
|
-
- [Type 42 Derivation](TYPE_42.md)
|
|
12
|
-
- [Transaction Signatures](TX_SIG.md)
|
|
13
|
-
- [Serializing and Deserializing Scripts](USING_SCRIPTS.md)
|
package/docs/low-level/TX_SIG.md
DELETED
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
A Transaction Signature serves as strong evidence that the transaction has been authorized by the holder of the private key corresponding to an associated public key. This document provides information about the structure, serialization and pre-image format for these signatures.
|
|
2
|
-
|
|
3
|
-
### Data Structure
|
|
4
|
-
|
|
5
|
-
The `TransactionSignature` class extends the `Signature` class, inheriting its basic properties of `r` and `s`, which are components of the ECDSA (Elliptic Curve Digital Signature Algorithm) signature. Additionally, it introduces a `scope` variable which is specific to the context of transaction signing, indicating the parts of the transaction the signature commits to.
|
|
6
|
-
|
|
7
|
-
The class defines several static readonly properties representing the SIGHASH types for the `scope`:
|
|
8
|
-
|
|
9
|
-
- `SIGHASH_ALL`: The signature commits to all outputs of the transaction, ensuring none can be changed without invalidating the signature.
|
|
10
|
-
- `SIGHASH_NONE`: The signature commits to no outputs, allowing others to add outputs to the transaction.
|
|
11
|
-
- `SIGHASH_SINGLE`: The signature commits to exactly one output, the one with the same index as the input the signature is for. This allows for independent adjustment of outputs in multi-output transactions.
|
|
12
|
-
- `SIGHASH_ANYONECANPAY`: Modifies the behavior of the other types by only committing to the current input, allowing others to add or remove other inputs.
|
|
13
|
-
- `SIGHASH_FORKID`: Currently always enabled in BSV.
|
|
14
|
-
|
|
15
|
-
### Serialization and Formats
|
|
16
|
-
|
|
17
|
-
The `TransactionSignature` class includes methods for serializing and deserializing transaction signatures, useful for referencing them within scripts, among other things.
|
|
18
|
-
|
|
19
|
-
- `format()`: This static method prepares the transaction data for signing by creating a preimage according to the specified SIGHASH type. It considers various components like inputs, outputs, the transaction sequence, and lock time. Useful for generating the data that will be signed to produce a transaction signature.
|
|
20
|
-
- `fromChecksigFormat()`: Deserializes a script stack element into a `TransactionSignature` instance, useful for parsing signatures from raw transaction data.
|
|
21
|
-
- `toChecksigFormat()`: Serializes the signature back into a format that can be embedded in a script. This includes converting the ECDSA components (`r` and `s`) into DER format, followed by the `scope` (SIGHASH flags) to indicate which components are signed.
|
|
22
|
-
|
|
23
|
-
The `TransactionSignature` encapsulates the complexity of transaction signing and signature serialization. You can make use of the static `.format()` method to compute the signatures you need, enabling a wide variety of applications.
|
|
24
|
-
|
|
25
|
-
## Using the Signature Preimage Formatter
|
|
26
|
-
|
|
27
|
-
Here's an example of formatting a signature preimage for use in a Transaction:
|
|
28
|
-
|
|
29
|
-
```typescript
|
|
30
|
-
import { P2PKH, Transaction, PrivateKey, TransactionSignature, UnlockingScript, Hash } from '@bsv/sdk'
|
|
31
|
-
|
|
32
|
-
// Initialize the script template, source TX, and the TX we'll be working on adding a signature for.
|
|
33
|
-
const p2pkh = new P2PKH()
|
|
34
|
-
const sourceTx = Transaction.fromHex('0200000001849c6419aec8b65d747cb72282cc02f3fc26dd018b46962f5de48957fac50528020000006a473044022008a60c611f3b48eaf0d07b5425d75f6ce65c3730bd43e6208560648081f9661b0220278fa51877100054d0d08e38e069b0afdb4f0f9d38844c68ee2233ace8e0de2141210360cd30f72e805be1f00d53f9ccd47dfd249cbb65b0d4aee5cfaf005a5258be37ffffffff03d0070000000000001976a914acc4d7c37bc9d0be0a4987483058a2d842f2265d88ac75330100000000001976a914db5b7964eecb19fcab929bf6bd29297ec005d52988ac809f7c09000000001976a914c0b0a42e92f062bdbc6a881b1777eed1213c19eb88ac00000000')
|
|
35
|
-
const tx = new Transaction(
|
|
36
|
-
1, //version
|
|
37
|
-
[{
|
|
38
|
-
sourceTransaction: sourceTx,
|
|
39
|
-
sourceOutputIndex: 0,
|
|
40
|
-
sequence: 0xffffffff
|
|
41
|
-
}],
|
|
42
|
-
[{ // outputs
|
|
43
|
-
lockingScript: p2pkh.lock('176ayvhKue1C5StD31cTsdN1hwotw59jsR'),
|
|
44
|
-
satoshis: 1000
|
|
45
|
-
}],
|
|
46
|
-
0 // lock time
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
// The private key we will use for signing
|
|
50
|
-
const privateKey = new PrivateKey(42) // Replace
|
|
51
|
-
|
|
52
|
-
// Let's decide which input index we're signing
|
|
53
|
-
const inputIndex = 0
|
|
54
|
-
|
|
55
|
-
// We'll sign all inputs and outputs with this signature.
|
|
56
|
-
let signatureScope = TransactionSignature.SIGHASH_FORKID | TransactionSignature.SIGHASH_ALL
|
|
57
|
-
|
|
58
|
-
const otherInputs = [...tx.inputs]
|
|
59
|
-
const [input] = otherInputs.splice(inputIndex, 1)
|
|
60
|
-
if (typeof input.sourceTransaction !== 'object') {
|
|
61
|
-
throw new Error(
|
|
62
|
-
'The source transaction is needed for transaction signing.'
|
|
63
|
-
)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// The pre-image is the data that we are incorporating into the signature.
|
|
67
|
-
// It needs a few important details about the output we're spending and the new transaction we're creating.
|
|
68
|
-
const preimage = TransactionSignature.format({
|
|
69
|
-
// The source TXID of the output we're spending needs to be provided.
|
|
70
|
-
sourceTXID: input.sourceTransaction.id('hex') as string,
|
|
71
|
-
|
|
72
|
-
// Identify the output index in the source transaction so we know where the coins come from.
|
|
73
|
-
sourceOutputIndex: input.sourceOutputIndex,
|
|
74
|
-
|
|
75
|
-
// Identify the amount of satoshis that are in the source output.
|
|
76
|
-
sourceSatoshis: input.sourceTransaction.outputs[input.sourceOutputIndex].satoshis as number,
|
|
77
|
-
|
|
78
|
-
// Identify the version of the new transaction you are creating, that will spend the source output.
|
|
79
|
-
transactionVersion: tx.version,
|
|
80
|
-
|
|
81
|
-
// Stipulate any other inputs (with the current input removed from the list) in the new transaction
|
|
82
|
-
// that will be included in the signature. Note that with SIGHASH_ANYONECANPAY, this can be empty.
|
|
83
|
-
otherInputs,
|
|
84
|
-
|
|
85
|
-
// Stipulate the index of the current input in the new transaction you are working to create.
|
|
86
|
-
inputIndex,
|
|
87
|
-
|
|
88
|
-
// Stipulate the outputs to the new transaction you are creating.
|
|
89
|
-
// Note that if you are using SIGHASH_NONE, this can be empty.
|
|
90
|
-
// If you are using SIGHASH_SINGLE, it could be a "sparse array" with only the output at the same index as the inputIndex populated.
|
|
91
|
-
outputs: tx.outputs,
|
|
92
|
-
|
|
93
|
-
// Provide the current sequence number of the input that you are working on signing.
|
|
94
|
-
inputSequence: input.sequence,
|
|
95
|
-
|
|
96
|
-
// Provide the portion of the script in which you are working.
|
|
97
|
-
// In most simple use-cases (that don't make use of OP_CODESEPARATOR), this is just the locking script from the source output.
|
|
98
|
-
subscript: input.sourceTransaction.outputs[input.sourceOutputIndex].lockingScript,
|
|
99
|
-
|
|
100
|
-
// Provide the lock time for the new transaction you are working to create.
|
|
101
|
-
lockTime: tx.lockTime,
|
|
102
|
-
|
|
103
|
-
// Finally, provide the SIGHASH flags you wish to include in the preimage that will be generated.
|
|
104
|
-
scope: signatureScope
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
// The result will be a preimage that can be signed, and included in scripts.
|
|
108
|
-
|
|
109
|
-
// We sign the hash of the preimage.
|
|
110
|
-
// Because the `.sign()` method also performs a hash, the result is the "double-hash" needed by Bitcoin.
|
|
111
|
-
const rawSignature = privateKey.sign(Hash.sha256(preimage))
|
|
112
|
-
|
|
113
|
-
// Now, we construct a TransactionSignature from the ECDSA signature, for conversion to Checksig format.
|
|
114
|
-
const sig = new TransactionSignature(
|
|
115
|
-
rawSignature.r,
|
|
116
|
-
rawSignature.s,
|
|
117
|
-
signatureScope
|
|
118
|
-
)
|
|
119
|
-
|
|
120
|
-
// Then we convert it so it can be used in a script
|
|
121
|
-
const sigForScript = sig.toChecksigFormat()
|
|
122
|
-
|
|
123
|
-
// Finally, we could go on to make any kind of needed unlocking script with the signature..
|
|
124
|
-
const pubkeyForScript = privateKey.toPublicKey().encode(true) as number[]
|
|
125
|
-
const script = new UnlockingScript([
|
|
126
|
-
{ op: sigForScript.length, data: sigForScript },
|
|
127
|
-
{ op: pubkeyForScript.length, data: pubkeyForScript }
|
|
128
|
-
])
|
|
129
|
-
console.log('Signature was computed! P2PKH Unlocking Script:', script.toHex())
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
First, we set up the data we wanted to sign. Then, we created a pre-image, hashed it, and signed it with a private key using ECSA. Then, we created a new `TransactionSignature` instance with the ECDSA signature, so that we could convert it into Checksig format. At this point, you could use the transaction signature in a script to help unlock a UTXO, enabling you to unlock and spend the associated Bitcoins or other digital assets.
|