tapyrus 0.2.8 → 0.2.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0ad31bf4aa539aa394eeb5002fe11fc9b8c6a43aab73c9e36a63220159c2fb30
4
- data.tar.gz: 8b7aaacfd238de278b334b7b26249045facf14843b8fb32985045c0a52b9cdc9
3
+ metadata.gz: 44f097dd931371e9cce458e44ff030d9ebedcd9372632339d274457bb3839a4c
4
+ data.tar.gz: c72dddb87aacb3f649cc4a542b0988eb54347da6203e0bcc2d430065fc3398b8
5
5
  SHA512:
6
- metadata.gz: ad3bc4d2fbaaf0e228cd7c07ee78e878f6b913e971645b8a6e188df70c9e363fbc210456833436f1e7ea780881bd10accdd7a069365e26fc09195744fe606766
7
- data.tar.gz: b267bb2ff699df8822feffc75573db5e506dc5490f5f79146cfaf16d20abfd14660ddbfa4f2f01401d54b5bb9ecdb646613de8c7a28b01d48260aebb862834d3
6
+ metadata.gz: cc7fae61da930e3af35d17039dcd9bda45b6a9317d132dc5096e585ed3b00309a7fc4a3f3552928a57b5b46289bf3fe5be28000cffe666f0d0990480e88b31f3
7
+ data.tar.gz: b7d9c26524bda4fe26f4522b51b3328145a6e590a0099f2f72b0d9cbfb43c9a4e9b7ee4eb23907d8d8c8cf3daa239b0b7ad76caee82b5b00edffef63cb69d178
data/lib/schnorr.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  module Schnorr
2
2
  autoload :Signature, 'schnorr/signature'
3
+ autoload :SignToContract, 'schnorr/sign_to_contract'
3
4
 
4
5
  module_function
5
6
 
@@ -16,12 +17,7 @@ module Schnorr
16
17
  raise 'private_key is zero or over the curve order.' if private_key == 0 || private_key >= GROUP.order
17
18
 
18
19
  p = GROUP.new_point(private_key)
19
- secret = ECDSA::Format::IntegerOctetString.encode(private_key, GROUP.byte_length)
20
- secret = secret + message + ALGO16
21
- nonce = Tapyrus::Secp256k1::RFC6979.generate_rfc6979_nonce(secret, '')
22
-
23
- k0 = nonce % GROUP.order
24
- raise 'Creation of signature failed. k is zero' if k0.zero?
20
+ k0 = deterministic_nonce(message, private_key)
25
21
 
26
22
  r = GROUP.new_point(k0)
27
23
  k = ECDSA::PrimeField.jacobi(r.y, GROUP.field.prime) == 1 ? k0 : GROUP.order - k0
@@ -31,6 +27,16 @@ module Schnorr
31
27
  Schnorr::Signature.new(r.x, (k + e * private_key) % GROUP.order)
32
28
  end
33
29
 
30
+ def deterministic_nonce(message, private_key)
31
+ secret = ECDSA::Format::IntegerOctetString.encode(private_key, GROUP.byte_length)
32
+ secret = secret + message + ALGO16
33
+ nonce = Tapyrus::Secp256k1::RFC6979.generate_rfc6979_nonce(secret, '')
34
+
35
+ k0 = nonce % GROUP.order
36
+ raise 'Creation of signature failed. k is zero' if k0.zero?
37
+ k0
38
+ end
39
+
34
40
  # Verifies the given {Signature} and returns true if it is valid.
35
41
  # @param message (String) A message to be signed with binary format.
36
42
  # @param public_key (String) The public key with binary format.
@@ -0,0 +1,51 @@
1
+ module Schnorr
2
+ module SignToContract
3
+ module_function
4
+
5
+ GROUP = ECDSA::Group::Secp256k1
6
+
7
+ # Generate schnorr signature for sign-to-signature.
8
+ # @param message [String] A message to be signed with binary format.
9
+ # @param private_key [Integer] The private key.
10
+ # @param contract [String] A contract information with 32-bytes binary format.
11
+ # @return [(Schnorr::Signature, ECDSA::Point)] signature and point to prove the commitment to contract.
12
+ def sign(message, private_key, contract)
13
+ raise 'The message must be a 32-byte array.' unless message.bytesize == 32
14
+ raise 'private_key is zero or over the curve order.' if private_key == 0 || private_key >= GROUP.order
15
+ raise 'The contract must be a 32-byte binary string.' unless contract.bytesize == 32
16
+
17
+ p = GROUP.new_point(private_key)
18
+ k0 = Schnorr.deterministic_nonce(message, private_key)
19
+
20
+ k1, r = tweak(k0, contract)
21
+
22
+ q = GROUP.new_point(k1)
23
+ k = ECDSA::PrimeField.jacobi(q.y, GROUP.field.prime) == 1 ? k1 : GROUP.order - k1
24
+
25
+ e = Schnorr.create_challenge(q.x, p, message)
26
+
27
+ [Schnorr::Signature.new(q.x, (k + e * private_key) % GROUP.order), r]
28
+ end
29
+
30
+ def tweak(k, contract)
31
+ r = GROUP.new_point(k)
32
+ rx = ECDSA::Format::IntegerOctetString.encode(r.x, GROUP.byte_length)
33
+ h = Tapyrus.sha256(rx + contract)
34
+ k1 = (k + h.bth.to_i(16)) % GROUP.order
35
+ raise 'Creation of signature failed. k + h(R || c) is zero' if k1.zero?
36
+ [k1, r]
37
+ end
38
+
39
+ # Validate contract
40
+ # @param r [ECDSA::Point] point to prove the commitment.
41
+ # @param signature [Schnorr::Signature] signature.
42
+ # @param contract [String] A contract information with 32-bytes binary format.
43
+ # @return true if commitment for contract is valid, otherwise false
44
+ def valid_contract?(r, signature, contract)
45
+ rx = ECDSA::Format::IntegerOctetString.encode(r.x, GROUP.byte_length)
46
+ commitment = Tapyrus.sha256(rx + contract).bth.to_i(16) % GROUP.order
47
+ point = r + GROUP.generator.multiply_by_scalar(commitment)
48
+ signature.r == point.x
49
+ end
50
+ end
51
+ end
data/lib/tapyrus.rb CHANGED
@@ -49,6 +49,7 @@ module Tapyrus
49
49
  autoload :Color, 'tapyrus/script/color'
50
50
  autoload :Errors, 'tapyrus/errors'
51
51
  autoload :TxBuilder, 'tapyrus/tx_builder'
52
+ autoload :BIP175, 'tapyrus/bip175'
52
53
 
53
54
  require_relative 'tapyrus/constants'
54
55
  require_relative 'tapyrus/ext/ecdsa'
@@ -0,0 +1,67 @@
1
+ module Tapyrus
2
+ # Key generation based on BIP-175
3
+ #
4
+ # @example
5
+ #
6
+ # master = Tapyrus::ExtKey.from_base58('xprv9s21ZrQH143K2JF8RafpqtKiTbsbaxEeUaMnNHsm5o6wCW3z8ySyH4UxFVSfZ8n7ESu7fgir8imbZKLYVBxFPND1pniTZ81vKfd45EHKX73')
7
+ # bip175 = Tapyrus::BIP175.from_private_key(master)
8
+ # bip175 << "foo"
9
+ # bip175 << "bar"
10
+ # bip175.addr
11
+ # > 1C7f322izqMqLzZzfzkPAjxBzprxDi47Yf
12
+ #
13
+ # @see https://github.com/bitcoin/bips/blob/master/bip-0175.mediawiki
14
+ class BIP175
15
+ PURPOSE_TYPE = 175
16
+
17
+ attr_accessor :payment_base
18
+
19
+ def initialize
20
+ @contracts = []
21
+ end
22
+
23
+ # @param key [Tapyrus::ExtKey] master private extended key
24
+ def self.from_ext_key(key)
25
+ raise ArgumentError, 'key should be Tapyrus::ExtKey' unless key.is_a?(Tapyrus::ExtKey)
26
+ raise ArgumentError, 'key should be master private extended key' unless key.master?
27
+ new.tap do |bip175|
28
+ bip175.payment_base =
29
+ key.derive(PURPOSE_TYPE, true).derive(Tapyrus.chain_params.bip44_coin_type, true).ext_pubkey
30
+ end
31
+ end
32
+
33
+ # @param key [Tapyrus::ExtPubkey] contract base public key
34
+ def self.from_ext_pubkey(key)
35
+ raise ArgumentError, 'key should be Tapyrus::ExtPubkey' unless key.is_a?(Tapyrus::ExtPubkey)
36
+ new.tap { |bip175| bip175.payment_base = key }
37
+ end
38
+
39
+ # Add value of hashed contract
40
+ # @param contract [String] contract information
41
+ def add(contract)
42
+ @contracts << Tapyrus.sha256(contract)
43
+ self
44
+ end
45
+ alias << add
46
+
47
+ # Return combined hash consist of payment_base and contract hashes
48
+ # @return [String] contract_hash
49
+ def combined_hash
50
+ hashes = @contracts.map { |c| c.bth }.sort
51
+ concatenated_hash = [payment_base.to_base58].concat(hashes).join
52
+ Tapyrus.sha256(concatenated_hash)
53
+ end
54
+
55
+ # Return pay-to-contract extended public key
56
+ # @return [Tapyrus::ExtPubkey] extended public key
57
+ def pubkey
58
+ # Split every 2 bytes
59
+ paths = combined_hash.unpack('S>*')
60
+ paths.inject(payment_base) { |key, p| key.derive(p) }
61
+ end
62
+
63
+ def addr
64
+ pubkey.addr
65
+ end
66
+ end
67
+ end
@@ -196,6 +196,10 @@ module Tapyrus
196
196
  Tapyrus.chain_params.extended_pubkey_version
197
197
  end
198
198
  end
199
+
200
+ def master?
201
+ depth == 0 && number == 0 && parent_fingerprint == '00000000'
202
+ end
199
203
  end
200
204
 
201
205
  # BIP-32 Extended public key
@@ -356,5 +360,9 @@ module Tapyrus
356
360
  p = Tapyrus.chain_params
357
361
  [p.bip49_pubkey_p2wpkh_p2sh_version, p.bip84_pubkey_p2wpkh_version, p.extended_pubkey_version].include?(version)
358
362
  end
363
+
364
+ def master?
365
+ depth == 0 && number == 0 && parent_fingerprint == '00000000'
366
+ end
359
367
  end
360
368
  end
data/lib/tapyrus/rpc.rb CHANGED
@@ -3,5 +3,6 @@ module Tapyrus
3
3
  autoload :HttpServer, 'tapyrus/rpc/http_server'
4
4
  autoload :RequestHandler, 'tapyrus/rpc/request_handler'
5
5
  autoload :TapyrusCoreClient, 'tapyrus/rpc/tapyrus_core_client'
6
+ autoload :Error, 'tapyrus/rpc/tapyrus_core_client'
6
7
  end
7
8
  end
@@ -16,22 +16,25 @@ module Tapyrus
16
16
  # end
17
17
  # end
18
18
  class Error < StandardError
19
- attr_reader :message
19
+ attr_reader :response_code, :response_msg, :rpc_error
20
20
 
21
- def initialize(response)
22
- raise ArgumentError, 'Must set response as cause.' unless response
21
+ def initialize(response_code, response_msg, rpc_error)
22
+ @response_code = response_code
23
+ @response_msg = response_msg
24
+ @rpc_error = rpc_error
25
+ end
23
26
 
24
- # set message from response body or status code.
25
- @message = { response_code: response&.code, response_msg: response&.msg }
26
- begin
27
- @message.merge!({ rpc_error: Tapyrus::RPC.response_body2json(response.body)['error'] })
28
- rescue JSON::ParserError => _
29
- # if RPC server don't send error message.
30
- end
27
+ def message
28
+ @message ||=
29
+ begin
30
+ m = { response_code: response_code, response_msg: response_msg }
31
+ m.merge!(rpc_error: rpc_error) if rpc_error
32
+ m
33
+ end
31
34
  end
32
35
 
33
36
  def to_s
34
- @message.to_s
37
+ message.to_s
35
38
  end
36
39
  end
37
40
 
@@ -83,10 +86,21 @@ module Tapyrus
83
86
  request.content_type = 'application/json'
84
87
  request.body = data.to_json
85
88
  response = http.request(request)
86
- raise Error.new(response) unless response.is_a? Net::HTTPOK
89
+ raise error!(response) unless response.is_a? Net::HTTPOK
87
90
  response = Tapyrus::RPC.response_body2json(response.body)
88
91
  response['result']
89
92
  end
93
+
94
+ def error!(response)
95
+ rpc_error =
96
+ begin
97
+ Tapyrus::RPC.response_body2json(response.body)['error']
98
+ rescue JSON::ParserError => _
99
+ # if RPC server don't send error message.
100
+ end
101
+
102
+ raise Error.new(response.code, response.msg, rpc_error)
103
+ end
90
104
  end
91
105
 
92
106
  def response_body2json(body)
@@ -1,3 +1,3 @@
1
1
  module Tapyrus
2
- VERSION = '0.2.8'
2
+ VERSION = '0.2.9'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tapyrus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.8
4
+ version: 0.2.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - azuchi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-05-14 00:00:00.000000000 Z
11
+ date: 2021-05-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ecdsa
@@ -306,9 +306,11 @@ files:
306
306
  - lib/openassets/payload.rb
307
307
  - lib/openassets/util.rb
308
308
  - lib/schnorr.rb
309
+ - lib/schnorr/sign_to_contract.rb
309
310
  - lib/schnorr/signature.rb
310
311
  - lib/tapyrus.rb
311
312
  - lib/tapyrus/base58.rb
313
+ - lib/tapyrus/bip175.rb
312
314
  - lib/tapyrus/block.rb
313
315
  - lib/tapyrus/block_header.rb
314
316
  - lib/tapyrus/bloom_filter.rb