Module: Bitcoin::Secp256k1::Ruby
- Defined in:
- lib/bitcoin/secp256k1/ruby.rb
Overview
secp256 module using ecdsa gem github.com/DavidEGrayson/ruby_ecdsa
Class Method Summary collapse
-
.generate_key(compressed: true) ⇒ Object
generate bitcoin key object.
-
.generate_key_pair(compressed: true) ⇒ Object
generate ec private key and public key.
- .generate_pubkey(privkey, compressed: true) ⇒ Object
-
.parse_ec_pubkey?(pubkey, allow_hybrid = false) ⇒ Boolean
validate whether this is a valid public key (more expensive than IsValid()).
-
.recover_compact(data, signature, rec, compressed) ⇒ Bitcoin::Key
Recover public key from compact signature.
-
.repack_pubkey(pubkey) ⇒ Object
if
pubkey
is hybrid public key format, it convert uncompressed format. -
.sign_compact(data, privkey) ⇒ Array[signature, recovery id]
Sign data with compact format.
-
.sign_data(data, privkey, extra_entropy = nil, algo: :ecdsa) ⇒ String
sign data.
- .sign_ecdsa(data, privkey, extra_entropy) ⇒ Object
- .sign_schnorr(data, privkey, aux_rand) ⇒ Object
-
.valid_xonly_pubkey?(pub_key) ⇒ Boolean
Check whether valid x-only public key or not.
- .verify_ecdsa(data, sig, pubkey) ⇒ Object
- .verify_schnorr(data, sig, pubkey) ⇒ Object
-
.verify_sig(data, sig, pubkey, algo: :ecdsa) ⇒ Boolean
verify signature using public key.
Class Method Details
.generate_key(compressed: true) ⇒ Object
generate bitcoin key object
20 21 22 23 |
# File 'lib/bitcoin/secp256k1/ruby.rb', line 20 def generate_key(compressed: true) privkey, pubkey = generate_key_pair(compressed: compressed) Bitcoin::Key.new(priv_key: privkey, pubkey: pubkey, compressed: compressed) end |
.generate_key_pair(compressed: true) ⇒ Object
generate ec private key and public key
11 12 13 14 15 16 17 |
# File 'lib/bitcoin/secp256k1/ruby.rb', line 11 def generate_key_pair(compressed: true) private_key = 1 + SecureRandom.random_number(GROUP.order - 1) public_key = GROUP.generator.multiply_by_scalar(private_key) privkey = ECDSA::Format::IntegerOctetString.encode(private_key, 32) pubkey = public_key.to_hex(compressed) [privkey.bth, pubkey] end |
.generate_pubkey(privkey, compressed: true) ⇒ Object
25 26 27 28 |
# File 'lib/bitcoin/secp256k1/ruby.rb', line 25 def generate_pubkey(privkey, compressed: true) public_key = ECDSA::Group::Secp256k1.generator.multiply_by_scalar(privkey.to_i(16)) public_key.to_hex(compressed) end |
.parse_ec_pubkey?(pubkey, allow_hybrid = false) ⇒ Boolean
validate whether this is a valid public key (more expensive than IsValid())
119 120 121 122 123 124 125 126 |
# File 'lib/bitcoin/secp256k1/ruby.rb', line 119 def parse_ec_pubkey?(pubkey, allow_hybrid = false) begin point = ECDSA::Format::PointOctetString.decode(pubkey.htb, ECDSA::Group::Secp256k1, allow_hybrid: allow_hybrid) ECDSA::Group::Secp256k1.valid_public_key?(point) rescue ECDSA::Format::DecodeError false end end |
.recover_compact(data, signature, rec, compressed) ⇒ Bitcoin::Key
Recover public key from compact signature.
76 77 78 79 80 81 82 83 84 |
# File 'lib/bitcoin/secp256k1/ruby.rb', line 76 def recover_compact(data, signature, rec, compressed) r = ECDSA::Format::IntegerOctetString.decode(signature[1...33]) s = ECDSA::Format::IntegerOctetString.decode(signature[33..-1]) ECDSA.recover_public_key(Bitcoin::Secp256k1::GROUP, data, ECDSA::Signature.new(r, s)).each do |p| if p.y & 1 == rec return Bitcoin::Key.from_point(p, compressed: compressed) end end end |
.repack_pubkey(pubkey) ⇒ Object
if pubkey
is hybrid public key format, it convert uncompressed format. lists.linuxfoundation.org/pipermail/bitcoin-dev/2012-June/001578.html
104 105 106 107 108 109 110 111 112 113 |
# File 'lib/bitcoin/secp256k1/ruby.rb', line 104 def repack_pubkey(pubkey) p = pubkey.htb case p[0] when "\x06", "\x07" p[0] = "\x04" p else pubkey.htb end end |
.sign_compact(data, privkey) ⇒ Array[signature, recovery id]
Sign data with compact format.
65 66 67 68 |
# File 'lib/bitcoin/secp256k1/ruby.rb', line 65 def sign_compact(data, privkey) sig, rec = sign_ecdsa(data, privkey, nil) [ECDSA::Format::SignatureDerString.decode(sig), rec] end |
.sign_data(data, privkey, extra_entropy = nil, algo: :ecdsa) ⇒ String
sign data.
50 51 52 53 54 55 56 57 58 59 |
# File 'lib/bitcoin/secp256k1/ruby.rb', line 50 def sign_data(data, privkey, extra_entropy = nil, algo: :ecdsa) case algo when :ecdsa sign_ecdsa(data, privkey, extra_entropy)&.first when :schnorr sign_schnorr(data, privkey, extra_entropy) else nil end end |
.sign_ecdsa(data, privkey, extra_entropy) ⇒ Object
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/bitcoin/secp256k1/ruby.rb', line 128 def sign_ecdsa(data, privkey, extra_entropy) privkey = privkey.htb private_key = ECDSA::Format::IntegerOctetString.decode(privkey) extra_entropy ||= '' nonce = RFC6979.generate_rfc6979_nonce(privkey + data, extra_entropy) # port form ecdsa gem. r_point = GROUP.new_point(nonce) point_field = ECDSA::PrimeField.new(GROUP.order) r = point_field.mod(r_point.x) return nil if r.zero? rec = r_point.y & 1 e = ECDSA.normalize_digest(data, GROUP.bit_length) s = point_field.mod(point_field.inverse(nonce) * (e + r * private_key)) if s > (GROUP.order / 2) # convert low-s s = GROUP.order - s rec ^= 1 end return nil if s.zero? signature = ECDSA::Signature.new(r, s).to_der public_key = Bitcoin::Key.new(priv_key: privkey.bth).pubkey raise 'Creation of signature failed.' unless Bitcoin::Secp256k1::Ruby.verify_sig(data, signature, public_key) [signature, rec] end |
.sign_schnorr(data, privkey, aux_rand) ⇒ Object
159 160 161 |
# File 'lib/bitcoin/secp256k1/ruby.rb', line 159 def sign_schnorr(data, privkey, aux_rand) aux_rand ? Schnorr.sign(data, privkey.htb, aux_rand).encode : Schnorr.sign(data, privkey.htb).encode end |
.valid_xonly_pubkey?(pub_key) ⇒ Boolean
Check whether valid x-only public key or not.
33 34 35 36 37 38 39 40 41 42 |
# File 'lib/bitcoin/secp256k1/ruby.rb', line 33 def valid_xonly_pubkey?(pub_key) pubkey = pub_key.htb return false unless pubkey.bytesize == 32 begin ECDSA::Format::PointOctetString.decode(pubkey, ECDSA::Group::Secp256k1) rescue Exception return false end true end |
.verify_ecdsa(data, sig, pubkey) ⇒ Object
163 164 165 166 167 168 169 170 171 |
# File 'lib/bitcoin/secp256k1/ruby.rb', line 163 def verify_ecdsa(data, sig, pubkey) begin k = ECDSA::Format::PointOctetString.decode(repack_pubkey(pubkey), GROUP) signature = ECDSA::Format::SignatureDerString.decode(sig) ECDSA.valid_signature?(k, data, signature) rescue Exception false end end |
.verify_schnorr(data, sig, pubkey) ⇒ Object
173 174 175 |
# File 'lib/bitcoin/secp256k1/ruby.rb', line 173 def verify_schnorr(data, sig, pubkey) Schnorr.valid_sig?(data, pubkey.htb, sig) end |
.verify_sig(data, sig, pubkey, algo: :ecdsa) ⇒ Boolean
verify signature using public key
91 92 93 94 95 96 97 98 99 100 |
# File 'lib/bitcoin/secp256k1/ruby.rb', line 91 def verify_sig(data, sig, pubkey, algo: :ecdsa) case algo when :ecdsa verify_ecdsa(data, sig, pubkey) when :schnorr verify_schnorr(data, sig, pubkey) else false end end |