mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-02-20 13:44:59 +01:00
Prepare for 1.9.6 (#4820)
This commit is contained in:
parent
de43dadf52
commit
e73b328833
12 changed files with 1143 additions and 2 deletions
|
@ -1,5 +1,5 @@
|
|||
package org.bitcoins.node.constant
|
||||
|
||||
case object NodeConstants {
|
||||
val userAgent = "/bitcoin-s:1.9.5/"
|
||||
val userAgent = "/bitcoin-s:1.9.6/"
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ import scala.util.Properties
|
|||
|
||||
object CommonSettings {
|
||||
|
||||
val previousStableVersion: String = "1.9.5"
|
||||
val previousStableVersion: String = "1.9.6"
|
||||
|
||||
private def isCI = {
|
||||
Properties
|
||||
|
|
144
release-notes/release-notes-1.9.6.md
Normal file
144
release-notes/release-notes-1.9.6.md
Normal file
|
@ -0,0 +1,144 @@
|
|||
# 1.9.6
|
||||
|
||||
This release is backwards compatible with the 1.9.x series of bitcoin-s
|
||||
|
||||
See the individual module sections for more information on lower level updates to the codebase.
|
||||
|
||||
Want to get started quickly? See our `docker-compose.yml` file. [See instructions here](https://github.com/bitcoin-s/bitcoin-s/#docker)
|
||||
|
||||
If you are a typescript developer, [you can access the backend via our typescript library](https://github.com/bitcoin-s/bitcoin-s-ts)
|
||||
|
||||
# Executive Summary
|
||||
|
||||
This release adds network notifications via the websocket when various tor interactions fail when negotiating a DLC.
|
||||
|
||||
This release delete all DLCs that are settled using the `Alpha` version of the DLC protocol.
|
||||
This makes upgrading to the new v0 format of the dlc protocol easier for an implementation point of view.
|
||||
This will not delete alpha DLCs that are still in progress, rather throw an exception on wallet startup.
|
||||
|
||||
This release also fixes a bug in the wallet where utxos would be stuck in an unconfirmed state.
|
||||
|
||||
## Running bitcoin-s
|
||||
|
||||
If you want to run the standalone server binary, after verifying gpg signatures, you
|
||||
can `unzip bitcoin-s-server-1.9.6.zip` and then run it with `chmod +x ./bin/bitcoin-s-server && ./bin/bitcoin-s-server` to start the node. You will need to
|
||||
configure the node properly first, you can find example
|
||||
configurations [here](https://bitcoin-s.org/docs/config/configuration#example-configuration-file).
|
||||
|
||||
You can then unzip the `bitcoin-s-cli-1.9.6.zip` folder and start using the `bitcoin-s-cli` like this:
|
||||
|
||||
```bashrc
|
||||
./bin/bitcoin-s-cli --help
|
||||
Usage: bitcoin-s-cli [options] [<cmd>]
|
||||
|
||||
-n, --network <value> Select the active network.
|
||||
--debug Print debugging information
|
||||
--rpcport <value> The port to send our rpc request to on the server
|
||||
-h, --help Display this help message and exit
|
||||
```
|
||||
|
||||
For more information on what commands `bitcoin-s-cli` supports check the documentation, here is where to
|
||||
start: https://bitcoin-s.org/docs/next/applications/server#server-endpoints
|
||||
|
||||
## Verifying signatures
|
||||
|
||||
This release is signed with [Chris's signing key](https://bitcoin-s.org/docs/next/security#disclosure) with
|
||||
fingerprint `9234F4D6AF47C71B741A390F8976CA0AF71A7A2A`
|
||||
|
||||
To do the verification, first hash the executable using `sha256sum`. You should check that the result is listed in
|
||||
the `SHA256SUMS.asc` file next to its file name. After doing that you can use `gpg --verify` to authenticate the
|
||||
signature.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
$ gpg -d SHA256SUMS.asc > SHA256SUMS.stripped
|
||||
gpg: Signature made Mon 18 Apr 2022 02:19:54 PM CDT
|
||||
gpg: using RSA key 9234F4D6AF47C71B741A390F8976CA0AF71A7A2A
|
||||
gpg: Good signature from "Chris Stewart <stewart.chris1234@gmail.com>" [ultimate]
|
||||
|
||||
$ sha256sum -c SHA256SUMS.stripped
|
||||
bitcoin-s_1.9.3-1_amd64.deb: OK
|
||||
bitcoin-s-1.9.3.dmg: OK
|
||||
bitcoin-s-bundle.msi: OK
|
||||
bitcoin-s-cli-x86_64-apple-darwin: OK
|
||||
bitcoin-s-cli-x86_64-pc-linux: OK
|
||||
bitcoin-s-server-1.9.3.zip: OK
|
||||
|
||||
```
|
||||
|
||||
### Website
|
||||
|
||||
https://bitcoin-s.org/
|
||||
|
||||
### Releases
|
||||
|
||||
https://repo1.maven.org/maven2/org/bitcoin-s/
|
||||
|
||||
### Snapshot releases
|
||||
|
||||
https://oss.sonatype.org/content/repositories/snapshots/org/bitcoin-s/
|
||||
|
||||
# Modules
|
||||
|
||||
## app commons
|
||||
|
||||
## App server
|
||||
|
||||
## bitcoind rpc
|
||||
|
||||
## bundle
|
||||
|
||||
## Build
|
||||
|
||||
## chain
|
||||
|
||||
## Core
|
||||
|
||||
## Crypto
|
||||
|
||||
## db commons
|
||||
|
||||
## DLC node
|
||||
|
||||
de43dadf52b Network notifications (#4774)
|
||||
|
||||
## DLC Oracle
|
||||
|
||||
## DLC wallet
|
||||
|
||||
62081a43ecd 2022 10 05 Delete legacy `DLCSerializationVersion.Alpha` DLCs for a cleaner upgrade to v0 spec (#4817)
|
||||
|
||||
## gui
|
||||
|
||||
## fee rate
|
||||
|
||||
## keymanager
|
||||
|
||||
## Lnd rpc
|
||||
|
||||
## Lnurl
|
||||
|
||||
## node
|
||||
|
||||
718053668d8 2022 10 07 node test fixes (#4819)
|
||||
|
||||
## Oracle Explorer Client
|
||||
|
||||
## wallet
|
||||
|
||||
Fix bug where transactions would be stuck in a unconfirmed state
|
||||
|
||||
ddc672cc466 Fix unconfirmed -> confirmed state change (#4816)
|
||||
|
||||
## testkit-core
|
||||
|
||||
## testkit
|
||||
|
||||
## tor
|
||||
|
||||
## Website
|
||||
|
||||
## Dependencies
|
||||
|
||||
c075112db5b Upgrade sbt to 1.7.2 (#4818)
|
59
website/versioned_docs/version-1.9.6/core/addresses.md
Normal file
59
website/versioned_docs/version-1.9.6/core/addresses.md
Normal file
|
@ -0,0 +1,59 @@
|
|||
---
|
||||
id: version-1.9.6-addresses
|
||||
title: Generating Addresses
|
||||
original_id: addresses
|
||||
---
|
||||
|
||||
Almost all Bitcoin applications need to generate addresses
|
||||
for their users somehow. There's a lot going on in getting
|
||||
a correct bitcoin address, but our APIs make it possible to
|
||||
to get started with all types of addresses in a matter of
|
||||
minutes.
|
||||
|
||||
## Generating SegWit (bech32) addresses
|
||||
|
||||
Generating native SegWit addresses in the bech32 format
|
||||
is something that all Bitcoin applications should enable,
|
||||
as it makes the transaction fees less expensive, and also
|
||||
makes the addresses more readable by humans. However, it
|
||||
has seen slower than necessary adoption. With Bitcoin-S
|
||||
you can generate bech32 addresses in four(!) lines of code
|
||||
(not counting comments and imports), so now there's no
|
||||
reason to keep using legacy transaction formats.
|
||||
|
||||
|
||||
```scala
|
||||
// this generates a random private key
|
||||
val privkey = ECPrivateKey()
|
||||
// privkey: ECPrivateKey = Masked(ECPrivateKey)
|
||||
val pubkey = privkey.publicKey
|
||||
// pubkey: org.bitcoins.crypto.ECPublicKey = ECPublicKey(031491da7bde590f90fe3cd2e4664888ea5c52cd008f50306bb98161d83b09440a)
|
||||
|
||||
val segwitAddress = {
|
||||
// see https://bitcoin.org/en/glossary/pubkey-script
|
||||
// for reading resources on the details of scriptPubKeys
|
||||
// pay-to-witness-pubkey-hash scriptPubKey V0
|
||||
val scriptPubKey = P2WPKHWitnessSPKV0(pubkey)
|
||||
Bech32Address(scriptPubKey, TestNet3)
|
||||
}
|
||||
// segwitAddress: Bech32Address = tb1qxteuu6th8v8qh5hjv0vss4qgxj2dfzmwu6lsjc
|
||||
|
||||
println(segwitAddress.toString)
|
||||
// tb1qxteuu6th8v8qh5hjv0vss4qgxj2dfzmwu6lsjc
|
||||
```
|
||||
|
||||
## Generating legacy (base58) addresses
|
||||
|
||||
If you need to generate legacy addresses for backwards
|
||||
compatability reasons, that's also a walk in the park.
|
||||
Take a look:
|
||||
|
||||
```scala
|
||||
// we're reusing the same private/public key pair
|
||||
// from before. don't do this in an actual application!
|
||||
val legacyAddress = P2PKHAddress(pubkey, TestNet3)
|
||||
// legacyAddress: P2PKHAddress = mkAN9bzB9WQtZraGyy8mkeWKg9HZiyNW9Y
|
||||
|
||||
println(legacyAddress.toString)
|
||||
// mkAN9bzB9WQtZraGyy8mkeWKg9HZiyNW9Y
|
||||
```
|
226
website/versioned_docs/version-1.9.6/core/dlc.md
Normal file
226
website/versioned_docs/version-1.9.6/core/dlc.md
Normal file
File diff suppressed because one or more lines are too long
145
website/versioned_docs/version-1.9.6/core/hd-keys.md
Normal file
145
website/versioned_docs/version-1.9.6/core/hd-keys.md
Normal file
|
@ -0,0 +1,145 @@
|
|||
---
|
||||
id: version-1.9.6-hd-keys
|
||||
title: HD Key Generation
|
||||
original_id: hd-keys
|
||||
---
|
||||
|
||||
In modern Bitcoin wallets, users only need to write down
|
||||
a sequence of words, and that sequence is a complete backup
|
||||
of their wallet. This is thanks to what's called Hierarchical
|
||||
Deterministic key generation. In short, every wallet using HD
|
||||
key generation has a root seed for each wallet, and this
|
||||
seed can be used to generate an arbitrary amount of later
|
||||
private and public keys. This is done in a standardized manner,
|
||||
so different wallets can operate with the same standard.
|
||||
|
||||
> If you want to jump into the details of how this work,
|
||||
> you should check out
|
||||
> [BIP 32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki).
|
||||
|
||||
Bitcoin-S supports generating keys in this fashion. Here's a
|
||||
full example of how to obtain a wallet seed, and then
|
||||
use that to generate further private and public keys:
|
||||
|
||||
```scala
|
||||
import scodec.bits._
|
||||
import org.bitcoins.core.crypto._
|
||||
import org.bitcoins.core.hd._
|
||||
|
||||
// the length of the entropy bit vector determine
|
||||
// how long our phrase ends up being
|
||||
// 256 bits of entropy results in 24 words
|
||||
val entropy: BitVector = MnemonicCode.getEntropy256Bits
|
||||
// entropy: BitVector = BitVector(256 bits, 0x3d2e35e48b9eec87da46d5cc0b2e4cf8289395ebfbef07ef68c1d9b548a18e23)
|
||||
|
||||
val mnemonicCode = MnemonicCode.fromEntropy(entropy)
|
||||
// mnemonicCode: MnemonicCode = Masked(MnemonicCodeImpl)
|
||||
|
||||
mnemonicCode.words // the phrase the user should write down
|
||||
// res0: Vector[String] = Vector(diamond, immune, junior, blame, uphold, dumb, harbor, survey, slot, floor, nasty, utility, matrix, slab, quiz, law, among, kitten, corn, recall, fee, express, decade, giraffe) // the phrase the user should write down
|
||||
|
||||
// the password argument is an optional, extra security
|
||||
// measure. all MnemonicCode instances will give you a
|
||||
// valid BIP39 seed, but different passwords will give
|
||||
// you different seeds. So you could have as many wallets
|
||||
// from the same seed as you'd like, by simply giving them
|
||||
// different passwords.
|
||||
val bip39Seed = BIP39Seed.fromMnemonic(mnemonicCode,
|
||||
password = "secret password")
|
||||
// bip39Seed: BIP39Seed = Masked(BIP39SeedImpl)
|
||||
|
||||
val xpriv = ExtPrivateKey.fromBIP39Seed(ExtKeyVersion.SegWitMainNetPriv,
|
||||
bip39Seed)
|
||||
// xpriv: ExtPrivateKey = Masked(ExtPrivateKeyImpl)
|
||||
val xpub = xpriv.extPublicKey
|
||||
// xpub: ExtPublicKey = zpub6jftahH18ngZy7kb18qC5tVwvb61zyxF8FYVpvHJ3TEqoPVUWa77RQvq8HNzGLkL7qBxrRddwGdvoDNHp3acjXpWahoQ2QCZpefBoyFNqcj
|
||||
|
||||
// you can now use the generated xpriv to derive further
|
||||
// private or public keys
|
||||
|
||||
// this can be done with BIP89 paths (called SegWitHDPath in bitcoin-s)
|
||||
val segwitPath = SegWitHDPath.fromString("m/84'/0'/0'/0/0")
|
||||
// segwitPath: SegWitHDPath = m/84'/0'/0'/0/0
|
||||
|
||||
// alternatively:
|
||||
val otherSegwitPath =
|
||||
SegWitHDPath(HDCoinType.Bitcoin,
|
||||
accountIndex = 0,
|
||||
HDChainType.External,
|
||||
addressIndex = 0)
|
||||
// otherSegwitPath: SegWitHDPath = m/84'/0'/0'/0/0
|
||||
|
||||
segwitPath == otherSegwitPath
|
||||
// res1: Boolean = true
|
||||
```
|
||||
|
||||
## Generating new addresses without having access to the private key
|
||||
|
||||
One the coolest features of HD wallets is that it's possible
|
||||
to generate addresses offline, without having access to the
|
||||
private keys. This feature is commonly called watch-only
|
||||
wallets, where a wallet can import information about all
|
||||
your past and future transactions, without being able to
|
||||
spend or steal any of your money.
|
||||
|
||||
Let's see an example of this:
|
||||
|
||||
```scala
|
||||
import scala.util.Success
|
||||
import org.bitcoins.core.protocol.script._
|
||||
import org.bitcoins.core.protocol.Bech32Address
|
||||
import org.bitcoins.core.config.TestNet3
|
||||
|
||||
// first account -------┐
|
||||
// bitcoin ----------┐ |
|
||||
// segwit --------┐ | |
|
||||
val accountPath = BIP32Path.fromString("m/84'/0'/0'")
|
||||
// accountPath: BIP32Path = m/84'/0'/0'
|
||||
val accountXpub = {
|
||||
// this key is sensitive, keep away from prying eyes!
|
||||
val accountXpriv = xpriv.deriveChildPrivKey(accountPath)
|
||||
|
||||
// this key is not sufficient to spend from, but we
|
||||
// can generate addresses with it!
|
||||
accountXpriv.extPublicKey
|
||||
}
|
||||
// accountXpub: ExtPublicKey = zpub6qoYRU88iCy3grnYpf2WyQFzkih9eNxEsS1zrf8H9SRuFtfKW2ZWd2Q79BCCzxG4JxmKKgCa45JbC2oMBvg9V1ynonts7KNrvpAvcsYmEZD
|
||||
|
||||
// address no. 0 ---------------┐
|
||||
// external address ----------┐ |
|
||||
val firstAddressPath = SegWitHDPath.fromString("m/84'/0'/0'/0/0")
|
||||
// firstAddressPath: SegWitHDPath = m/84'/0'/0'/0/0
|
||||
val firstAccountAddress = {
|
||||
// this is a bit quirky, but we're not interesting in
|
||||
// deriving the complete path from our account xpub
|
||||
// instead, we're only interested in the part after
|
||||
// the account level (3rd level). the .diff() method
|
||||
// achieves that
|
||||
val Some(pathDiff) = accountPath.diff(firstAddressPath)
|
||||
|
||||
// deriving public keys from hardened extended keys
|
||||
// is not possible, that's why .deriveChildPubKey()
|
||||
// returns a Try[ExtPublicKey]. A hardened key is marked
|
||||
// by a ' after the number in the notation we use above.
|
||||
val Success(extPubKey) = accountXpub.deriveChildPubKey(pathDiff)
|
||||
val pubkey = extPubKey.key
|
||||
val scriptPubKey = P2WPKHWitnessSPKV0(pubkey)
|
||||
Bech32Address(scriptPubKey, TestNet3)
|
||||
}
|
||||
// firstAccountAddress: Bech32Address = tb1q403gq542v33vywyem8ztfk7l0g63gflzlc5zwk
|
||||
|
||||
// tada! We just generated an address you can send money to,
|
||||
// without having access to the private key!
|
||||
firstAccountAddress.value
|
||||
// res2: String = tb1q403gq542v33vywyem8ztfk7l0g63gflzlc5zwk
|
||||
|
||||
// you can now continue deriving addresses from the same public
|
||||
// key, by imitating what we did above. To get the next
|
||||
// HD path to generate an address at:
|
||||
val nextAddressPath: SegWitHDPath = firstAddressPath.next
|
||||
// nextAddressPath: SegWitHDPath = m/84'/0'/0'/0/1
|
||||
```
|
||||
|
||||
### Signing things with HD keys
|
||||
|
||||
Please see [sign.md](../crypto/sign.md) for information on how to sign things with HD keys.
|
158
website/versioned_docs/version-1.9.6/core/txbuilder.md
Normal file
158
website/versioned_docs/version-1.9.6/core/txbuilder.md
Normal file
|
@ -0,0 +1,158 @@
|
|||
---
|
||||
id: version-1.9.6-txbuilder
|
||||
title: TxBuilder Example
|
||||
original_id: txbuilder
|
||||
---
|
||||
|
||||
Bitcoin-S features a transaction building API that allows you to construct and sign Bitcoin transactions. Here's an example of how to use it
|
||||
|
||||
|
||||
```scala
|
||||
implicit val ec: ExecutionContext = ExecutionContext.Implicits.global
|
||||
// ec: ExecutionContext = scala.concurrent.impl.ExecutionContextImpl$$anon$3@2915f741[Running, parallelism = 8, size = 0, active = 0, running = 0, steals = 0, tasks = 0, submissions = 0]
|
||||
|
||||
// Initialize a transaction builder
|
||||
val builder = RawTxBuilder()
|
||||
// builder: RawTxBuilder = RawTxBuilder()
|
||||
|
||||
// generate a fresh private key that we are going to use in the scriptpubkey
|
||||
val privKey = ECPrivateKey.freshPrivateKey
|
||||
// privKey: ECPrivateKey = Masked(ECPrivateKey)
|
||||
val pubKey = privKey.publicKey
|
||||
// pubKey: ECPublicKey = ECPublicKey(03890e2a8ddb32cd2e0de2a4a5b2c5c35a5e017937696f2765537ed3cff43f8035)
|
||||
|
||||
// this is the script that the TxBuilder is going to create a
|
||||
// script signature that validly spends this scriptPubKey
|
||||
val creditingSpk = P2PKHScriptPubKey(pubKey = privKey.publicKey)
|
||||
// creditingSpk: P2PKHScriptPubKey = pkh(77ce65d7c78515f00874841cdf5b2f8fc387b5ce)
|
||||
val amount = 10000.satoshis
|
||||
// amount: Satoshis = 10000 sats
|
||||
|
||||
// this is the UTXO we are going to be spending
|
||||
val utxo =
|
||||
TransactionOutput(value = amount, scriptPubKey = creditingSpk)
|
||||
// utxo: TransactionOutput = TransactionOutput(10000 sats,pkh(77ce65d7c78515f00874841cdf5b2f8fc387b5ce))
|
||||
|
||||
// the private key that locks the funds for the script we are spending too
|
||||
val destinationPrivKey = ECPrivateKey.freshPrivateKey
|
||||
// destinationPrivKey: ECPrivateKey = Masked(ECPrivateKey)
|
||||
|
||||
// the amount we are sending -- 5000 satoshis -- to the destinationSPK
|
||||
val destinationAmount = 5000.satoshis
|
||||
// destinationAmount: Satoshis = 5000 sats
|
||||
|
||||
// the script that corresponds to destination private key, this is what is receiving the money
|
||||
val destinationSPK =
|
||||
P2PKHScriptPubKey(pubKey = destinationPrivKey.publicKey)
|
||||
// destinationSPK: P2PKHScriptPubKey = pkh(8a78c70ce814946fb2983a285fc40bb6efe7b6c6)
|
||||
|
||||
// this is where we are sending money too
|
||||
// we could add more destinations here if we
|
||||
// wanted to batch transactions
|
||||
val destinations = {
|
||||
val destination0 = TransactionOutput(value = destinationAmount,
|
||||
scriptPubKey = destinationSPK)
|
||||
|
||||
Vector(destination0)
|
||||
}
|
||||
// destinations: Vector[TransactionOutput] = Vector(TransactionOutput(5000 sats,pkh(8a78c70ce814946fb2983a285fc40bb6efe7b6c6)))
|
||||
|
||||
// Add the destinations to the tx builder
|
||||
builder ++= destinations
|
||||
// res0: RawTxBuilder = RawTxBuilder()
|
||||
|
||||
// we have to fabricate a transaction that contains the
|
||||
// UTXO we are trying to spend. If this were a real blockchain
|
||||
// we would need to reference the UTXO set
|
||||
val creditingTx = BaseTransaction(version = Int32.one,
|
||||
inputs = Vector.empty,
|
||||
outputs = Vector(utxo),
|
||||
lockTime = UInt32.zero)
|
||||
// creditingTx: BaseTransaction = BaseTransaction(Int32Impl(1),Vector(),Vector(TransactionOutput(10000 sats,pkh(77ce65d7c78515f00874841cdf5b2f8fc387b5ce))),UInt32Impl(0))
|
||||
|
||||
// this is the information we need from the crediting TX
|
||||
// to properly "link" it in the transaction we are creating
|
||||
val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero)
|
||||
// outPoint: TransactionOutPoint = TransactionOutPoint(df675236e164774db8794bf3a61a7dcca521b84244909437f3e33c94c0507cd2:0)
|
||||
val input = TransactionInput(
|
||||
outPoint,
|
||||
EmptyScriptSignature,
|
||||
sequenceNumber = UInt32.zero)
|
||||
// input: TransactionInput = TransactionInputImpl(TransactionOutPoint(df675236e164774db8794bf3a61a7dcca521b84244909437f3e33c94c0507cd2:0),EmptyScriptSignature,UInt32Impl(0))
|
||||
|
||||
// Add a new input to our builder
|
||||
builder += input
|
||||
// res1: RawTxBuilder = RawTxBuilder()
|
||||
|
||||
// We can now generate a RawTxBuilderResult ready to be finalized
|
||||
val builderResult = builder.result()
|
||||
// builderResult: RawTxBuilderResult = RawTxBuilderResult(Int32Impl(2),Vector(TransactionInputImpl(TransactionOutPoint(df675236e164774db8794bf3a61a7dcca521b84244909437f3e33c94c0507cd2:0),EmptyScriptSignature,UInt32Impl(0))),Vector(TransactionOutput(5000 sats,pkh(8a78c70ce814946fb2983a285fc40bb6efe7b6c6))),UInt32Impl(0))
|
||||
|
||||
// this contains the information needed to analyze our input during finalization
|
||||
val inputInfo = P2PKHInputInfo(outPoint, amount, privKey.publicKey)
|
||||
// inputInfo: P2PKHInputInfo = P2PKHInputInfo(TransactionOutPoint(df675236e164774db8794bf3a61a7dcca521b84244909437f3e33c94c0507cd2:0),10000 sats,ECPublicKey(03890e2a8ddb32cd2e0de2a4a5b2c5c35a5e017937696f2765537ed3cff43f8035))
|
||||
|
||||
// this is how much we are going to pay as a fee to the network
|
||||
// for this example, we are going to pay 1 satoshi per byte
|
||||
val feeRate = SatoshisPerByte(1.satoshi)
|
||||
// feeRate: SatoshisPerByte = 1 sats/byte
|
||||
|
||||
val changePrivKey = ECPrivateKey.freshPrivateKey
|
||||
// changePrivKey: ECPrivateKey = Masked(ECPrivateKey)
|
||||
val changeSPK = P2PKHScriptPubKey(pubKey = changePrivKey.publicKey)
|
||||
// changeSPK: P2PKHScriptPubKey = pkh(3517619d461a3deb79bd4cbf8adb0b6ffb9fb3c4)
|
||||
|
||||
// We chose a finalizer that adds a change output to our tx based on a fee rate
|
||||
val finalizer = StandardNonInteractiveFinalizer(
|
||||
Vector(inputInfo),
|
||||
feeRate,
|
||||
changeSPK)
|
||||
// finalizer: StandardNonInteractiveFinalizer = StandardNonInteractiveFinalizer(Vector(P2PKHInputInfo(TransactionOutPoint(df675236e164774db8794bf3a61a7dcca521b84244909437f3e33c94c0507cd2:0),10000 sats,ECPublicKey(03890e2a8ddb32cd2e0de2a4a5b2c5c35a5e017937696f2765537ed3cff43f8035))),1 sats/byte,pkh(3517619d461a3deb79bd4cbf8adb0b6ffb9fb3c4))
|
||||
|
||||
// We can now finalize the tx builder result from earlier with this finalizer
|
||||
val unsignedTx: Transaction = finalizer.buildTx(builderResult)
|
||||
// unsignedTx: Transaction = BaseTransaction(Int32Impl(2),Vector(TransactionInputImpl(TransactionOutPoint(df675236e164774db8794bf3a61a7dcca521b84244909437f3e33c94c0507cd2:0),EmptyScriptSignature,UInt32Impl(0))),Vector(TransactionOutput(5000 sats,pkh(8a78c70ce814946fb2983a285fc40bb6efe7b6c6)), TransactionOutput(4775 sats,pkh(3517619d461a3deb79bd4cbf8adb0b6ffb9fb3c4))),UInt32Impl(0))
|
||||
|
||||
// We now turn to signing the unsigned transaction
|
||||
// this contains all the information we need to
|
||||
// validly sign the UTXO above
|
||||
val utxoInfo = ScriptSignatureParams(inputInfo = inputInfo,
|
||||
prevTransaction = creditingTx,
|
||||
signers = Vector(privKey),
|
||||
hashType =
|
||||
HashType.sigHashAll)
|
||||
// utxoInfo: ScriptSignatureParams[P2PKHInputInfo] = ScriptSignatureParams(P2PKHInputInfo(TransactionOutPoint(df675236e164774db8794bf3a61a7dcca521b84244909437f3e33c94c0507cd2:0),10000 sats,ECPublicKey(03890e2a8ddb32cd2e0de2a4a5b2c5c35a5e017937696f2765537ed3cff43f8035)),BaseTransaction(Int32Impl(1),Vector(),Vector(TransactionOutput(10000 sats,pkh(77ce65d7c78515f00874841cdf5b2f8fc387b5ce))),UInt32Impl(0)),Vector(Masked(ECPrivateKey)),SIGHASH_ALL(1))
|
||||
|
||||
// all of the UTXO spending information, since we only have
|
||||
// one input, this is just one element
|
||||
val utxoInfos: Vector[ScriptSignatureParams[InputInfo]] = Vector(utxoInfo)
|
||||
// utxoInfos: Vector[ScriptSignatureParams[InputInfo]] = Vector(ScriptSignatureParams(P2PKHInputInfo(TransactionOutPoint(df675236e164774db8794bf3a61a7dcca521b84244909437f3e33c94c0507cd2:0),10000 sats,ECPublicKey(03890e2a8ddb32cd2e0de2a4a5b2c5c35a5e017937696f2765537ed3cff43f8035)),BaseTransaction(Int32Impl(1),Vector(),Vector(TransactionOutput(10000 sats,pkh(77ce65d7c78515f00874841cdf5b2f8fc387b5ce))),UInt32Impl(0)),Vector(Masked(ECPrivateKey)),SIGHASH_ALL(1)))
|
||||
|
||||
// Yay! Now we use the RawTxSigner object to sign the tx.
|
||||
// The 'sign' method is going produce a validly signed transaction
|
||||
// This is going to iterate through each of the UTXOs and use
|
||||
// the corresponding ScriptSignatureParams to produce a validly
|
||||
// signed input. This UTXO has:
|
||||
// 1: one input
|
||||
// 2: outputs (destination and change outputs)
|
||||
// 3: a fee rate of 1 satoshi/byte
|
||||
val signedTx: Transaction =
|
||||
RawTxSigner.sign(
|
||||
utx = unsignedTx,
|
||||
utxoInfos = utxoInfos,
|
||||
expectedFeeRate = feeRate
|
||||
)
|
||||
// signedTx: Transaction = BaseTransaction(Int32Impl(2),Vector(TransactionInputImpl(TransactionOutPoint(df675236e164774db8794bf3a61a7dcca521b84244909437f3e33c94c0507cd2:0),P2PKHScriptSignature(ECPublicKeyBytes(ByteVector(33 bytes, 0x03890e2a8ddb32cd2e0de2a4a5b2c5c35a5e017937696f2765537ed3cff43f8035)), ECDigitalSignature(304402203773de96dce15c8e144fee0b579b58c79073230a64f5bac153441afc1aad80d00220482bae1b87351702ebd18689580b06e0ebc9ef19b3050630d9ced09c082470d101)),UInt32Impl(0))),Vector(TransactionOutput(5000 sats,pkh(8a78c70ce814946fb2983a285fc40bb6efe7b6c6)), TransactionOutput(4775 sats,pkh(3517619d461a3deb79bd4cbf8adb0b6ffb9fb3c4))),UInt32Impl(0))
|
||||
```
|
||||
|
||||
```scala
|
||||
signedTx.inputs.length
|
||||
// res2: Int = 1
|
||||
|
||||
signedTx.outputs.length
|
||||
// res3: Int = 2
|
||||
|
||||
//remember, you can call .hex on any bitcoin-s data structure to get the hex representation!
|
||||
signedTx.hex
|
||||
// res4: String = 0200000001d27c50c0943ce3f33794904442b821a5cc7d1aa6f34b79b84d7764e1365267df000000006a47304402203773de96dce15c8e144fee0b579b58c79073230a64f5bac153441afc1aad80d00220482bae1b87351702ebd18689580b06e0ebc9ef19b3050630d9ced09c082470d1012103890e2a8ddb32cd2e0de2a4a5b2c5c35a5e017937696f2765537ed3cff43f8035000000000288130000000000001976a9148a78c70ce814946fb2983a285fc40bb6efe7b6c688aca7120000000000001976a9143517619d461a3deb79bd4cbf8adb0b6ffb9fb3c488ac00000000
|
||||
```
|
65
website/versioned_docs/version-1.9.6/crypto/sign.md
Normal file
65
website/versioned_docs/version-1.9.6/crypto/sign.md
Normal file
|
@ -0,0 +1,65 @@
|
|||
---
|
||||
id: version-1.9.6-sign
|
||||
title: Sign API
|
||||
original_id: sign
|
||||
---
|
||||
|
||||
### The [`Sign` API](/api/org/bitcoins/crypto/Sign)
|
||||
|
||||
This is the API we define to sign things with. It takes in an arbitrary byte vector and returns a `Future[ECDigitalSignature]`. The reason we incorporate `Future`s here is for extensibility of this API. We would like to provide implementations of this API for hardware devices, which need to be asynchrnous since they may require user input.
|
||||
|
||||
From [Sign.scala](/api/org/bitcoins/crypto/Sign):
|
||||
|
||||
```scala
|
||||
import scodec.bits._
|
||||
import org.bitcoins.crypto._
|
||||
import scala.concurrent._
|
||||
import scala.concurrent.duration._
|
||||
|
||||
trait Sign {
|
||||
def signFunction: ByteVector => Future[ECDigitalSignature]
|
||||
|
||||
def signFuture(bytes: ByteVector): Future[ECDigitalSignature] =
|
||||
signFunction(bytes)
|
||||
|
||||
def sign(bytes: ByteVector): ECDigitalSignature = {
|
||||
Await.result(signFuture(bytes), 30.seconds)
|
||||
}
|
||||
|
||||
def publicKey: ECPublicKey
|
||||
}
|
||||
```
|
||||
|
||||
The `ByteVector` that is input to the `signFunction` should be the hash that is output from [`TransactionSignatureSerializer`](/api/org/bitcoins/core/crypto/TransactionSignatureSerializer)'s `hashForSignature` method. Our in-memory [`BaseECKey`](/api/org/bitcoins/crypto/BaseECKey) types implement the `Sign` API.
|
||||
|
||||
If you wanted to implement a new `Sign` api for a hardware wallet, you can easily pass it into the `TxBuilder`/`Signer` classes to allow for you to use those devices to sign with Bitcoin-S.
|
||||
|
||||
This API is currently used to sign ordinary transactions with our [`Signer`](/api/org/bitcoins/core/wallet/signer/Signer)s. The `Signer` subtypes (i.e. `P2PKHSigner`) implement the specific functionality needed to produce a valid digital signature for their corresponding script type.
|
||||
|
||||
|
||||
### The [`ExtSign`](/api/org/bitcoins/crypto/Sign) API.
|
||||
|
||||
An [ExtKey](/api/org/bitcoins/core/crypto/ExtKey) is a data structure that can be used to generate more keys from a parent key. For more information look at [hd-keys.md](../core/hd-keys.md)
|
||||
|
||||
You can sign with `ExtPrivateKey` the same way you could with a normal `ECPrivateKey`.
|
||||
|
||||
```scala
|
||||
import org.bitcoins.core.hd._
|
||||
import org.bitcoins.core.crypto._
|
||||
|
||||
val extPrivKey = ExtPrivateKey(ExtKeyVersion.SegWitMainNetPriv)
|
||||
// extPrivKey: ExtPrivateKey = Masked(ExtPrivateKeyImpl)
|
||||
|
||||
extPrivKey.sign(DoubleSha256Digest.empty.bytes)
|
||||
// res0: ECDigitalSignature = ECDigitalSignature(3045022100c81a3e2a65ada4ea00cde9cf1618ebcda9f8b40ef4bf2a8f8b6b46a70dec008f022048a628634602e51301b2a0fc9ddb5504a642bf464bb806b51bf90de2e3dc665e)
|
||||
|
||||
val path = BIP32Path(Vector(BIP32Node(0,false)))
|
||||
// path: BIP32Path = m/0
|
||||
|
||||
extPrivKey.sign(DoubleSha256Digest.empty.bytes,path)
|
||||
// res1: ECDigitalSignature = ECDigitalSignature(304402205f7826826b5d4eb3373b5a62dc68320bcba5677d38b40005bf64e396778726e302200b949cbceaed378e6c53663f00591046e23489bca2835fa31544262c86bda4d1)
|
||||
```
|
||||
|
||||
With `ExtSign`, you can use `ExtPrivateKey` to sign transactions inside of `TxBuilder` since `UTXOSpendingInfo` takes in `Sign` as a parameter.
|
||||
|
||||
You can also provide a `path` to use to derive a child `ExtPrivateKey`, and then sign with that child private key
|
127
website/versioned_docs/version-1.9.6/getting-started.md
Normal file
127
website/versioned_docs/version-1.9.6/getting-started.md
Normal file
|
@ -0,0 +1,127 @@
|
|||
---
|
||||
id: version-1.9.6-getting-started
|
||||
title: Intro and Getting Started
|
||||
original_id: getting-started
|
||||
---
|
||||
|
||||
## Philosophy
|
||||
|
||||
Bitcoin-S is a loosely coupled set of cryptocurrency libraries for the JVM. They work well together, but also can be used
|
||||
independently. This project's goal is NOT to be a full node implementation, rather a set of scalable cryptocurrency libraries
|
||||
that use industry standard tools (rather than esoteric tech often found in cryptocurrency) where possible to make the lives of professional
|
||||
software engineers, security engineers, devops engineers and accountants easier.
|
||||
We are rapidly iterating on development with the goal of getting to a set of stable APIs that only change when the underlying bitcoin protocol changes.
|
||||
|
||||
If you are a professional working a cryptocurrency business and
|
||||
have feedback on how to make your lives easier, please reach out on [slack](https://join.slack.com/t/suredbits/shared_invite/zt-eavycu0x-WQL7XOakzQo8tAy7jHHZUw),
|
||||
[gitter](https://gitter.im/bitcoin-s-core/) or [twitter](https://twitter.com/Chris_Stewart_5/)!
|
||||
|
||||
## Getting prebuilt artifacts
|
||||
|
||||
### Java binaries
|
||||
|
||||
<details>
|
||||
|
||||
#### Latest release
|
||||
|
||||
Please see the release page on github, you can find it [here](https://github.com/bitcoin-s/bitcoin-s/releases)
|
||||
|
||||
#### Master builds
|
||||
|
||||
We build installers for mac, linux and windows everytime a PR is merged to master.
|
||||
|
||||
You can find the latest builds at this link:
|
||||
|
||||
https://github.com/bitcoin-s/bitcoin-s/actions/workflows/release.yml
|
||||
|
||||
Here is what the installers look like
|
||||
|
||||

|
||||
|
||||
</details>
|
||||
|
||||
### Docker
|
||||
|
||||
<details>
|
||||
We publish docker images to docker hub on every PR merge and tag on github.
|
||||
You can obtain the images for both the app server and oracle server on these
|
||||
docker hub repos
|
||||
|
||||
[bitcoin-s-server docker hub repo](https://hub.docker.com/r/bitcoinscala/bitcoin-s-server/tags?page=1&ordering=last_updated)
|
||||
|
||||
[bitcoin-s-oracle-server docker hub repo](https://hub.docker.com/r/bitcoinscala/bitcoin-s-oracle-server/tags?page=1&ordering=last_updated)
|
||||
</details>
|
||||
|
||||
### Library jars
|
||||
|
||||
<details>
|
||||
Add this to your `build.sbt`:
|
||||
|
||||
```scala
|
||||
|
||||
|
||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-bitcoind-rpc" % "1.9.4"
|
||||
|
||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-core" % "1.9.4"
|
||||
|
||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-chain" % "1.9.4"
|
||||
|
||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-dlc-oracle" % "1.9.4"
|
||||
|
||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-eclair-rpc" % "1.9.4"
|
||||
|
||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-fee-provider" % "1.9.4"
|
||||
|
||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-key-manager" % "1.9.4"
|
||||
|
||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-lnd-rpc" % "1.9.4"
|
||||
|
||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-node" % "1.9.4"
|
||||
|
||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-oracle-explorer-client" % "1.9.4"
|
||||
|
||||
libraryDependencies += "org.bitcoin-s" % "bitcoin-s-secp256k1jni" % "1.9.4"
|
||||
|
||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-testkit-core" % "1.9.4"
|
||||
|
||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-testkit" % "1.9.4"
|
||||
|
||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-wallet" % "1.9.4"
|
||||
|
||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-zmq" % "1.9.4"
|
||||
|
||||
```
|
||||
|
||||
|
||||
### Nightly builds
|
||||
|
||||
You can also run on the bleeding edge of Bitcoin-S, by
|
||||
adding a snapshot build to your `build.sbt`. The most
|
||||
recent snapshot published is `1.9.3-68-80deeed1-20220926-1805-SNAPSHOT`.
|
||||
|
||||
|
||||
|
||||
To fetch snapshots, you will need to add the correct
|
||||
resolver in your `build.sbt`:
|
||||
|
||||
```sbt
|
||||
resolvers += Resolver.sonatypeRepo("snapshots")
|
||||
```
|
||||
|
||||
The official maven repo for releases is
|
||||
|
||||
https://repo1.maven.org/maven2/org/bitcoin-s/
|
||||
|
||||
The repo for snapshots, which are published after everytime something is merged to master:
|
||||
|
||||
https://oss.sonatype.org/content/repositories/snapshots/org/bitcoin-s/
|
||||
|
||||
</details>
|
||||
|
||||
## Building JARs yourself
|
||||
|
||||
Please see [our setup docs](getting-setup.md)
|
||||
|
||||
## If you want to setup Bitcoin-S locally for development
|
||||
|
||||
Please see [our setup docs](getting-setup.md)
|
124
website/versioned_docs/version-1.9.6/key-manager/key-manager.md
Normal file
124
website/versioned_docs/version-1.9.6/key-manager/key-manager.md
Normal file
|
@ -0,0 +1,124 @@
|
|||
---
|
||||
id: version-1.9.6-key-manager
|
||||
title: Key Manager
|
||||
original_id: key-manager
|
||||
---
|
||||
|
||||
|
||||
### Key Manager
|
||||
|
||||
The key manager module's goal is to encapsulate all private key interactions with the [wallet](../wallet/wallet.md) project.
|
||||
|
||||
As of this writing, there is only one type of `KeyManager` - [`BIP39KeyManager`](/api/org/bitcoins/keymanager/bip39/BIP39KeyManager).
|
||||
|
||||
The [`BIP39KeyManager`](/api/org/bitcoins/keymanager/bip39/BIP39KeyManager) stores a [`MnemonicCode`](/api/org/bitcoins/core/crypto/MnemonicCode) on disk which can be decrypted and used as a hot wallet.
|
||||
|
||||
Over the long run, we want to make it so that the wallet project needs to communicate with the key-manager to access private keys.
|
||||
|
||||
This means that ALL SIGNING should be done inside of the key-manager, and private keys should not leave the key manager.
|
||||
|
||||
This makes it easier to reason about the security characteristics of our private keys, and a way to provide a uniform interface for alternative key storage systems (hsm, cloud based key storage, etc) to be plugged into the bitcoin-s library.
|
||||
|
||||
#### Creating a key manager
|
||||
|
||||
The first thing you need create a key manager is some entropy.
|
||||
|
||||
A popular way for bitcoin wallet's to represent entropy is [BIP39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) which you [can use in bitcoin-s](/api/org/bitcoins/core/crypto/BIP39Seed)
|
||||
|
||||
You can generate a `MnemonicCode` in bitcoin-s with the following code
|
||||
|
||||
```scala
|
||||
import org.bitcoins.core.crypto._
|
||||
|
||||
//get 256 bits of random entropy
|
||||
val entropy = MnemonicCode.getEntropy256Bits
|
||||
// entropy: scodec.bits.BitVector = BitVector(256 bits, 0xab0f0bec8940364a139d6987d560ad962918338a06121f9b39deebad3d313316)
|
||||
|
||||
val mnemonic = MnemonicCode.fromEntropy(entropy)
|
||||
// mnemonic: MnemonicCode = Masked(MnemonicCodeImpl)
|
||||
|
||||
//you can print that mnemonic seed with this
|
||||
println(mnemonic.words)
|
||||
// Vector(prison, joke, will, barely, address, celery, example, pudding, march, prison, clock, clump, muscle, border, chimney, seat, buzz, supply, jeans, struggle, stable, obtain, slush, spike)
|
||||
```
|
||||
|
||||
Now that we have a `MnemonicCode` that was securely generated, we need to now create `KeyManagerParams` which tells us how to generate
|
||||
generate specific kinds of addresses for wallets.
|
||||
|
||||
`KeyManagerParams` takes 3 parameters:
|
||||
|
||||
1. `seedPath` there is where we store the `MnemonicCode` on your file system
|
||||
2. [`purpose`](/api/org/bitcoins/core/hd/HDPurpose) which represents what type of utxo this `KeyManager` is associated with. The specification for this is in [BIP43](https://github.com/bitcoin/bips/blob/master/bip-0043.mediawiki)
|
||||
3. [`network`](/api/org/bitcoins/core/config/NetworkParameters) what cryptocurrency network this key manager is associated with
|
||||
|
||||
|
||||
This controls how the root key is defined. The combination of `purpose` and `network` determine how the root `ExtKey` is serialized. For more information on how this works please see [hd-keys](../core/hd-keys.md)
|
||||
|
||||
Now we can construct a native segwit key manager for the regtest network!
|
||||
|
||||
```scala
|
||||
//this will create a temp directory with the prefix 'key-manager-example` that will
|
||||
//have a file in it called "encrypted-bitcoin-s-seed.json"
|
||||
val seedPath = Files.createTempDirectory("key-manager-example").resolve(WalletStorage.ENCRYPTED_SEED_FILE_NAME)
|
||||
// seedPath: Path = /var/folders/fg/scntn26d4h55x96zc456l0r40000gn/T/key-manager-example171839988051633638/encrypted-bitcoin-s-seed.json
|
||||
|
||||
//let's create a native segwit key manager
|
||||
val purpose = HDPurposes.SegWit
|
||||
// purpose: HDPurpose = m/84'
|
||||
|
||||
//let's choose regtest as our network
|
||||
val network = RegTest
|
||||
// network: RegTest.type = RegTest
|
||||
|
||||
val kmParams = KeyManagerParams(seedPath, purpose, network)
|
||||
// kmParams: KeyManagerParams = KeyManagerParams(/var/folders/fg/scntn26d4h55x96zc456l0r40000gn/T/key-manager-example171839988051633638/encrypted-bitcoin-s-seed.json,m/84',RegTest)
|
||||
|
||||
val aesPasswordOpt = Some(AesPassword.fromString("password"))
|
||||
// aesPasswordOpt: Some[AesPassword] = Some(Masked(AesPassword))
|
||||
|
||||
val km = BIP39KeyManager.initializeWithMnemonic(aesPasswordOpt, mnemonic, None, kmParams)
|
||||
// km: Either[KeyManagerInitializeError, BIP39KeyManager] = Right(org.bitcoins.keymanager.bip39.BIP39KeyManager@1cbb44ab)
|
||||
|
||||
val rootXPub = km.right.get.getRootXPub
|
||||
// rootXPub: ExtPublicKey = vpub5SLqN2bLY4WeYbzqd1Co9uY8noP4gBYJrKbsJfqgTNUZKUWxPaZih6ieTgVxFJvvWh2Ac5MP2GnQckBhDdRbi3gCw3uyZELkxrZSvBmenRu
|
||||
|
||||
println(rootXPub)
|
||||
// vpub5SLqN2bLY4WeYbzqd1Co9uY8noP4gBYJrKbsJfqgTNUZKUWxPaZih6ieTgVxFJvvWh2Ac5MP2GnQckBhDdRbi3gCw3uyZELkxrZSvBmenRu
|
||||
```
|
||||
|
||||
Which should print something that looks like this
|
||||
|
||||
`vpub5SLqN2bLY4WeXxMqwJHJFBEwxSscGB2uDUnsTS3edVjZEwTrQDFDNqoR2xLqARQPabGaXsHSTenTRcqm2EnB9MpuC4vSk3LqSgNmGGZtuq7`
|
||||
|
||||
which is a native segwit `ExtPubKey` for the regtest network!
|
||||
|
||||
You can always change the `network` or `purpose` to support different things. You do _not_ need to initialize the key manager
|
||||
again after initializing it once. You can use the same `mnemonic` for different networks, which you control `KeyManagerParams`.
|
||||
|
||||
```scala
|
||||
//let's create a nested segwit key manager for mainnet
|
||||
val mainnetKmParams = KeyManagerParams(seedPath, HDPurposes.SegWit, MainNet)
|
||||
// mainnetKmParams: KeyManagerParams = KeyManagerParams(/var/folders/fg/scntn26d4h55x96zc456l0r40000gn/T/key-manager-example171839988051633638/encrypted-bitcoin-s-seed.json,m/84',MainNet)
|
||||
|
||||
//we do not need to all `initializeWithMnemonic()` again as we have saved the seed to dis
|
||||
val mainnetKeyManager = BIP39KeyManager.fromMnemonic(mnemonic, mainnetKmParams, None, Instant.now, false)
|
||||
// mainnetKeyManager: BIP39KeyManager = org.bitcoins.keymanager.bip39.BIP39KeyManager@3e293f84
|
||||
|
||||
val mainnetXpub = mainnetKeyManager.getRootXPub
|
||||
// mainnetXpub: ExtPublicKey = zpub6jftahH18ngZwnmJxSMHzFv9UfxrSfWJWmgkSFRDyPz5XsmsQDDyBMMCYWLJEwYc9FVPbyjcrvCc9tdx6R5etzQcQQhftsci3kp2UZVBxgn
|
||||
|
||||
println(mainnetXpub)
|
||||
// zpub6jftahH18ngZwnmJxSMHzFv9UfxrSfWJWmgkSFRDyPz5XsmsQDDyBMMCYWLJEwYc9FVPbyjcrvCc9tdx6R5etzQcQQhftsci3kp2UZVBxgn
|
||||
```
|
||||
|
||||
Which gives us something that looks like this
|
||||
|
||||
`zpub6jftahH18ngZw98KGjRo5XcxeKTQ2eztsvskb1dC9XF5TLimQquTs6Ry7nBBA425D9joXmfgJJCexmJ1u2SELJZJfRi95gcnXadLpZzYb5c`
|
||||
|
||||
which is a p2sh wrapped segwit `ExtPubKey` for the bitcoin main network!
|
||||
|
||||
#### Creating a key manager from existing mnemonic
|
||||
|
||||
To create a `KeyManager` from existing mnemonic you need to specify the `seedPath` and then construct the `KeyManagerParams` that you would like.
|
||||
|
||||
Finally you call `KeyManager.fromParams()` that reads the mnemonic from disk and create's the key manager
|
92
website/versioned_docs/version-1.9.6/secp256k1/secp256k1.md
Normal file
92
website/versioned_docs/version-1.9.6/secp256k1/secp256k1.md
Normal file
|
@ -0,0 +1,92 @@
|
|||
---
|
||||
id: version-1.9.6-secp256k1
|
||||
title: Secp256k1
|
||||
original_id: secp256k1
|
||||
---
|
||||
|
||||
[Libsecp256k1](https://github.com/bitcoin-core/secp256k1) is used to preform cryptographic operations on the secp256k1 curve.
|
||||
This is the curve that bitcoin uses. There is a _signficant_ speedup when using this library compared to java crypto libraries
|
||||
like bouncy castle.
|
||||
|
||||
In bitcoin-s, we support native binaries for libsecp256k1
|
||||
|
||||
1. [linux 32 bit](../../secp256k1jni/natives/linux_32)
|
||||
2. [linux 64 bit](../../secp256k1jni/natives/linux_64)
|
||||
3. [mac osx 64 bit](../../secp256k1jni/natives/osx_64)
|
||||
4. [windows 64 bit](../../secp256k1jni/natives/windows_64)
|
||||
|
||||
Bitcoin-s uses a zero dependency library called [`native-lib-loader`](https://github.com/scijava/native-lib-loader).
|
||||
That does the appropriate loading of the library onto your classpath to be accessed.
|
||||
|
||||
### Using libsecp256k1
|
||||
|
||||
To tell if you have access to libsecp256k1 you can do the following
|
||||
|
||||
|
||||
```scala
|
||||
val isEnabled = org.bitcoin.Secp256k1Context.isEnabled()
|
||||
|
||||
println(s"Secp256k1Context.isEnabled=${isEnabled}")
|
||||
```
|
||||
|
||||
If libsecp256k1 is enabled, you can use [NativeSecp256k1](/api/org/bitcoin/NativeSecp256k1)
|
||||
with static method defined in the class.
|
||||
|
||||
|
||||
```scala
|
||||
val privKey = ECPrivateKey.freshPrivateKey
|
||||
val pubKey = privKey.publicKey
|
||||
val dataToSign = DoubleSha256Digest.empty
|
||||
|
||||
val signature = NativeSecp256k1.sign(dataToSign.bytes.toArray, privKey.bytes.toArray)
|
||||
|
||||
val verify = NativeSecp256k1.verify(dataToSign.bytes.toArray, signature, pubKey.bytes.toArray)
|
||||
|
||||
println(s"Verified with NativeSecp256k1 signature=${verify}")
|
||||
|
||||
//you can also just directly sign with the ECKey interface:
|
||||
val signature2 = privKey.sign(dataToSign)
|
||||
|
||||
val verified2 = pubKey.verify(dataToSign, signature2)
|
||||
|
||||
println(s"Verified with NativeSecp256k1 again=${verified2}")
|
||||
```
|
||||
|
||||
### When libsecp256k1 isn't available, or you want to turn it off
|
||||
|
||||
There are two reasons you wouldn't want to use libsecp256k1
|
||||
|
||||
1. You don't trust the pre-compiled binaries we are using
|
||||
2. Your OS/arch is not supported
|
||||
|
||||
There are two ways you can circumvent libsecp256k1
|
||||
|
||||
1. Set `DISABLE_SECP256K1=true` in your environment variables. This will force `CryptoContext.default` to return false which will make Bitcoin-S act like `Secp256k1Context.isEnabled()` has returned false.
|
||||
2. Call Bouncy castle methods in `ECKey`.
|
||||
|
||||
Here is an example of calling bouncy castle methods in `ECKey`
|
||||
|
||||
```scala
|
||||
val privKey = ECPrivateKey.freshPrivateKey
|
||||
// privKey: ECPrivateKey = Masked(ECPrivateKey)
|
||||
// calls bouncy castle indirectly via CryptoContext
|
||||
val publicKey = privKey.publicKey
|
||||
// publicKey: ECPublicKey = ECPublicKey(021df4f25c9c004169d38e789b71e8fd07f5fbd9ccf73ac7d5df7d4ed216fcc392)
|
||||
val dataToSign = DoubleSha256Digest.empty
|
||||
// dataToSign: DoubleSha256Digest = DoubleSha256Digest(0000000000000000000000000000000000000000000000000000000000000000)
|
||||
|
||||
// calls bouncy castle indirectly via CryptoContext
|
||||
val signature = privKey.sign(dataToSign.bytes)
|
||||
// signature: ECDigitalSignature = ECDigitalSignature(30450221008d01381b03e1a64d3d1b4fe58d736c5001800f11671920e4e5954a6cd2b45ae402205a1322a5c30ebfa2de59b76fa4525a036c29df8421b836b36243df2904fdd748)
|
||||
|
||||
// calls bouncy castle indirectly via CryptoContext
|
||||
val verified = publicKey.verify(dataToSign.bytes, signature)
|
||||
// verified: Boolean = true
|
||||
|
||||
println(s"Verified with bouncy castle=${verified}")
|
||||
// Verified with bouncy castle=true
|
||||
```
|
||||
|
||||
### Building libsecp256k1
|
||||
|
||||
[See instructions here](add-to-jni.md#adding-to-bitcoin-s)
|
|
@ -1,4 +1,5 @@
|
|||
[
|
||||
"1.9.6",
|
||||
"1.9.5",
|
||||
"1.9.4",
|
||||
"1.9.3",
|
||||
|
|
Loading…
Add table
Reference in a new issue