bsv-sdk 0.2.0 → 0.2.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -0
- data/lib/bsv/primitives/private_key.rb +1 -2
- data/lib/bsv/script/script.rb +4 -0
- data/lib/bsv/transaction/beef.rb +7 -7
- data/lib/bsv/transaction/transaction.rb +8 -14
- data/lib/bsv/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d8f24ed29fd0a8beb572b3737c3bbfaba5bf939c5fe20d485306e5e4374587c1
|
|
4
|
+
data.tar.gz: 53746a1cdad1370718892805b76c763fbe58a73ef057bd65a1eaa4b1b120c7bd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 93590d116e66151f51af5167bb405b2d91cd2997f685fad0d684cd07f5231aa1387d57d71852e5464f3f222d1b471534d22ab6633c75d188f9080c1718f834a0
|
|
7
|
+
data.tar.gz: b26e9a26837af3ce9426311050c0e2fbbdaac9ce4d04a7987c123ef189ec6528e779c69bd7b77605e25df70c1510327a71b7843151f50eb710b2b63a788eeae2
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,22 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.2.1] - 2026-03-07
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- Truncated OP_PUSHDATA1/2/4 scripts now raise `ArgumentError` instead of crashing with `TypeError`
|
|
13
|
+
- `Transaction#to_beef` uses `merge_bump` to correctly handle multiple ancestors at the same block height
|
|
14
|
+
- `PrivateKey#derive_child` uses `BN.mod_add` instead of Integer roundtrip for modular addition
|
|
15
|
+
- Fixed txid byte-order documentation (display order, not internal order)
|
|
16
|
+
|
|
17
|
+
### Testing
|
|
18
|
+
|
|
19
|
+
- FORKID enforcement spec verifying interpreter rejects signatures without SIGHASH_FORKID
|
|
20
|
+
- ExtendedKey fingerprint chain integrity across 3-generation derivation
|
|
21
|
+
- Mnemonic entropy round-trip across all 5 valid entropy lengths
|
|
22
|
+
- BEEF spec for multiple ancestors at the same block height
|
|
23
|
+
|
|
8
24
|
## [0.2.0] - 2026-03-07
|
|
9
25
|
|
|
10
26
|
### Added
|
|
@@ -158,8 +158,7 @@ module BSV
|
|
|
158
158
|
shared = derive_shared_secret(public_key)
|
|
159
159
|
hmac = Digest.hmac_sha256(shared.compressed, invoice_number.encode('UTF-8'))
|
|
160
160
|
hmac_bn = OpenSSL::BN.new(hmac.unpack1('H*'), 16)
|
|
161
|
-
|
|
162
|
-
PrivateKey.new(OpenSSL::BN.new(child_bn.to_s))
|
|
161
|
+
PrivateKey.new(@bn.mod_add(hmac_bn, Curve::N))
|
|
163
162
|
end
|
|
164
163
|
|
|
165
164
|
# Sign a 32-byte hash using deterministic ECDSA (RFC 6979).
|
data/lib/bsv/script/script.rb
CHANGED
|
@@ -391,22 +391,26 @@ module BSV
|
|
|
391
391
|
pos += 1
|
|
392
392
|
|
|
393
393
|
if opcode.positive? && opcode <= 0x4b
|
|
394
|
+
raise ArgumentError, "truncated script: need #{opcode} data bytes at offset #{pos}" if pos + opcode > raw.bytesize
|
|
394
395
|
data = raw.byteslice(pos, opcode)
|
|
395
396
|
pos += opcode
|
|
396
397
|
result << Chunk.new(opcode: opcode, data: data)
|
|
397
398
|
elsif opcode == Opcodes::OP_PUSHDATA1
|
|
399
|
+
raise ArgumentError, "truncated script: OP_PUSHDATA1 missing length byte at offset #{pos}" if pos >= raw.bytesize
|
|
398
400
|
len = raw.getbyte(pos)
|
|
399
401
|
pos += 1
|
|
400
402
|
data = raw.byteslice(pos, len)
|
|
401
403
|
pos += len
|
|
402
404
|
result << Chunk.new(opcode: opcode, data: data)
|
|
403
405
|
elsif opcode == Opcodes::OP_PUSHDATA2
|
|
406
|
+
raise ArgumentError, "truncated script: OP_PUSHDATA2 needs 2 length bytes at offset #{pos}" if pos + 2 > raw.bytesize
|
|
404
407
|
len = raw.byteslice(pos, 2).unpack1('v')
|
|
405
408
|
pos += 2
|
|
406
409
|
data = raw.byteslice(pos, len)
|
|
407
410
|
pos += len
|
|
408
411
|
result << Chunk.new(opcode: opcode, data: data)
|
|
409
412
|
elsif opcode == Opcodes::OP_PUSHDATA4
|
|
413
|
+
raise ArgumentError, "truncated script: OP_PUSHDATA4 needs 4 length bytes at offset #{pos}" if pos + 4 > raw.bytesize
|
|
410
414
|
len = raw.byteslice(pos, 4).unpack1('V')
|
|
411
415
|
pos += 4
|
|
412
416
|
data = raw.byteslice(pos, len)
|
data/lib/bsv/transaction/beef.rb
CHANGED
|
@@ -63,7 +63,7 @@ module BSV
|
|
|
63
63
|
|
|
64
64
|
# The transaction ID for this entry.
|
|
65
65
|
#
|
|
66
|
-
# @return [String, nil] 32-byte txid in
|
|
66
|
+
# @return [String, nil] 32-byte txid in display byte order
|
|
67
67
|
def txid
|
|
68
68
|
case @format
|
|
69
69
|
when FORMAT_TXID_ONLY
|
|
@@ -210,7 +210,7 @@ module BSV
|
|
|
210
210
|
|
|
211
211
|
# Find a transaction in the bundle by its transaction ID.
|
|
212
212
|
#
|
|
213
|
-
# @param txid [String] 32-byte txid in
|
|
213
|
+
# @param txid [String] 32-byte txid in display byte order
|
|
214
214
|
# @return [Transaction, nil] the matching transaction, or nil
|
|
215
215
|
def find_transaction(txid)
|
|
216
216
|
@transactions.each do |beef_tx|
|
|
@@ -221,7 +221,7 @@ module BSV
|
|
|
221
221
|
|
|
222
222
|
# Find the merkle path (BUMP) for a transaction by its txid.
|
|
223
223
|
#
|
|
224
|
-
# @param txid [String] 32-byte txid in
|
|
224
|
+
# @param txid [String] 32-byte txid in display byte order
|
|
225
225
|
# @return [MerklePath, nil] the merkle path, or nil if not found
|
|
226
226
|
def find_bump(txid)
|
|
227
227
|
bt = @transactions.find { |entry| entry.txid == txid && entry.format == FORMAT_RAW_TX_AND_BUMP }
|
|
@@ -232,7 +232,7 @@ module BSV
|
|
|
232
232
|
|
|
233
233
|
# Find a transaction with all source_transactions wired for signing.
|
|
234
234
|
#
|
|
235
|
-
# @param txid [String] 32-byte txid in
|
|
235
|
+
# @param txid [String] 32-byte txid in display byte order
|
|
236
236
|
# @return [Transaction, nil] the transaction with wired inputs, or nil
|
|
237
237
|
def find_transaction_for_signing(txid)
|
|
238
238
|
tx = find_transaction(txid)
|
|
@@ -245,7 +245,7 @@ module BSV
|
|
|
245
245
|
# Find a transaction and recursively wire its ancestry (source transactions
|
|
246
246
|
# and merkle paths) for atomic proof validation.
|
|
247
247
|
#
|
|
248
|
-
# @param txid [String] 32-byte txid in
|
|
248
|
+
# @param txid [String] 32-byte txid in display byte order
|
|
249
249
|
# @return [Transaction, nil] the transaction with full proof tree, or nil
|
|
250
250
|
def find_atomic_transaction(txid)
|
|
251
251
|
tx = find_transaction(txid)
|
|
@@ -381,7 +381,7 @@ module BSV
|
|
|
381
381
|
|
|
382
382
|
# Convert a transaction entry to TXID-only format.
|
|
383
383
|
#
|
|
384
|
-
# @param txid [String] 32-byte txid in
|
|
384
|
+
# @param txid [String] 32-byte txid in display byte order
|
|
385
385
|
# @return [BeefTx, nil] the converted entry, or nil if not found
|
|
386
386
|
def make_txid_only(txid)
|
|
387
387
|
idx = @transactions.index { |bt| bt.txid == txid }
|
|
@@ -557,7 +557,7 @@ module BSV
|
|
|
557
557
|
|
|
558
558
|
# Wire inputs to ancestors already in the map (BEEF is dependency-ordered)
|
|
559
559
|
beef_tx.transaction.inputs.each do |input|
|
|
560
|
-
# prev_tx_id is
|
|
560
|
+
# prev_tx_id is wire byte order; txid keys are display byte order (reversed)
|
|
561
561
|
source = tx_map[input.prev_tx_id.reverse]
|
|
562
562
|
input.source_transaction = source if source
|
|
563
563
|
end
|
|
@@ -296,25 +296,15 @@ module BSV
|
|
|
296
296
|
# @return [String] raw BEEF V2 binary
|
|
297
297
|
def to_beef
|
|
298
298
|
beef = Beef.new
|
|
299
|
-
bump_map = {}
|
|
300
299
|
ancestors = collect_ancestors
|
|
301
300
|
|
|
302
301
|
ancestors.each do |tx|
|
|
303
|
-
# Collect BUMPs
|
|
304
|
-
if tx.merkle_path
|
|
305
|
-
height = tx.merkle_path.block_height
|
|
306
|
-
unless bump_map.key?(height)
|
|
307
|
-
bump_map[height] = beef.bumps.length
|
|
308
|
-
beef.bumps << tx.merkle_path
|
|
309
|
-
end
|
|
310
|
-
end
|
|
311
|
-
|
|
312
|
-
# Add transaction in dependency order
|
|
313
302
|
entry = if tx.merkle_path
|
|
303
|
+
bump_idx = beef.merge_bump(tx.merkle_path)
|
|
314
304
|
Beef::BeefTx.new(
|
|
315
305
|
format: Beef::FORMAT_RAW_TX_AND_BUMP,
|
|
316
306
|
transaction: tx,
|
|
317
|
-
bump_index:
|
|
307
|
+
bump_index: bump_idx
|
|
318
308
|
)
|
|
319
309
|
else
|
|
320
310
|
Beef::BeefTx.new(
|
|
@@ -356,9 +346,13 @@ module BSV
|
|
|
356
346
|
|
|
357
347
|
# --- Transaction ID ---
|
|
358
348
|
|
|
359
|
-
# Compute the transaction ID (double-SHA-256 of the serialised tx, reversed).
|
|
349
|
+
# Compute the transaction ID (double-SHA-256 of the serialised tx, byte-reversed).
|
|
350
|
+
#
|
|
351
|
+
# Returns display byte order (reversed from the natural hash).
|
|
352
|
+
# Compare with {TransactionInput#prev_tx_id} which stores wire byte
|
|
353
|
+
# order (natural hash). Use +.reverse+ to convert between the two.
|
|
360
354
|
#
|
|
361
|
-
# @return [String] 32-byte transaction ID in
|
|
355
|
+
# @return [String] 32-byte transaction ID in display byte order
|
|
362
356
|
def txid
|
|
363
357
|
BSV::Primitives::Digest.sha256d(to_binary).reverse
|
|
364
358
|
end
|
data/lib/bsv/version.rb
CHANGED