@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.
Files changed (42) hide show
  1. package/dist/cjs/package.json +1 -1
  2. package/package.json +1 -1
  3. package/src/transaction/__tests/Transaction.test.ts +2 -2
  4. package/docs/concepts/42.md +0 -35
  5. package/docs/concepts/BEEF.md +0 -38
  6. package/docs/concepts/CHAIN_SPV.md +0 -38
  7. package/docs/concepts/FEE.md +0 -35
  8. package/docs/concepts/HASHES.md +0 -19
  9. package/docs/concepts/HOW_TX.md +0 -60
  10. package/docs/concepts/OP.md +0 -38
  11. package/docs/concepts/README.md +0 -14
  12. package/docs/concepts/TEMPLATES.md +0 -42
  13. package/docs/concepts/TX_SIG.md +0 -34
  14. package/docs/concepts/TX_VALID.md +0 -35
  15. package/docs/examples/EXAMPLE_BUILDING_CUSTOM_TX_BROADCASTER.md +0 -91
  16. package/docs/examples/EXAMPLE_COMPLEX_TX.md +0 -162
  17. package/docs/examples/EXAMPLE_ECIES.md +0 -37
  18. package/docs/examples/EXAMPLE_ENCRYPT_DECRYPT_MESSAGE.md +0 -52
  19. package/docs/examples/EXAMPLE_FEE_MODELING.md +0 -199
  20. package/docs/examples/EXAMPLE_HD_WALLETS.md +0 -71
  21. package/docs/examples/EXAMPLE_MESSAGE_SIGNING.md +0 -63
  22. package/docs/examples/EXAMPLE_SCRIPT_TEMPLATES.md +0 -170
  23. package/docs/examples/EXAMPLE_SIMPLE_TX.md +0 -145
  24. package/docs/examples/EXAMPLE_TYPE_42.md +0 -108
  25. package/docs/examples/EXAMPLE_UTXOS_TX.md +0 -85
  26. package/docs/examples/EXAMPLE_VERIFYING_BEEF.md +0 -62
  27. package/docs/examples/EXAMPLE_VERIFYING_ROOTS.md +0 -97
  28. package/docs/examples/EXAMPLE_VERIFYING_SPENDS.md +0 -69
  29. package/docs/examples/GETTING_STARTED_NODE_CJS.md +0 -71
  30. package/docs/examples/GETTING_STARTED_REACT.md +0 -119
  31. package/docs/examples/README.md +0 -19
  32. package/docs/low-level/AES_SYMMETRIC_ENCRYPTION.md +0 -40
  33. package/docs/low-level/ECDH.md +0 -64
  34. package/docs/low-level/NUMBERS_POINTS.md +0 -116
  35. package/docs/low-level/README.md +0 -13
  36. package/docs/low-level/TX_SIG.md +0 -132
  37. package/docs/low-level/TYPE_42.md +0 -53
  38. package/docs/low-level/USING_ECDSA.md +0 -30
  39. package/docs/low-level/USING_HASHES_AND_HMACS.md +0 -79
  40. package/docs/low-level/USING_PRIVATE_PUBLIC_KEYS.md +0 -70
  41. package/docs/low-level/USING_SCRIPTS.md +0 -71
  42. 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.
@@ -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.
@@ -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.
@@ -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)
@@ -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.