libsecp256k1 0.6.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 9a570f278310d4598aa3af6b5fb2d5e5c08ba9f792bf0ebec5b49b0d388a34fa
4
+ data.tar.gz: 86ca304f39e32483add4bee960cdc17f3dc53647381f6ee52861c7c26b0f2521
5
+ SHA512:
6
+ metadata.gz: c545a8e88097e54885674990b05ee6d5e9487af50cc099f53d10c2071f2becc0b710c6fcc123ceb8c39b142436994ce2778731954fdaca68ae72f916bfe72de9
7
+ data.tar.gz: e976925274fc79cae6bd626a4a0527f6cfefb1ffc3a0a6419ff3de9edfbadbd5532fef5b2cb9ef35b6093a4705d75496d9ff6b97e78139f5d53e41ce5b170cc0
data/CHANGELOG.md ADDED
@@ -0,0 +1,10 @@
1
+
2
+ # Changelog
3
+
4
+ ## 0.6.1
5
+
6
+ - Republish yanked version
7
+
8
+ ## 0.6.0 (yanked)
9
+
10
+ - The first rewritten version, superseding [ruby-bitcoin-secp256k1](https://github.com/cryptape/ruby-bitcoin-secp256k1).
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 Weiliang Li
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,41 @@
1
+ # libsecp256k1-rb
2
+
3
+ A Ruby FFI binding for bitcoin's secp256k1 library, superseding [ruby-bitcoin-secp256k1](https://github.com/cryptape/ruby-bitcoin-secp256k1).
4
+
5
+ ## Prerequisite
6
+
7
+ In order to use this gem, bitcoins's [secp256k1](https://github.com/bitcoin-core/secp256k1) dynamic library (`libsecp256k1.dylib`) must be discoverable.
8
+
9
+ ### Install secp256k1
10
+
11
+ Use Homebrew:
12
+
13
+ ```bash
14
+ brew install secp256k1
15
+ ```
16
+
17
+ Or build locally:
18
+
19
+ ```bash
20
+ git submodule update --init --recursive
21
+ ./make.sh
22
+ ./test.sh
23
+ ```
24
+
25
+ ## Install
26
+
27
+ ```bash
28
+ gem i libsecp256k1
29
+ ```
30
+
31
+ Then `require "secp256k1"` in your source code.
32
+
33
+ You need to set `C_INCLUDE_PATH` and `LD_LIBRARY_PATH` (or `SECP256K1_LIB_PATH`) environment variables, see [test.sh](./test.sh) for usage.
34
+
35
+ ## Examples
36
+
37
+ Check [test](./tests/) for examples.
38
+
39
+ ## LICENSE
40
+
41
+ [MIT License](./LICENSE)
@@ -0,0 +1,105 @@
1
+ require "ffi"
2
+ require "ffi/tools/const_generator"
3
+
4
+ module Secp256k1
5
+ module Bindings
6
+ extend FFI::Library
7
+
8
+ class << self
9
+ def capabilities
10
+ @capabilities ||= Hash.new(false)
11
+ end
12
+
13
+ def module_enabled?(feature)
14
+ capabilities.fetch(feature) { false }
15
+ end
16
+
17
+ def ensure_capability!(feature)
18
+ return if module_enabled?(feature)
19
+
20
+ message = "libsecp256k1 #{feature} module is not enabled"
21
+ if defined?(Secp256k1::LoadModuleError)
22
+ raise Secp256k1::LoadModuleError, message
23
+ else
24
+ raise LoadError, message
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def track_capability(feature, enabled)
31
+ capabilities[feature] = enabled
32
+ end
33
+
34
+ def attach_optional_group(feature)
35
+ yield
36
+ track_capability(feature, true)
37
+ rescue FFI::NotFoundError
38
+ track_capability(feature, false)
39
+ end
40
+ end
41
+
42
+ ffi_lib(ENV["SECP256K1_LIB_PATH"] || "libsecp256k1")
43
+
44
+ Constants = FFI::ConstGenerator.new("Secp256k1", required: true) do |gen|
45
+ gen.include "secp256k1.h"
46
+
47
+ gen.const(:SECP256K1_EC_COMPRESSED)
48
+ gen.const(:SECP256K1_EC_UNCOMPRESSED)
49
+
50
+ gen.const(:SECP256K1_CONTEXT_SIGN)
51
+ gen.const(:SECP256K1_CONTEXT_VERIFY)
52
+ gen.const(:SECP256K1_CONTEXT_NONE)
53
+ end
54
+
55
+ class Pubkey < FFI::Struct
56
+ layout :data, [:uchar, 64]
57
+ end
58
+
59
+ class ECDSASignature < FFI::Struct
60
+ layout :data, [:uchar, 64]
61
+ end
62
+
63
+ class ECDSARecoverableSignature < FFI::Struct
64
+ layout :data, [:uchar, 65]
65
+ end
66
+
67
+ attach_function :secp256k1_context_create, [:uint], :pointer
68
+ attach_function :secp256k1_context_destroy, [:pointer], :void
69
+ attach_function :secp256k1_ec_pubkey_parse, [:pointer, :pointer, :pointer, :size_t], :int
70
+ attach_function :secp256k1_ec_pubkey_create, [:pointer, :pointer, :pointer], :int
71
+ attach_function :secp256k1_ec_pubkey_serialize, [:pointer, :pointer, :pointer, :pointer, :uint], :int
72
+ attach_function :secp256k1_ec_seckey_verify, [:pointer, :pointer], :int
73
+ attach_function :secp256k1_ecdsa_signature_serialize_der, [:pointer, :pointer, :pointer, :pointer], :int
74
+ attach_function :secp256k1_ecdsa_signature_serialize_compact, [:pointer, :pointer, :pointer], :int
75
+ attach_function :secp256k1_ecdsa_signature_parse_der, [:pointer, :pointer, :pointer, :size_t], :int
76
+ attach_function :secp256k1_ecdsa_signature_parse_compact, [:pointer, :pointer, :pointer], :int
77
+ attach_function :secp256k1_ecdsa_sign, [:pointer, :pointer, :pointer, :pointer, :pointer, :pointer], :int
78
+ attach_function :secp256k1_ecdsa_verify, [:pointer, :pointer, :pointer, :pointer], :int
79
+ attach_function :secp256k1_ecdsa_signature_normalize, [:pointer, :pointer, :pointer], :int
80
+ attach_function :secp256k1_ec_pubkey_tweak_add, [:pointer, :pointer, :pointer], :int
81
+ attach_function :secp256k1_ec_pubkey_tweak_mul, [:pointer, :pointer, :pointer], :int
82
+ attach_function :secp256k1_ec_seckey_tweak_add, [:pointer, :pointer, :pointer], :int
83
+ attach_function :secp256k1_ec_seckey_tweak_mul, [:pointer, :pointer, :pointer], :int
84
+
85
+ attach_optional_group(:recovery) do
86
+ attach_function :secp256k1_ecdsa_recoverable_signature_parse_compact, [:pointer, :pointer, :pointer, :int], :int
87
+ attach_function :secp256k1_ecdsa_recoverable_signature_convert, [:pointer, :pointer, :pointer], :int
88
+ attach_function :secp256k1_ecdsa_recoverable_signature_serialize_compact, [:pointer, :pointer, :pointer, :pointer], :int
89
+ attach_function :secp256k1_ecdsa_sign_recoverable, [:pointer, :pointer, :pointer, :pointer, :pointer, :pointer], :int
90
+ attach_function :secp256k1_ecdsa_recover, [:pointer, :pointer, :pointer, :pointer], :int
91
+ end
92
+
93
+ attach_optional_group(:ecdh) do
94
+ attach_function :secp256k1_ecdh, [:pointer, :pointer, :pointer, :pointer, :pointer, :pointer], :int
95
+ end
96
+
97
+ def self.module_recovery_enabled?
98
+ module_enabled?(:recovery)
99
+ end
100
+
101
+ def self.module_ecdh_enabled?
102
+ module_enabled?(:ecdh)
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,5 @@
1
+ require "secp256k1/bindings"
2
+
3
+ module Secp256k1
4
+ C = Bindings unless const_defined?(:C)
5
+ end
@@ -0,0 +1,99 @@
1
+ module Secp256k1
2
+ module ECDSA
3
+ SIZE_SERIALIZED = 74
4
+ SIZE_COMPACT = 64
5
+
6
+ def ecdsa_serialize(raw_sig)
7
+ output = pointer(:uchar, SIZE_SERIALIZED)
8
+ outputlen = size_pointer(SIZE_SERIALIZED)
9
+
10
+ res = C.secp256k1_ecdsa_signature_serialize_der(@ctx, output, outputlen, raw_sig)
11
+ raise AssertError, "failed to seriazlie signature" unless res == 1
12
+
13
+ read_bytes(output, outputlen.read_uint)
14
+ end
15
+
16
+ def ecdsa_deserialize(ser_sig)
17
+ raw_sig = C::ECDSASignature.new.pointer
18
+
19
+ res = C.secp256k1_ecdsa_signature_parse_der(@ctx, raw_sig, ser_sig, ser_sig.size)
20
+ raise AssertError, "raw signature parse failed" unless res == 1
21
+
22
+ raw_sig
23
+ end
24
+
25
+ def ecdsa_serialize_compact(raw_sig)
26
+ output = pointer(:uchar, SIZE_COMPACT)
27
+
28
+ res = C.secp256k1_ecdsa_signature_serialize_compact(@ctx, output, raw_sig)
29
+ raise AssertError, "failed to seriazlie compact signature" unless res == 1
30
+
31
+ read_bytes(output, SIZE_COMPACT)
32
+ end
33
+
34
+ def ecdsa_deserialize_compact(ser_sig)
35
+ raise ArgumentError, "invalid signature length" unless ser_sig.size == 64
36
+
37
+ raw_sig = C::ECDSASignature.new.pointer
38
+
39
+ res = C.secp256k1_ecdsa_signature_parse_compact(@ctx, raw_sig, ser_sig)
40
+ raise AssertError, "failed to deserialize compact signature" unless res == 1
41
+
42
+ raw_sig
43
+ end
44
+
45
+ ##
46
+ # Check and optionally convert a signature to a normalized lower-S form. If
47
+ # check_only is `true` then the normalized signature is not returned.
48
+ #
49
+ # This function always return a tuple containing a boolean (`true` if not
50
+ # previously normalized or `false` if signature was already normalized),
51
+ # and the normalized signature. When check_only is `true`, the normalized
52
+ # signature returned is always `nil`.
53
+ #
54
+ def ecdsa_signature_normalize(raw_sig, check_only: false)
55
+ sigout = check_only ? nil : C::ECDSASignature.new.pointer
56
+ res = C.secp256k1_ecdsa_signature_normalize(@ctx, sigout, raw_sig)
57
+ [res == 1, sigout]
58
+ end
59
+
60
+ def ecdsa_recover(msg, recover_sig, raw: false, digest: Digest::SHA256)
61
+ raise AssertError, "instance not configured for ecdsa recover" if (@flags & ALL_FLAGS) != ALL_FLAGS
62
+
63
+ msg32 = hash32 msg, raw, digest
64
+ pubkey = C::Pubkey.new.pointer
65
+
66
+ res = C.secp256k1_ecdsa_recover(@ctx, pubkey, recover_sig, msg32)
67
+ raise AssertError, "failed to recover ECDSA public key" unless res == 1
68
+
69
+ pubkey
70
+ end
71
+
72
+ def ecdsa_recoverable_serialize(recover_sig)
73
+ output = pointer(:uchar, SIZE_COMPACT)
74
+ recid = pointer(:int)
75
+
76
+ C.secp256k1_ecdsa_recoverable_signature_serialize_compact(@ctx, output, recid, recover_sig)
77
+
78
+ [read_bytes(output, SIZE_COMPACT), recid.read_int]
79
+ end
80
+
81
+ def ecdsa_recoverable_deserialize(ser_sig, rec_id)
82
+ raise ArgumentError, "invalid rec_id" if rec_id < 0 || rec_id > 3
83
+ raise ArgumentError, "invalid signature length" if ser_sig.size != 64
84
+
85
+ recover_sig = C::ECDSARecoverableSignature.new.pointer
86
+
87
+ res = C.secp256k1_ecdsa_recoverable_signature_parse_compact(@ctx, recover_sig, ser_sig, rec_id)
88
+ raise AssertError, "failed to parse ECDSA compact sig" unless res == 1
89
+
90
+ recover_sig
91
+ end
92
+
93
+ def ecdsa_recoverable_convert(recover_sig)
94
+ normal_sig = C::ECDSASignature.new.pointer
95
+ C.secp256k1_ecdsa_recoverable_signature_convert(@ctx, normal_sig, recover_sig)
96
+ normal_sig
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,271 @@
1
+ require "digest"
2
+ require "securerandom"
3
+
4
+ module Secp256k1
5
+ class BaseKey
6
+ def initialize(ctx, flags)
7
+ @destroy = false
8
+
9
+ unless ctx
10
+ raise ArgumentError, "invalid flags" unless [NO_FLAGS, FLAG_SIGN, FLAG_VERIFY, ALL_FLAGS].include?(flags)
11
+ ctx = FFI::AutoPointer.new C.secp256k1_context_create(flags), C.method(:secp256k1_context_destroy)
12
+ @destroy = true
13
+ end
14
+
15
+ @flags = flags
16
+ @ctx = ctx
17
+ end
18
+ end
19
+
20
+ class PublicKey < BaseKey
21
+ include Utils
22
+ include ECDSA
23
+
24
+ attr_accessor :public_key
25
+
26
+ def initialize(pubkey: nil, raw: false, flags: FLAG_VERIFY, ctx: nil)
27
+ super(ctx, flags)
28
+
29
+ if pubkey
30
+ if raw
31
+ raise ArgumentError, "raw pubkey must be bytes" unless pubkey.instance_of?(String)
32
+ @public_key = deserialize pubkey
33
+ else
34
+ @public_key = pubkey
35
+ end
36
+ else
37
+ @public_key = nil
38
+ end
39
+ end
40
+
41
+ def serialize(compressed: true)
42
+ raise AssertError, "No public key defined" unless @public_key
43
+
44
+ len_compressed = compressed ? 33 : 65
45
+ res_compressed = pointer(:char, len_compressed)
46
+ outlen = size_pointer(len_compressed)
47
+ compflag = compressed ? EC_COMPRESSED : EC_UNCOMPRESSED
48
+
49
+ res = C.secp256k1_ec_pubkey_serialize(@ctx, res_compressed, outlen, @public_key, compflag)
50
+ raise AssertError, "pubkey serialization failed" unless res == 1
51
+
52
+ read_bytes(res_compressed, len_compressed)
53
+ end
54
+
55
+ def deserialize(pubkey_ser)
56
+ raise ArgumentError, "unknown public key size (expected 33 or 65)" unless [33, 65].include?(pubkey_ser.size)
57
+
58
+ pubkey = C::Pubkey.new.pointer
59
+
60
+ res = C.secp256k1_ec_pubkey_parse(@ctx, pubkey, pubkey_ser, pubkey_ser.size)
61
+ raise AssertError, "invalid public key" unless res == 1
62
+
63
+ @public_key = pubkey
64
+ pubkey
65
+ end
66
+
67
+ ##
68
+ # Add a number of public keys together.
69
+ #
70
+ def combine(pubkeys)
71
+ raise ArgumentError, "must give at least 1 pubkey" if pubkeys.empty?
72
+
73
+ outpub = C::Pubkey.new.pointer
74
+ pointers = pubkeys.map { |item| extract_pubkey_pointer(item) }
75
+
76
+ pubkey_ptrs = FFI::MemoryPointer.new(:pointer, pointers.size)
77
+ pubkey_ptrs.write_array_of_pointer(pointers)
78
+
79
+ res = C.secp256k1_ec_pubkey_combine(@ctx, outpub, pubkey_ptrs, pointers.size)
80
+ raise AssertError, "failed to combine public keys" unless res == 1
81
+
82
+ @public_key = outpub
83
+ outpub
84
+ end
85
+
86
+ ##
87
+ # Tweak the current public key by adding a 32 byte scalar times the
88
+ # generator to it and return a new PublicKey instance.
89
+ #
90
+ def tweak_add(scalar)
91
+ tweak_public :secp256k1_ec_pubkey_tweak_add, scalar
92
+ end
93
+
94
+ ##
95
+ # Tweak the current public key by multiplying it by a 32 byte scalar and
96
+ # return a new PublicKey instance.
97
+ #
98
+ def tweak_mul(scalar)
99
+ tweak_public :secp256k1_ec_pubkey_tweak_mul, scalar
100
+ end
101
+
102
+ def ecdsa_verify(msg, raw_sig, raw: false, digest: Digest::SHA256)
103
+ raise AssertError, "No public key defined" unless @public_key
104
+ raise AssertError, "instance not configured for sig verification" if (@flags & FLAG_VERIFY) != FLAG_VERIFY
105
+
106
+ msg32 = hash32 msg, raw, digest
107
+
108
+ C.secp256k1_ecdsa_verify(@ctx, raw_sig, msg32, @public_key) == 1
109
+ end
110
+
111
+ def ecdh(scalar)
112
+ raise AssertError, "No public key defined" unless @public_key
113
+ raise ArgumentError, "scalar must be composed of 32 bytes" unless scalar.instance_of?(String) && scalar.size == 32
114
+
115
+ C.ensure_capability!(:ecdh)
116
+
117
+ result = pointer(:uchar, 32)
118
+ scalar_ptr = bytes_pointer(scalar)
119
+
120
+ res = C.secp256k1_ecdh @ctx, result, @public_key, scalar_ptr, nil, nil
121
+ raise AssertError, "invalid scalar (#{scalar})" unless res == 1
122
+ read_bytes(result, 32)
123
+ end
124
+
125
+ private
126
+
127
+ def extract_pubkey_pointer(value)
128
+ case value
129
+ when nil
130
+ raise ArgumentError, "pubkey cannot be nil"
131
+ when self.class
132
+ value.public_key
133
+ when C::Pubkey
134
+ value.pointer
135
+ else
136
+ value.respond_to?(:pointer) ? value.pointer : value
137
+ end
138
+ end
139
+
140
+ def tweak_public(meth, scalar)
141
+ raise ArgumentError, "scalar must be composed of 32 bytes" unless scalar.instance_of?(String) && scalar.size == 32
142
+ raise AssertError, "No public key defined." unless @public_key
143
+
144
+ newpub = self.class.new pubkey: serialize, raw: true
145
+
146
+ scalar_ptr = bytes_pointer(scalar)
147
+
148
+ res = C.send meth, @ctx, newpub.public_key, scalar_ptr
149
+ raise AssertError, "Tweak is out of range" unless res == 1
150
+
151
+ newpub
152
+ end
153
+ end
154
+
155
+ class PrivateKey < BaseKey
156
+ include Utils
157
+ include ECDSA
158
+
159
+ attr_reader :pubkey
160
+
161
+ def initialize(privkey: nil, raw: true, flags: ALL_FLAGS, ctx: nil)
162
+ raise AssertError, "invalid flags" unless [ALL_FLAGS, FLAG_SIGN].include?(flags)
163
+
164
+ super(ctx, flags)
165
+
166
+ @pubkey = nil
167
+ @private_key = nil
168
+
169
+ if privkey
170
+ if raw
171
+ raise ArgumentError, "privkey must be composed of 32 bytes" unless privkey.instance_of?(String) && privkey.size == 32
172
+ set_raw_privkey privkey
173
+ else
174
+ deserialize privkey
175
+ end
176
+ else
177
+ set_raw_privkey generate_private_key
178
+ end
179
+ end
180
+
181
+ def ecdsa_sign(msg, raw: false, digest: Digest::SHA256)
182
+ msg32 = hash32 msg, raw, digest
183
+ raw_sig = C::ECDSASignature.new.pointer
184
+
185
+ res = C.secp256k1_ecdsa_sign @ctx, raw_sig, msg32, @private_key, nil, nil
186
+ raise AssertError, "failed to sign" unless res == 1
187
+
188
+ raw_sig
189
+ end
190
+
191
+ def ecdsa_sign_recoverable(msg, raw: false, digest: Digest::SHA256)
192
+ C.ensure_capability!(:recovery)
193
+
194
+ msg32 = hash32 msg, raw, digest
195
+ raw_sig = C::ECDSARecoverableSignature.new.pointer
196
+
197
+ res = C.secp256k1_ecdsa_sign_recoverable @ctx, raw_sig, msg32, @private_key, nil, nil
198
+ raise AssertError, "failed to sign" unless res == 1
199
+
200
+ raw_sig
201
+ end
202
+
203
+ def set_raw_privkey(privkey)
204
+ raise ArgumentError, "invalid private key" unless C.secp256k1_ec_seckey_verify(@ctx, privkey)
205
+ @private_key = privkey
206
+ update_public_key
207
+ end
208
+
209
+ ##
210
+ # Tweak the current private key by adding a 32 bytes scalar to it and
211
+ # return a new raw private key composed of 32 bytes.
212
+ #
213
+ def tweak_add(scalar)
214
+ tweak_private :secp256k1_ec_seckey_tweak_add, scalar
215
+ end
216
+
217
+ ##
218
+ # Tweak the current private key by multiplying it by a 32 byte scalar and
219
+ # return a new raw private key composed of 32 bytes.
220
+ #
221
+ def tweak_mul(scalar)
222
+ tweak_private :secp256k1_ec_seckey_tweak_mul, scalar
223
+ end
224
+
225
+ private
226
+
227
+ def tweak_private(meth, scalar)
228
+ raise ArgumentError, "scalar must be composed of 32 bytes" unless scalar.instance_of?(String) && scalar.size == 32
229
+
230
+ key = bytes_pointer(@private_key)
231
+
232
+ scalar_ptr = bytes_pointer(scalar)
233
+
234
+ res = C.send meth, @ctx, key, scalar_ptr
235
+ raise AssertError, "Tweak is out of range" unless res == 1
236
+
237
+ read_bytes(key, 32)
238
+ end
239
+
240
+ def update_public_key
241
+ public_key = generate_public_key @private_key
242
+ @pubkey = PublicKey.new pubkey: public_key, raw: false, ctx: @ctx, flags: @flags
243
+ end
244
+
245
+ def generate_public_key(privkey)
246
+ pubkey_ptr = C::Pubkey.new.pointer
247
+
248
+ res = C.secp256k1_ec_pubkey_create @ctx, pubkey_ptr, privkey
249
+ raise AssertError, "failed to generate public key" unless res == 1
250
+
251
+ pubkey_ptr
252
+ end
253
+
254
+ def generate_private_key
255
+ SecureRandom.random_bytes(32)
256
+ end
257
+
258
+ def serialize
259
+ encode_hex @private_key
260
+ end
261
+
262
+ def deserialize(privkey_serialized)
263
+ raise ArgumentError, "invalid private key" unless privkey_serialized.size == 64
264
+
265
+ rawkey = decode_hex privkey_serialized
266
+ set_raw_privkey rawkey
267
+
268
+ @private_key
269
+ end
270
+ end
271
+ end
@@ -0,0 +1,38 @@
1
+ require "ffi"
2
+
3
+ module Secp256k1
4
+ module Utils
5
+ extend self
6
+
7
+ def pointer(type, count = 1)
8
+ FFI::MemoryPointer.new(type, count)
9
+ end
10
+
11
+ def size_pointer(initial_value)
12
+ pointer(:size_t).tap { |ptr| ptr.write_uint(initial_value) }
13
+ end
14
+
15
+ def bytes_pointer(bytes)
16
+ raise ArgumentError, "bytes must be a String" unless bytes.is_a?(String)
17
+ pointer(:uchar, bytes.bytesize).tap { |ptr| ptr.put_bytes(0, bytes) }
18
+ end
19
+
20
+ def read_bytes(buffer, length)
21
+ buffer.read_bytes(length)
22
+ end
23
+
24
+ def hash32(msg, raw, digest)
25
+ msg32 = raw ? msg : digest.digest(msg)
26
+ raise AssertError, "digest function must produce 256 bits" unless msg32.size == 32
27
+ msg32
28
+ end
29
+
30
+ def encode_hex(b)
31
+ b.unpack1("H*")
32
+ end
33
+
34
+ def decode_hex(s)
35
+ [s].pack("H*")
36
+ end
37
+ end
38
+ end
data/lib/secp256k1.rb ADDED
@@ -0,0 +1,19 @@
1
+ # -*- encoding : ascii-8bit -*-
2
+
3
+ require "secp256k1/c"
4
+ require "secp256k1/utils"
5
+ require "secp256k1/ecdsa"
6
+ require "secp256k1/key"
7
+
8
+ module Secp256k1
9
+ EC_COMPRESSED = C::Constants["SECP256K1_EC_COMPRESSED"].to_i
10
+ EC_UNCOMPRESSED = C::Constants["SECP256K1_EC_UNCOMPRESSED"].to_i
11
+
12
+ FLAG_SIGN = C::Constants["SECP256K1_CONTEXT_SIGN"].to_i
13
+ FLAG_VERIFY = C::Constants["SECP256K1_CONTEXT_VERIFY"].to_i
14
+ NO_FLAGS = C::Constants["SECP256K1_CONTEXT_NONE"].to_i
15
+ ALL_FLAGS = FLAG_SIGN | FLAG_VERIFY
16
+
17
+ class AssertError < StandardError; end
18
+ class LoadModuleError < StandardError; end
19
+ end
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: libsecp256k1
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.6.1
5
+ platform: ruby
6
+ authors:
7
+ - Weiliang Li
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: ffi
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '1.17'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '1.17'
26
+ description: A Ruby FFI binding for bitcoin's secp256k1 library, superseding ruby-bitcoin-secp256k1.
27
+ email: to.be.impressive@gmail.com
28
+ executables: []
29
+ extensions: []
30
+ extra_rdoc_files: []
31
+ files:
32
+ - CHANGELOG.md
33
+ - LICENSE
34
+ - README.md
35
+ - lib/secp256k1.rb
36
+ - lib/secp256k1/bindings.rb
37
+ - lib/secp256k1/c.rb
38
+ - lib/secp256k1/ecdsa.rb
39
+ - lib/secp256k1/key.rb
40
+ - lib/secp256k1/utils.rb
41
+ homepage: https://github.com/ecies/libsecp256k1-rb
42
+ licenses:
43
+ - MIT
44
+ metadata: {}
45
+ rdoc_options: []
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '3.2'
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ requirements: []
59
+ rubygems_version: 3.6.9
60
+ specification_version: 4
61
+ summary: A Ruby FFI binding for bitcoin's secp256k1 library
62
+ test_files: []