Class: BlockIo::Key
- Inherits:
-
Object
- Object
- BlockIo::Key
- Defined in:
- lib/block_io/key.rb
Class Method Summary collapse
Instance Method Summary collapse
-
#initialize(privkey = nil, use_low_r = true, compressed = true) ⇒ Key
constructor
A new instance of Key.
- #private_key ⇒ Object
- #public_key ⇒ Object
- #sign(data) ⇒ Object
- #valid_signature?(signature, data) ⇒ Boolean
Constructor Details
#initialize(privkey = nil, use_low_r = true, compressed = true) ⇒ Key
Returns a new instance of Key.
5 6 7 8 9 10 11 12 13 14 |
# File 'lib/block_io/key.rb', line 5 def initialize(privkey = nil, use_low_r = true, compressed = true) # the privkey must be in hex if at all provided @group = ECDSA::Group::Secp256k1 @private_key = (privkey.nil? ? (1 + SecureRandom.random_number(@group.order - 1)) : privkey.to_i(16)) @public_key = @group.generator.multiply_by_scalar(@private_key) @compressed = compressed @use_low_r = use_low_r end |
Class Method Details
.from_passphrase(passphrase, use_low_r = true) ⇒ Object
65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/block_io/key.rb', line 65 def self.from_passphrase(passphrase, use_low_r = true) # ATTENTION: use BlockIo::Key.new to generate new private keys. Using passphrases is not recommended due to lack of / low entropy. # create a private/public key pair from a given passphrase # use a long, random passphrase. your security depends on the passphrase's entropy. raise Exception.new("Must provide passphrase at least 8 characters long.") if passphrase.nil? or passphrase.length < 8 hashed_key = Helper.sha256([passphrase].pack("H*")) # must pass bytes to sha256 # modding is for backward compatibility with legacy bitcoinjs Key.new((hashed_key.to_i(16) % ECDSA::Group::Secp256k1.order).to_s(16), use_low_r) end |
.from_wif(wif, use_low_r = true) ⇒ Object
78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/block_io/key.rb', line 78 def self.from_wif(wif, use_low_r = true) # returns a new key extracted from the Wallet Import Format provided # TODO check against checksum hexkey = Helper.decode_base58(wif) actual_key = hexkey[2...66] compressed = hexkey[2..hexkey.length].length-8 > 64 and hexkey[2..hexkey.length][64...66] == "01" Key.new(actual_key, use_low_r, compressed) end |
Instance Method Details
#private_key ⇒ Object
16 17 18 19 |
# File 'lib/block_io/key.rb', line 16 def private_key # returns private key in hex form @private_key.to_s(16) end |
#public_key ⇒ Object
21 22 23 24 25 |
# File 'lib/block_io/key.rb', line 21 def public_key # returns the compressed form of the public key to save network fees (shorter scripts) # hex form ECDSA::Format::PointOctetString.encode(@public_key, compression: @compressed).unpack("H*")[0] end |
#sign(data) ⇒ Object
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/block_io/key.rb', line 27 def sign(data) # sign the given hexadecimal string counter = 0 signature = nil loop do # first this we get K, it's without extra entropy # second time onwards, with extra entropy nonce = Key.deterministicGenerateK([data].pack("H*"), @private_key, counter) # RFC6979 signature = ECDSA.sign(@group, @private_key, data.to_i(16), nonce) r, s = signature.components # BIP0062 -- use lower S values only over_two = @group.order >> 1 # half of what it was s = @group.order - s if (s > over_two) signature = ECDSA::Signature.new(r, s) # DER encode this, and return it in hex form signature = ECDSA::Format::SignatureDerString.encode(signature).unpack("H*")[0] break if !@use_low_r or Helper.low_r?(signature) counter += 1 end signature end |
#valid_signature?(signature, data) ⇒ Boolean
61 62 63 |
# File 'lib/block_io/key.rb', line 61 def valid_signature?(signature, data) ECDSA.valid_signature?(@public_key, [data].pack("H*"), ECDSA::Format::SignatureDerString.decode([signature].pack("H*"))) end |