Module: Secp256k1::Key
- Included in:
- Secp256k1
- Defined in:
- lib/secp256k1/key.rb
Overview
Key module provides EC key arithmetic (tweak/negate/combine), x-only public key operations used by Taproot, and key pair accessors.
Instance Method Summary collapse
-
#combine_pubkeys(pubkeys, compressed: true) ⇒ String
Add a number of public keys together.
-
#compare_pubkey(pubkey1, pubkey2) ⇒ Integer
Compare two public keys using lexicographic(of compressed serialization) order.
-
#compare_xonly_pubkey(pubkey1, pubkey2) ⇒ Integer
Compare two x-only public keys using lexicographic order.
-
#keypair_to_pubkey(keypair, compressed: true) ⇒ String
Get the public key from a key pair.
-
#keypair_to_seckey(keypair) ⇒ String
Get the private key from a key pair.
-
#keypair_to_xonly_pubkey(keypair) ⇒ Array(String, Integer)
Get the x-only public key from a key pair.
-
#keypair_xonly_tweak_add(keypair, tweak) ⇒ String
Tweak a key pair by adding
tweakto the key pair’s x-only context. -
#negate_pubkey(pubkey, compressed: true) ⇒ String
Negate a public key.
-
#negate_seckey(private_key) ⇒ String
Negate a private key in place and return the result.
-
#sort_pubkeys(pubkeys, compressed: true) ⇒ Array<String>
Sort public keys using lexicographic(of compressed serialization) order.
-
#tweak_add_pubkey(pubkey, tweak, compressed: true) ⇒ String
Tweak a public key by adding
tweak* G to it. -
#tweak_add_seckey(private_key, tweak) ⇒ String
Tweak a private key by adding
tweakto it. -
#tweak_mul_pubkey(pubkey, tweak, compressed: true) ⇒ String
Tweak a public key by multiplying it by
tweak. -
#tweak_mul_seckey(private_key, tweak) ⇒ String
Tweak a private key by multiplying it by
tweak. -
#xonly_pubkey_from_pubkey(pubkey) ⇒ Array(String, Integer)
Convert a public key into an x-only public key.
-
#xonly_tweak_add_check?(tweaked_pubkey32, tweaked_pk_parity, internal_pubkey, tweak) ⇒ Boolean
Check that a tweaked x-only public key was computed by tweaking
internal_pubkeywithtweak. -
#xonly_tweak_add_pubkey(xonly_pubkey, tweak, compressed: true) ⇒ Array(String, Integer)
Tweak an x-only public key by adding
tweak* G to it (used for Taproot output key derivation).
Instance Method Details
#combine_pubkeys(pubkeys, compressed: true) ⇒ String
Add a number of public keys together.
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/secp256k1/key.rb', line 95 def combine_pubkeys(pubkeys, compressed: true) raise ArgumentError, "pubkeys must be Array." unless pubkeys.is_a?(Array) raise ArgumentError, "pubkeys must not be empty." if pubkeys.empty? with_context do |context| internals = pubkeys.map do |pubkey| raise ArgumentError, "pubkey must be String." unless pubkey.is_a?(String) parse_pubkey_internal(context, hex2bin(pubkey)) end ins = FFI::MemoryPointer.new(:pointer, internals.size) ins.write_array_of_pointer(internals) combined = FFI::MemoryPointer.new(:uchar, 64) raise Error, 'secp256k1_ec_pubkey_combine failed.' unless secp256k1_ec_pubkey_combine(context, combined, ins, internals.size) == 1 serialize_pubkey_internal(context, combined, compressed) end end |
#compare_pubkey(pubkey1, pubkey2) ⇒ Integer
Compare two public keys using lexicographic(of compressed serialization) order.
233 234 235 236 237 238 239 240 241 |
# File 'lib/secp256k1/key.rb', line 233 def compare_pubkey(pubkey1, pubkey2) raise ArgumentError, "pubkey1 must be String." unless pubkey1.is_a?(String) raise ArgumentError, "pubkey2 must be String." unless pubkey2.is_a?(String) with_context do |context| a = parse_pubkey_internal(context, hex2bin(pubkey1)) b = parse_pubkey_internal(context, hex2bin(pubkey2)) secp256k1_ec_pubkey_cmp(context, a, b) end end |
#compare_xonly_pubkey(pubkey1, pubkey2) ⇒ Integer
Compare two x-only public keys using lexicographic order.
270 271 272 273 274 275 276 277 278 |
# File 'lib/secp256k1/key.rb', line 270 def compare_xonly_pubkey(pubkey1, pubkey2) validate_string!("pubkey1", pubkey1, X_ONLY_PUBKEY_SIZE) validate_string!("pubkey2", pubkey2, X_ONLY_PUBKEY_SIZE) with_context do |context| a = parse_xonly_pubkey_internal(context, hex2bin(pubkey1)) b = parse_xonly_pubkey_internal(context, hex2bin(pubkey2)) secp256k1_xonly_pubkey_cmp(context, a, b) end end |
#keypair_to_pubkey(keypair, compressed: true) ⇒ String
Get the public key from a key pair.
183 184 185 186 187 188 189 190 191 192 |
# File 'lib/secp256k1/key.rb', line 183 def keypair_to_pubkey(keypair, compressed: true) validate_string!("keypair", keypair, 96) keypair = hex2bin(keypair) with_context do |context| keypair_ptr = FFI::MemoryPointer.new(:uchar, 96).put_bytes(0, keypair) internal = FFI::MemoryPointer.new(:uchar, 64) raise Error, 'secp256k1_keypair_pub failed.' unless secp256k1_keypair_pub(context, internal, keypair_ptr) == 1 serialize_pubkey_internal(context, internal, compressed) end end |
#keypair_to_seckey(keypair) ⇒ String
Get the private key from a key pair.
199 200 201 202 203 204 205 206 207 208 |
# File 'lib/secp256k1/key.rb', line 199 def keypair_to_seckey(keypair) validate_string!("keypair", keypair, 96) keypair = hex2bin(keypair) with_context do |context| keypair_ptr = FFI::MemoryPointer.new(:uchar, 96).put_bytes(0, keypair) seckey = FFI::MemoryPointer.new(:uchar, 32) raise Error, 'secp256k1_keypair_sec failed.' unless secp256k1_keypair_sec(context, seckey, keypair_ptr) == 1 seckey.read_string(32).unpack1('H*') end end |
#keypair_to_xonly_pubkey(keypair) ⇒ Array(String, Integer)
Get the x-only public key from a key pair.
215 216 217 218 219 220 221 222 223 224 225 |
# File 'lib/secp256k1/key.rb', line 215 def keypair_to_xonly_pubkey(keypair) validate_string!("keypair", keypair, 96) keypair = hex2bin(keypair) with_context do |context| keypair_ptr = FFI::MemoryPointer.new(:uchar, 96).put_bytes(0, keypair) xonly = FFI::MemoryPointer.new(:uchar, 64) parity = FFI::MemoryPointer.new(:int) raise Error, 'secp256k1_keypair_xonly_pub failed.' unless secp256k1_keypair_xonly_pub(context, xonly, parity, keypair_ptr) == 1 [serialize_xonly_pubkey_internal(context, xonly), parity.read_int] end end |
#keypair_xonly_tweak_add(keypair, tweak) ⇒ String
Tweak a key pair by adding tweak to the key pair’s x-only context.
286 287 288 289 290 291 292 293 294 295 296 297 |
# File 'lib/secp256k1/key.rb', line 286 def keypair_xonly_tweak_add(keypair, tweak) validate_string!("keypair", keypair, 96) validate_string!("tweak", tweak, 32) keypair = hex2bin(keypair) tweak = hex2bin(tweak) with_context do |context| keypair_ptr = FFI::MemoryPointer.new(:uchar, 96).put_bytes(0, keypair) tweak_ptr = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, tweak) raise Error, 'secp256k1_keypair_xonly_tweak_add failed.' unless secp256k1_keypair_xonly_tweak_add(context, keypair_ptr, tweak_ptr) == 1 keypair_ptr.read_string(96).unpack1('H*') end end |
#negate_pubkey(pubkey, compressed: true) ⇒ String
Negate a public key.
57 58 59 60 61 62 63 64 65 |
# File 'lib/secp256k1/key.rb', line 57 def negate_pubkey(pubkey, compressed: true) raise ArgumentError, "pubkey must be String." unless pubkey.is_a?(String) pubkey = hex2bin(pubkey) with_context do |context| internal = parse_pubkey_internal(context, pubkey) raise Error, 'secp256k1_ec_pubkey_negate failed.' unless secp256k1_ec_pubkey_negate(context, internal) == 1 serialize_pubkey_internal(context, internal, compressed) end end |
#negate_seckey(private_key) ⇒ String
Negate a private key in place and return the result.
21 22 23 24 25 26 27 28 29 |
# File 'lib/secp256k1/key.rb', line 21 def negate_seckey(private_key) validate_string!("private_key", private_key, 32) private_key = hex2bin(private_key) with_context do |context| seckey = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, private_key) raise Error, 'secp256k1_ec_seckey_negate failed.' unless secp256k1_ec_seckey_negate(context, seckey) == 1 seckey.read_string(32).unpack1('H*') end end |
#sort_pubkeys(pubkeys, compressed: true) ⇒ Array<String>
Sort public keys using lexicographic(of compressed serialization) order.
249 250 251 252 253 254 255 256 257 258 259 260 261 262 |
# File 'lib/secp256k1/key.rb', line 249 def sort_pubkeys(pubkeys, compressed: true) raise ArgumentError, "pubkeys must be Array." unless pubkeys.is_a?(Array) raise ArgumentError, "pubkeys must not be empty." if pubkeys.empty? with_context do |context| internals = pubkeys.map do |pubkey| raise ArgumentError, "pubkey must be String." unless pubkey.is_a?(String) parse_pubkey_internal(context, hex2bin(pubkey)) end arr = FFI::MemoryPointer.new(:pointer, internals.size) arr.write_array_of_pointer(internals) raise Error, 'secp256k1_ec_pubkey_sort failed.' unless secp256k1_ec_pubkey_sort(context, arr, internals.size) == 1 arr.read_array_of_pointer(internals.size).map { |ptr| serialize_pubkey_internal(context, ptr, compressed) } end end |
#tweak_add_pubkey(pubkey, tweak, compressed: true) ⇒ String
Tweak a public key by adding tweak * G to it.
74 75 76 |
# File 'lib/secp256k1/key.rb', line 74 def tweak_add_pubkey(pubkey, tweak, compressed: true) tweak_pubkey(pubkey, tweak, :secp256k1_ec_pubkey_tweak_add, compressed: compressed) end |
#tweak_add_seckey(private_key, tweak) ⇒ String
Tweak a private key by adding tweak to it.
37 38 39 |
# File 'lib/secp256k1/key.rb', line 37 def tweak_add_seckey(private_key, tweak) tweak_seckey(private_key, tweak, :secp256k1_ec_seckey_tweak_add) end |
#tweak_mul_pubkey(pubkey, tweak, compressed: true) ⇒ String
Tweak a public key by multiplying it by tweak.
85 86 87 |
# File 'lib/secp256k1/key.rb', line 85 def tweak_mul_pubkey(pubkey, tweak, compressed: true) tweak_pubkey(pubkey, tweak, :secp256k1_ec_pubkey_tweak_mul, compressed: compressed) end |
#tweak_mul_seckey(private_key, tweak) ⇒ String
Tweak a private key by multiplying it by tweak.
47 48 49 |
# File 'lib/secp256k1/key.rb', line 47 def tweak_mul_seckey(private_key, tweak) tweak_seckey(private_key, tweak, :secp256k1_ec_seckey_tweak_mul) end |
#xonly_pubkey_from_pubkey(pubkey) ⇒ Array(String, Integer)
Convert a public key into an x-only public key.
116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/secp256k1/key.rb', line 116 def xonly_pubkey_from_pubkey(pubkey) raise ArgumentError, "pubkey must be String." unless pubkey.is_a?(String) pubkey = hex2bin(pubkey) with_context do |context| internal = parse_pubkey_internal(context, pubkey) xonly = FFI::MemoryPointer.new(:uchar, 64) parity = FFI::MemoryPointer.new(:int) raise Error, 'secp256k1_xonly_pubkey_from_pubkey failed.' unless secp256k1_xonly_pubkey_from_pubkey(context, xonly, parity, internal) == 1 [serialize_xonly_pubkey_internal(context, xonly), parity.read_int] end end |
#xonly_tweak_add_check?(tweaked_pubkey32, tweaked_pk_parity, internal_pubkey, tweak) ⇒ Boolean
Check that a tweaked x-only public key was computed by tweaking internal_pubkey with tweak.
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/secp256k1/key.rb', line 159 def xonly_tweak_add_check?(tweaked_pubkey32, tweaked_pk_parity, internal_pubkey, tweak) validate_string!("tweaked_pubkey32", tweaked_pubkey32, X_ONLY_PUBKEY_SIZE) validate_string!("internal_pubkey", internal_pubkey, X_ONLY_PUBKEY_SIZE) validate_string!("tweak", tweak, 32) raise ArgumentError, "tweaked_pk_parity must be 0 or 1." unless [0, 1].include?(tweaked_pk_parity) tweaked_pubkey32 = hex2bin(tweaked_pubkey32) internal_pubkey = hex2bin(internal_pubkey) tweak = hex2bin(tweak) with_context do |context| internal = FFI::MemoryPointer.new(:uchar, X_ONLY_PUBKEY_SIZE).put_bytes(0, internal_pubkey) internal_xonly = FFI::MemoryPointer.new(:uchar, 64) return false unless secp256k1_xonly_pubkey_parse(context, internal_xonly, internal) == 1 tweaked_ptr = FFI::MemoryPointer.new(:uchar, X_ONLY_PUBKEY_SIZE).put_bytes(0, tweaked_pubkey32) tweak_ptr = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, tweak) secp256k1_xonly_pubkey_tweak_add_check(context, tweaked_ptr, tweaked_pk_parity, internal_xonly, tweak_ptr) == 1 end end |
#xonly_tweak_add_pubkey(xonly_pubkey, tweak, compressed: true) ⇒ Array(String, Integer)
Tweak an x-only public key by adding tweak * G to it (used for Taproot output key derivation).
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/secp256k1/key.rb', line 135 def xonly_tweak_add_pubkey(xonly_pubkey, tweak, compressed: true) validate_string!("xonly_pubkey", xonly_pubkey, X_ONLY_PUBKEY_SIZE) validate_string!("tweak", tweak, 32) xonly_pubkey = hex2bin(xonly_pubkey) tweak = hex2bin(tweak) with_context do |context| xonly = FFI::MemoryPointer.new(:uchar, X_ONLY_PUBKEY_SIZE).put_bytes(0, xonly_pubkey) internal = FFI::MemoryPointer.new(:uchar, 64) raise Error, 'An invalid x-only public key was specified.' unless secp256k1_xonly_pubkey_parse(context, internal, xonly) == 1 tweak_ptr = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, tweak) output = FFI::MemoryPointer.new(:uchar, 64) raise Error, 'secp256k1_xonly_pubkey_tweak_add failed.' unless secp256k1_xonly_pubkey_tweak_add(context, output, internal, tweak_ptr) == 1 _, parity = xonly_pubkey_from_internal(context, output) [serialize_pubkey_internal(context, output, compressed), parity] end end |