bsv-sdk 0.13.0 → 0.15.0
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 +53 -0
- data/README.md +14 -2
- data/lib/bsv/auth/certificate.rb +1 -1
- data/lib/bsv/network/whats_on_chain.rb +41 -2
- data/lib/bsv/primitives/base58.rb +2 -1
- data/lib/bsv/primitives/curve.rb +37 -12
- data/lib/bsv/primitives/ecdsa.rb +4 -4
- data/lib/bsv/primitives/openssl_ec_shim.rb +32 -5
- data/lib/bsv/primitives/private_key.rb +2 -2
- data/lib/bsv/primitives/public_key.rb +1 -1
- data/lib/bsv/primitives/schnorr.rb +4 -4
- data/lib/bsv/primitives/secp256k1.rb +4 -595
- data/lib/bsv/primitives/signature.rb +2 -0
- data/lib/bsv/primitives/signed_message.rb +6 -5
- data/lib/bsv/secp256k1_native.bundle +0 -0
- data/lib/bsv/transaction/transaction.rb +52 -7
- data/lib/bsv/transaction/verification_error.rb +11 -0
- data/lib/bsv/version.rb +1 -1
- data/lib/bsv-sdk.rb +1 -2
- metadata +16 -5
- data/lib/bsv/messages.rb +0 -16
- data/lib/bsv/wallet/insufficient_funds_error.rb +0 -15
- data/lib/bsv/wallet/wallet.rb +0 -120
- data/lib/bsv/wallet.rb +0 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 27489947d80a203e32fad08b53cfee4edabca7df61f244dff2ca12c5fa45e261
|
|
4
|
+
data.tar.gz: d3bd5ead19a4fa67f4111e9bd3a203a1cad3c083ad4b8e174ee114b5b7fdb4bd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5ebdd5176602d584debb675d470dc31079cb16a29bb858c806123227efe03783c7c7f77eccf38174e254b7579fae9bad71d17c9e71791c21a694653647e15ad6
|
|
7
|
+
data.tar.gz: cedddebaec0eeb9c2fa037af4227ad7307492146c2b4dc18d3a7f4dfc7f3179c20428245424d0a8542db97bbad08831a334d7821f17fd3c05264d38289271552
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,59 @@ All notable changes to the `bsv-sdk` gem are documented here.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
|
|
6
6
|
and this gem adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## 0.15.0 — 2026-04-29
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Extracted secp256k1 elliptic curve operations to the standalone
|
|
12
|
+
`secp256k1-native` gem, with an optional native C extension providing
|
|
13
|
+
~22x speedup for field, scalar, and Jacobian point operations (#648)
|
|
14
|
+
- Native C extension scaffold with field arithmetic, scalar arithmetic,
|
|
15
|
+
and Jacobian point operations (#627, #628, #629, #630, #631)
|
|
16
|
+
- Constant-time Montgomery ladder with branchless conditional swap for
|
|
17
|
+
scalar multiplication; `mul` is now constant-time by default, with
|
|
18
|
+
`mul_vt` available for variable-time use cases (#641, #653)
|
|
19
|
+
- Wycheproof Bitcoin ECDSA test vectors (463 cases) with explicit
|
|
20
|
+
categorisation of high-S malleability cases as mathematically valid
|
|
21
|
+
but policy-rejected — documenting the layer separation between
|
|
22
|
+
ECDSA verification and Bitcoin's low-S enforcement (#652)
|
|
23
|
+
- Wycheproof standard ECDSA test vectors (474 cases), RFC 6979
|
|
24
|
+
compliance suite, and secp256k1 field/scalar/point compliance
|
|
25
|
+
examples (#636, #637, #638)
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
- Carry overflow in schoolbook multiplication (L2) and branchless
|
|
29
|
+
borrow extraction in field reduction (#631)
|
|
30
|
+
- Gemspec version floor, docstring, and variable name corrections
|
|
31
|
+
from PR review (#653)
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
- Replaced `BN` hex intermediaries with direct binary construction
|
|
35
|
+
for improved performance (#622)
|
|
36
|
+
- Binary byte comparison in `SignedMessage` verification (#624)
|
|
37
|
+
|
|
38
|
+
## 0.14.0 — 2026-04-22
|
|
39
|
+
|
|
40
|
+
### Added
|
|
41
|
+
- `BSV::Network::WhatsOnChain` expanded with `current_height`,
|
|
42
|
+
`get_block_header(height)`, and `valid_root_for_height?(root, height)` —
|
|
43
|
+
a single WhatsOnChain instance now serves as a complete chain data source
|
|
44
|
+
(#596)
|
|
45
|
+
- BEEF-based SPV verification conformance tests (#607)
|
|
46
|
+
|
|
47
|
+
### Changed
|
|
48
|
+
- `Transaction#verify` now raises `VerificationError` for all failure modes:
|
|
49
|
+
`:script_failure` (wraps `ScriptError` with cause chaining),
|
|
50
|
+
`:missing_source` (replaces `ArgumentError`), `:invalid_merkle_proof`,
|
|
51
|
+
`:insufficient_fee`, and `:output_overflow`. Code rescuing `ArgumentError`
|
|
52
|
+
or `ScriptError` from `verify` must switch to `VerificationError` (#608)
|
|
53
|
+
- Removed dead code: `BSV::Wallet::Wallet` (superseded by bsv-wallet gem's
|
|
54
|
+
`Client`), `BSV::Messages` (unused re-export alias), and duplicate
|
|
55
|
+
`BSV::Wallet::InsufficientFundsError` (#594)
|
|
56
|
+
|
|
57
|
+
### Fixed
|
|
58
|
+
- WhatsOnChain `valid_root_for_height?` YARD doc now correctly documents
|
|
59
|
+
that 404 returns `false` rather than raising
|
|
60
|
+
|
|
8
61
|
## 0.13.0 — 2026-04-21
|
|
9
62
|
|
|
10
63
|
### Added
|
data/README.md
CHANGED
|
@@ -34,7 +34,9 @@ These are maintained under the BSV Blockchain organisation and backed by the Bit
|
|
|
34
34
|
|
|
35
35
|
The BSV Blockchain Libraries Project aims to structure and maintain a middleware layer of the BSV Blockchain technology stack. By facilitating the development and maintenance of core libraries, it serves as an essential toolkit for developers looking to build on the BSV Blockchain.
|
|
36
36
|
|
|
37
|
-
This Ruby SDK brings maximum compatibility with the official SDK family to the Ruby ecosystem. It was born from a practical need: building an attestation gem ([bsv-attest](https://rubygems.org/gems/bsv-attest)) required a complete, idiomatic Ruby implementation of BSV primitives, script handling, and transaction construction.
|
|
37
|
+
This Ruby SDK brings maximum compatibility with the official SDK family to the Ruby ecosystem. It was born from a practical need: building an attestation gem ([bsv-attest](https://rubygems.org/gems/bsv-attest)) required a complete, idiomatic Ruby implementation of BSV primitives, script handling, and transaction construction.
|
|
38
|
+
|
|
39
|
+
Elliptic curve operations (secp256k1) are provided by the [`secp256k1-native`](https://github.com/sgbett/secp256k1-native) gem, which was originally part of this library and has been extracted as a standalone dependency. This is a custom implementation ported from the TypeScript reference SDK — it does not wrap `libsecp256k1`. It includes a pure Ruby implementation with an optional native C extension for constant-time field arithmetic and performance. OpenSSL is used only for hashing, HMAC, and symmetric encryption.
|
|
38
40
|
|
|
39
41
|
<!-- TODO: Update bsv-attest link once gem documentation is published (see #48) -->
|
|
40
42
|
|
|
@@ -59,6 +61,16 @@ Or install directly:
|
|
|
59
61
|
gem install bsv-sdk
|
|
60
62
|
```
|
|
61
63
|
|
|
64
|
+
### Native C Extension (Recommended)
|
|
65
|
+
|
|
66
|
+
The SDK depends on [`secp256k1-native`](https://github.com/sgbett/secp256k1-native) for elliptic curve operations. It works out of the box in pure Ruby, but compiling the optional C extension is strongly recommended — it provides constant-time field arithmetic, which protects against timing side-channel attacks on private key operations:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
cd $(bundle show secp256k1-native) && bundle exec rake compile
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
This requires a C99 compiler with `__uint128_t` support (GCC or Clang on macOS/Linux). If compilation is not possible, the SDK falls back to pure Ruby automatically — but the pure Ruby path does not guarantee constant-time execution.
|
|
73
|
+
|
|
62
74
|
### Basic Usage
|
|
63
75
|
|
|
64
76
|
Create and sign a P2PKH transaction:
|
|
@@ -101,7 +113,7 @@ puts tx.to_hex
|
|
|
101
113
|
|
|
102
114
|
## Features & Deliverables
|
|
103
115
|
|
|
104
|
-
- **Cryptographic Primitives** — ECDSA signing with RFC 6979 deterministic nonces, Schnorr signatures, ECIES encryption/decryption, Bitcoin Signed Messages. Elliptic curve operations
|
|
116
|
+
- **Cryptographic Primitives** — ECDSA signing with RFC 6979 deterministic nonces, Schnorr signatures, ECIES encryption/decryption, Bitcoin Signed Messages. Elliptic curve operations are provided by the [`secp256k1-native`](https://github.com/sgbett/secp256k1-native) gem — a pure Ruby secp256k1 implementation with an optional C extension (~22× speedup).
|
|
105
117
|
- **Key Management** — BIP-32 HD key derivation, BIP-39 mnemonic generation (12/24-word phrases), WIF import/export, Base58Check encoding/decoding.
|
|
106
118
|
- **Script Layer** — Complete opcode set, script parsing and serialisation, type detection and predicates (`p2pkh?`, `p2pk?`, `p2sh?`, `multisig?`, `op_return?`), data extraction (pubkey hashes, script hashes, addresses), and a fluent builder API.
|
|
107
119
|
- **Script Templates** — Ready-made locking and unlocking script generators for P2PKH, P2PK, P2MS (multisig), and OP_RETURN.
|
data/lib/bsv/auth/certificate.rb
CHANGED
|
@@ -176,7 +176,7 @@ module BSV
|
|
|
176
176
|
def verify(verifier_wallet = nil)
|
|
177
177
|
raise ArgumentError, 'certificate has no signature to verify' if @signature.nil? || @signature.empty?
|
|
178
178
|
|
|
179
|
-
verifier_wallet ||= BSV::Wallet::Client.new('anyone', storage: BSV::Wallet::Store::Memory.new)
|
|
179
|
+
verifier_wallet ||= BSV::Wallet::Client.new('anyone', storage: BSV::Wallet::Store::Memory.new, allow_memory_store: true)
|
|
180
180
|
preimage = to_binary(include_signature: false)
|
|
181
181
|
sig_bytes = [@signature].pack('H*').unpack('C*')
|
|
182
182
|
|
|
@@ -5,8 +5,11 @@ module BSV
|
|
|
5
5
|
# WhatsOnChain chain data provider for reading transactions and UTXOs
|
|
6
6
|
# from the BSV network.
|
|
7
7
|
#
|
|
8
|
-
# Any object responding to #fetch_utxos(address)
|
|
9
|
-
# #fetch_transaction(txid)
|
|
8
|
+
# Any object responding to #fetch_utxos(address),
|
|
9
|
+
# #fetch_transaction(txid), #current_height,
|
|
10
|
+
# #get_block_header(height), and optionally
|
|
11
|
+
# #valid_root_for_height?(root_hex, height) can serve as a chain
|
|
12
|
+
# data source;
|
|
10
13
|
# this class implements that contract by delegating to
|
|
11
14
|
# Protocols::WoCREST.
|
|
12
15
|
#
|
|
@@ -62,6 +65,42 @@ module BSV
|
|
|
62
65
|
BSV::Transaction::Transaction.from_hex(result.data)
|
|
63
66
|
end
|
|
64
67
|
|
|
68
|
+
# Return the current blockchain height.
|
|
69
|
+
# @return [Integer]
|
|
70
|
+
# @raise [BSV::Network::ChainProviderError] on network or API error
|
|
71
|
+
def current_height
|
|
72
|
+
result = @protocol.call(:current_height)
|
|
73
|
+
raise_on_error(result)
|
|
74
|
+
|
|
75
|
+
result.data
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Fetch the block header for a given height.
|
|
79
|
+
# @param height [Integer] block height
|
|
80
|
+
# @return [Hash] parsed block header JSON
|
|
81
|
+
# @raise [BSV::Network::ChainProviderError] on network or API error
|
|
82
|
+
def get_block_header(height)
|
|
83
|
+
result = @protocol.call(:get_block_header, height)
|
|
84
|
+
raise_on_error(result)
|
|
85
|
+
|
|
86
|
+
result.data
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Verify that a merkle root is valid for the given block height.
|
|
90
|
+
# Returns +false+ when the block is not found (404); raises on other errors.
|
|
91
|
+
# @param root [String] expected merkle root as hex
|
|
92
|
+
# @param height [Integer] block height
|
|
93
|
+
# @return [Boolean]
|
|
94
|
+
# @raise [BSV::Network::ChainProviderError] on network or non-404 API error
|
|
95
|
+
def valid_root_for_height?(root, height)
|
|
96
|
+
result = @protocol.call(:valid_root, root, height)
|
|
97
|
+
return false if result.not_found?
|
|
98
|
+
|
|
99
|
+
raise_on_error(result)
|
|
100
|
+
|
|
101
|
+
result.data == true
|
|
102
|
+
end
|
|
103
|
+
|
|
65
104
|
private
|
|
66
105
|
|
|
67
106
|
# Translates a non-success Protocol result into a raised ChainProviderError.
|
|
@@ -42,6 +42,7 @@ module BSV
|
|
|
42
42
|
bytes.each_byte { |b| b.zero? ? leading_zeros += 1 : break }
|
|
43
43
|
|
|
44
44
|
# Convert to big integer and repeatedly divide by 58
|
|
45
|
+
# C-backed hex conversion — 10x faster than pure-Ruby byte shifting; not a porting artefact.
|
|
45
46
|
n = bytes.unpack1('H*').to_i(16)
|
|
46
47
|
result = +''
|
|
47
48
|
while n.positive?
|
|
@@ -78,7 +79,7 @@ module BSV
|
|
|
78
79
|
n = (n * BASE) + digit
|
|
79
80
|
end
|
|
80
81
|
|
|
81
|
-
# Convert integer to bytes
|
|
82
|
+
# Convert integer to bytes — C-backed hex round-trip is the fastest pure-Ruby integer→bytes path.
|
|
82
83
|
hex = n.zero? ? '' : n.to_s(16)
|
|
83
84
|
hex = "0#{hex}" if hex.length.odd?
|
|
84
85
|
result = [hex].pack('H*')
|
data/lib/bsv/primitives/curve.rb
CHANGED
|
@@ -25,10 +25,11 @@ module BSV
|
|
|
25
25
|
|
|
26
26
|
module_function
|
|
27
27
|
|
|
28
|
-
# Multiply the generator point by a scalar (
|
|
28
|
+
# Multiply the generator point by a scalar (constant-time).
|
|
29
29
|
#
|
|
30
|
-
#
|
|
31
|
-
# scalars
|
|
30
|
+
# Uses the Montgomery ladder by default, matching OpenSSL convention.
|
|
31
|
+
# Safe for both secret and public scalars. For explicit variable-time
|
|
32
|
+
# multiplication of public scalars, use {multiply_generator_vt}.
|
|
32
33
|
#
|
|
33
34
|
# @param scalar_bn [OpenSSL::BN] the scalar multiplier
|
|
34
35
|
# @return [OpenSSL::PKey::EC::Point] the resulting curve point
|
|
@@ -38,19 +39,31 @@ module BSV
|
|
|
38
39
|
|
|
39
40
|
# Multiply the generator point by a secret scalar (constant-time).
|
|
40
41
|
#
|
|
41
|
-
#
|
|
42
|
-
#
|
|
42
|
+
# Alias for {multiply_generator} — retained for backward compatibility
|
|
43
|
+
# and expressiveness.
|
|
43
44
|
#
|
|
44
45
|
# @param scalar_bn [OpenSSL::BN] the secret scalar multiplier
|
|
45
46
|
# @return [OpenSSL::PKey::EC::Point] the resulting curve point
|
|
46
47
|
def multiply_generator_ct(scalar_bn)
|
|
47
|
-
G.
|
|
48
|
+
G.mul(scalar_bn)
|
|
48
49
|
end
|
|
49
50
|
|
|
50
|
-
# Multiply
|
|
51
|
+
# Multiply the generator point by a public scalar (variable-time, wNAF).
|
|
51
52
|
#
|
|
52
|
-
#
|
|
53
|
-
#
|
|
53
|
+
# Faster than {multiply_generator} but leaks timing information about
|
|
54
|
+
# the scalar. Use only for public scalars (e.g. signature verification).
|
|
55
|
+
#
|
|
56
|
+
# @param scalar_bn [OpenSSL::BN] the public scalar multiplier
|
|
57
|
+
# @return [OpenSSL::PKey::EC::Point] the resulting curve point
|
|
58
|
+
def multiply_generator_vt(scalar_bn)
|
|
59
|
+
G.mul_vt(scalar_bn)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Multiply an arbitrary curve point by a scalar (constant-time).
|
|
63
|
+
#
|
|
64
|
+
# Uses the Montgomery ladder by default, matching OpenSSL convention.
|
|
65
|
+
# Safe for both secret and public scalars. For explicit variable-time
|
|
66
|
+
# multiplication of public scalars, use {multiply_point_vt}.
|
|
54
67
|
#
|
|
55
68
|
# @param point [OpenSSL::PKey::EC::Point] the point to multiply
|
|
56
69
|
# @param scalar_bn [OpenSSL::BN] the scalar multiplier
|
|
@@ -61,14 +74,26 @@ module BSV
|
|
|
61
74
|
|
|
62
75
|
# Multiply an arbitrary curve point by a secret scalar (constant-time).
|
|
63
76
|
#
|
|
64
|
-
#
|
|
65
|
-
#
|
|
77
|
+
# Alias for {multiply_point} — retained for backward compatibility
|
|
78
|
+
# and expressiveness.
|
|
66
79
|
#
|
|
67
80
|
# @param point [OpenSSL::PKey::EC::Point] the base point
|
|
68
81
|
# @param scalar_bn [OpenSSL::BN] the secret scalar multiplier
|
|
69
82
|
# @return [OpenSSL::PKey::EC::Point] the resulting curve point
|
|
70
83
|
def multiply_point_ct(point, scalar_bn)
|
|
71
|
-
point.
|
|
84
|
+
point.mul(scalar_bn)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Multiply an arbitrary curve point by a public scalar (variable-time, wNAF).
|
|
88
|
+
#
|
|
89
|
+
# Faster than {multiply_point} but leaks timing information about
|
|
90
|
+
# the scalar. Use only for public scalars (e.g. signature verification).
|
|
91
|
+
#
|
|
92
|
+
# @param point [OpenSSL::PKey::EC::Point] the point to multiply
|
|
93
|
+
# @param scalar_bn [OpenSSL::BN] the public scalar multiplier
|
|
94
|
+
# @return [OpenSSL::PKey::EC::Point] the resulting curve point
|
|
95
|
+
def multiply_point_vt(point, scalar_bn)
|
|
96
|
+
point.mul_vt(scalar_bn)
|
|
72
97
|
end
|
|
73
98
|
|
|
74
99
|
# Add two curve points together.
|
data/lib/bsv/primitives/ecdsa.rb
CHANGED
|
@@ -82,8 +82,8 @@ module BSV
|
|
|
82
82
|
u1 = ((n - e) * r_inv) % n
|
|
83
83
|
u2 = (s * r_inv) % n
|
|
84
84
|
|
|
85
|
-
p1 = Curve.
|
|
86
|
-
p2 = Curve.
|
|
85
|
+
p1 = Curve.multiply_generator_vt(u1)
|
|
86
|
+
p2 = Curve.multiply_point_vt(r_point, u2)
|
|
87
87
|
q = Curve.add_points(p1, p2)
|
|
88
88
|
|
|
89
89
|
raise ArgumentError, 'recovered point is at infinity' if q.infinity?
|
|
@@ -112,8 +112,8 @@ module BSV
|
|
|
112
112
|
u2 = (r * s_inv) % n
|
|
113
113
|
|
|
114
114
|
# R' = u1*G + u2*Q
|
|
115
|
-
point1 = Curve.
|
|
116
|
-
point2 = Curve.
|
|
115
|
+
point1 = Curve.multiply_generator_vt(u1)
|
|
116
|
+
point2 = Curve.multiply_point_vt(public_key_point, u2)
|
|
117
117
|
result_point = Curve.add_points(point1, point2)
|
|
118
118
|
|
|
119
119
|
return false if result_point.infinity?
|
|
@@ -66,6 +66,22 @@ class BSVShimECPoint
|
|
|
66
66
|
pt
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
+
# Scalar multiplication: self * scalar (constant-time, Montgomery ladder).
|
|
70
|
+
#
|
|
71
|
+
# Matches OpenSSL convention where +EC_POINT_mul+ is always constant-time.
|
|
72
|
+
# Safe for both secret and public scalars.
|
|
73
|
+
#
|
|
74
|
+
# Also supports the multi-scalar form: +mul(bns, points)+ computes
|
|
75
|
+
# <tt>bns[0]*self + bns[1]*points[0] + ...</tt>
|
|
76
|
+
# where +bns.length == points.length + 1+.
|
|
77
|
+
#
|
|
78
|
+
# @overload mul(scalar_bn)
|
|
79
|
+
# @param scalar_bn [OpenSSL::BN, Integer] the scalar multiplier
|
|
80
|
+
# @overload mul(bns, points)
|
|
81
|
+
# @param bns [Array<OpenSSL::BN>] scalars; must have +points.length + 1+ elements
|
|
82
|
+
# @param points [Array<BSVShimECPoint>] additional points
|
|
83
|
+
# @raise [NoMethodError] if +bns+ and +points+ lengths are mismatched
|
|
84
|
+
# @return [BSVShimECPoint]
|
|
69
85
|
def mul(*args)
|
|
70
86
|
if args.length == 1
|
|
71
87
|
scalar = bn_to_int(args[0])
|
|
@@ -85,16 +101,27 @@ class BSVShimECPoint
|
|
|
85
101
|
end
|
|
86
102
|
end
|
|
87
103
|
|
|
88
|
-
# Constant-time scalar multiplication
|
|
104
|
+
# Constant-time scalar multiplication (alias for {#mul}).
|
|
89
105
|
#
|
|
90
|
-
#
|
|
91
|
-
#
|
|
106
|
+
# Retained for backward compatibility and expressiveness. Delegates
|
|
107
|
+
# to {#mul}, which is constant-time by default.
|
|
92
108
|
#
|
|
93
|
-
# @param scalar_bn [OpenSSL::BN, Integer] the
|
|
109
|
+
# @param scalar_bn [OpenSSL::BN, Integer] the scalar multiplier
|
|
94
110
|
# @return [BSVShimECPoint]
|
|
95
111
|
def mul_ct(scalar_bn)
|
|
112
|
+
mul(scalar_bn)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Variable-time scalar multiplication (wNAF).
|
|
116
|
+
#
|
|
117
|
+
# Faster than {#mul} but leaks timing information about the scalar.
|
|
118
|
+
# Use only for public scalars (e.g. signature verification).
|
|
119
|
+
#
|
|
120
|
+
# @param scalar_bn [OpenSSL::BN, Integer] the public scalar multiplier
|
|
121
|
+
# @return [BSVShimECPoint]
|
|
122
|
+
def mul_vt(scalar_bn)
|
|
96
123
|
scalar = bn_to_int(scalar_bn)
|
|
97
|
-
result = @secp_point.
|
|
124
|
+
result = @secp_point.mul_vt(scalar)
|
|
98
125
|
self.class.from_secp_point(@group, result)
|
|
99
126
|
end
|
|
100
127
|
|
|
@@ -165,7 +165,7 @@ module BSV
|
|
|
165
165
|
def derive_child(public_key, invoice_number)
|
|
166
166
|
shared = derive_shared_secret(public_key)
|
|
167
167
|
hmac = Digest.hmac_sha256(shared.compressed, invoice_number.encode('UTF-8'))
|
|
168
|
-
hmac_bn = OpenSSL::BN.new(hmac
|
|
168
|
+
hmac_bn = OpenSSL::BN.new(hmac, 2)
|
|
169
169
|
PrivateKey.new(@bn.mod_add(hmac_bn, Curve::N))
|
|
170
170
|
end
|
|
171
171
|
|
|
@@ -207,7 +207,7 @@ module BSV
|
|
|
207
207
|
loop do
|
|
208
208
|
counter_bytes = [i, attempts].pack('N*') + SecureRandom.random_bytes(32)
|
|
209
209
|
h = Digest.hmac_sha512(seed, counter_bytes)
|
|
210
|
-
candidate = OpenSSL::BN.new(h
|
|
210
|
+
candidate = OpenSSL::BN.new(h, 2) % PointInFiniteField::P
|
|
211
211
|
|
|
212
212
|
attempts += 1
|
|
213
213
|
raise ArgumentError, 'failed to generate unique x-coordinate after 5 attempts' if attempts > 5
|
|
@@ -132,7 +132,7 @@ module BSV
|
|
|
132
132
|
def derive_child(private_key, invoice_number)
|
|
133
133
|
shared = derive_shared_secret(private_key)
|
|
134
134
|
hmac = Digest.hmac_sha256(shared.compressed, invoice_number.encode('UTF-8'))
|
|
135
|
-
hmac_bn = OpenSSL::BN.new(hmac
|
|
135
|
+
hmac_bn = OpenSSL::BN.new(hmac, 2)
|
|
136
136
|
hmac_point = Curve.multiply_generator_ct(hmac_bn)
|
|
137
137
|
child_point = Curve.add_points(@point, hmac_point)
|
|
138
138
|
PublicKey.new(child_point)
|
|
@@ -97,15 +97,15 @@ module BSV
|
|
|
97
97
|
e = compute_challenge(public_key_a, public_key_b, shared_secret, proof.s_prime, proof.r)
|
|
98
98
|
|
|
99
99
|
# Equation 1: z·G == R + e·A
|
|
100
|
-
z_g = Curve.
|
|
101
|
-
e_a = Curve.
|
|
100
|
+
z_g = Curve.multiply_generator_vt(proof.z)
|
|
101
|
+
e_a = Curve.multiply_point_vt(public_key_a.point, e)
|
|
102
102
|
r_plus_ea = Curve.add_points(proof.r.point, e_a)
|
|
103
103
|
|
|
104
104
|
return false unless points_equal?(z_g, r_plus_ea)
|
|
105
105
|
|
|
106
106
|
# Equation 2: z·B == S' + e·S
|
|
107
|
-
z_b = Curve.
|
|
108
|
-
e_s = Curve.
|
|
107
|
+
z_b = Curve.multiply_point_vt(public_key_b.point, proof.z)
|
|
108
|
+
e_s = Curve.multiply_point_vt(shared_secret.point, e)
|
|
109
109
|
sp_plus_es = Curve.add_points(proof.s_prime.point, e_s)
|
|
110
110
|
|
|
111
111
|
points_equal?(z_b, sp_plus_es)
|