rbsecp256k1 3.0.1 → 5.1.0
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 +4 -4
- data/README.md +15 -5
- data/Rakefile +2 -0
- data/documentation/context.md +81 -0
- data/documentation/index.md +319 -0
- data/documentation/key_pair.md +28 -0
- data/documentation/private_key.md +25 -0
- data/documentation/public_key.md +32 -0
- data/documentation/recoverable_signature.md +30 -0
- data/documentation/secp256k1.md +19 -0
- data/documentation/shared_secret.md +16 -0
- data/documentation/signature.md +42 -0
- data/documentation/util.md +17 -0
- data/ext/rbsecp256k1/extconf.rb +11 -56
- data/ext/rbsecp256k1/rbsecp256k1.c +291 -297
- data/lib/rbsecp256k1/context.rb +29 -0
- data/lib/rbsecp256k1/util.rb +2 -0
- data/lib/rbsecp256k1/version.rb +3 -1
- data/lib/rbsecp256k1.rb +3 -0
- metadata +29 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 911e42c1184881dc8aa0fd52c833b5c5cc092d5ef04c1d264755acfa9668545b
|
4
|
+
data.tar.gz: 808c994ea9dd8965deb16feb82393a044a69fdeeada0654f64031fa74e4b4761
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8038fffce14eb3e4b5fdb41f7001349823f4cf0a2b291fca66e6d024e75e4f5e58c1286d7d8473f5daf05016740c61e7d056b6c2c6b118e367bf3a532451e78c
|
7
|
+
data.tar.gz: 5430aaefc5a6c8e8ea348d39a425ce48943f3a467744182f68a170bc8784877b95d07c4d66c0351cb7860de4f01b71661d87e70e422a1f382fe0a48dae89e663
|
data/README.md
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
# rbsecp256k1
|
2
2
|
|
3
|
-
[](https://github.com/etscrivner/rbsecp256k1/actions/workflows/spec.yml) [](https://badge.fury.io/rb/rbsecp256k1) [](https://codeclimate.com/github/etscrivner/rbsecp256k1/maintainability)
|
4
4
|
|
5
|
-
|
6
|
-
and later libsecp256k1 is bundled with the gem.
|
5
|
+
Native extension gem for secp256k1 ECDSA. Wraps [libsecp256k1](https://github.com/bitcoin-core/secp256k1). In
|
6
|
+
rbsecp256k1 3.0.0 and later libsecp256k1 is bundled with the gem.
|
7
7
|
|
8
|
-
[Documentation](documentation/index.md)
|
8
|
+
* [Documentation](https://github.com/etscrivner/rbsecp256k1/blob/master/documentation/index.md)
|
9
|
+
* [Examples](https://github.com/etscrivner/rbsecp256k1/blob/master/examples/README.md)
|
9
10
|
|
10
11
|
### Why wrap libsecp256k1?
|
11
12
|
|
@@ -16,6 +17,9 @@ faster than the OpenSSL implementation of the same curve. It is the only library
|
|
16
17
|
that provides constant time signing of this curve and has been deployed as part
|
17
18
|
of Bitcoin since [v0.10.0](https://bitcoin.org/en/release/v0.10.0#improved-signing-security)
|
18
19
|
|
20
|
+
Natively wrapping the library in an extension gem means users don't have to
|
21
|
+
worry about compiling or locating the library, unlike many [FFI](https://github.com/ffi/ffi) based gems.
|
22
|
+
|
19
23
|
## Installation
|
20
24
|
|
21
25
|
The simplest installation:
|
@@ -55,7 +59,7 @@ brew install openssl libtool pkg-config gmp libffi
|
|
55
59
|
|
56
60
|
## Features
|
57
61
|
|
58
|
-
See [rbsecp256k1 documentation](documentation/index.md) for examples and complete list of supported functionality.
|
62
|
+
See [rbsecp256k1 documentation](https://github.com/etscrivner/rbsecp256k1/blob/master/documentation/index.md) for examples and complete list of supported functionality.
|
59
63
|
|
60
64
|
## Development
|
61
65
|
|
@@ -108,6 +112,12 @@ To test with both disabled run:
|
|
108
112
|
make test WITH_RECOVERY=0 WITH_ECDH=0
|
109
113
|
```
|
110
114
|
|
115
|
+
Testing for memory leaks with valgrind:
|
116
|
+
|
117
|
+
```
|
118
|
+
make memcheck
|
119
|
+
```
|
120
|
+
|
111
121
|
### Building Gem
|
112
122
|
|
113
123
|
```
|
data/Rakefile
CHANGED
@@ -0,0 +1,81 @@
|
|
1
|
+
[Index](index.md)
|
2
|
+
|
3
|
+
Secp256k1::Context
|
4
|
+
==================
|
5
|
+
|
6
|
+
Secp256k1::Context represents a libsecp256k1 context object. Contexts are
|
7
|
+
thread-safe and initialization is expensive, so a single context should be used
|
8
|
+
for multiple operations as much as possible.
|
9
|
+
|
10
|
+
Initializers
|
11
|
+
------------
|
12
|
+
|
13
|
+
#### new(context_randomization_bytes: nil)
|
14
|
+
|
15
|
+
Returns a newly initialized libsecp256k1 context. The context is randomized at
|
16
|
+
initialization if given `context_randomization_bytes`. The
|
17
|
+
`context_randomization_bytes` argument can optionally take a string containing
|
18
|
+
32 bytes of random data, if not provided then the Context is not randomized and
|
19
|
+
may be vulnerable to side-channel attacks.
|
20
|
+
|
21
|
+
Class Methods
|
22
|
+
-------------
|
23
|
+
|
24
|
+
#### create
|
25
|
+
|
26
|
+
Creates and returns a new randomized `Context` using `SecureRandom` for the
|
27
|
+
random initialization bytes. This is the recommended method for initialization.
|
28
|
+
|
29
|
+
#### create_unrandomized
|
30
|
+
|
31
|
+
Creates a new unrandomized `Context`.
|
32
|
+
|
33
|
+
Instance Methods
|
34
|
+
----------------
|
35
|
+
|
36
|
+
#### ecdh(point, scalar)
|
37
|
+
|
38
|
+
**Requires:** libsecp256k1 was built with the experimental ECDH module.
|
39
|
+
|
40
|
+
Takes a `point` ([PublicKey](public_key.md)) and a `scalar` ([PrivateKey](private_key.md)) and returns a new
|
41
|
+
[SharedSecret](shared_secret.md) containing the 32-byte shared secret. Raises a `Secp256k1::Error` if
|
42
|
+
the `scalar` is invalid (zero or causes an overflow).
|
43
|
+
|
44
|
+
#### generate_key_pair
|
45
|
+
|
46
|
+
Generates and returns a new [KeyPair](key_pair.md) using a cryptographically
|
47
|
+
secure random number generator (CSRNG) provided by OpenSSL.
|
48
|
+
|
49
|
+
#### key_pair_from_private_key(private_key_data)
|
50
|
+
|
51
|
+
Returns a new [KeyPair](key_pair.md) from the given `private_key_data`. The
|
52
|
+
`private_key_data` is expected to be a binary string. Raises a `Secp256k1::Error`
|
53
|
+
if the private key is invalid or key derivation fails.
|
54
|
+
|
55
|
+
#### recoverable_signature_from_compact(compact_signature, recovery_id)
|
56
|
+
|
57
|
+
**Requires:** libsecp256k1 was build with recovery module.
|
58
|
+
|
59
|
+
Attempts to load a [RecoverableSignature](recoverable_signature.md) from the given `compact_signature`
|
60
|
+
and `recovery_id`. Raises a `Secp256k1::DeserializationError` if the signature data or recovery ID are invalid.
|
61
|
+
|
62
|
+
#### sign(private_key, hash32)
|
63
|
+
|
64
|
+
Signs the SHA-256 hash given by `hash32` using `private_key` and returns a new
|
65
|
+
[Signature](signature.md). The `private_key` is expected to be a [PrivateKey](private_key.md)
|
66
|
+
object and `data` can be either a binary string or text.
|
67
|
+
|
68
|
+
#### sign_recoverable(private_key, hash32)
|
69
|
+
|
70
|
+
**Requires:** libsecp256k1 was build with recovery module.
|
71
|
+
|
72
|
+
Signs the data represented by the SHA-256 hash `hash32` using `private_key` and returns a
|
73
|
+
new [RecoverableSignature](recoverable_signature.md). The `private_key` is expected to be a [PrivateKey](private_key.md) and
|
74
|
+
`data` can be either a binary string or text.
|
75
|
+
|
76
|
+
#### verify(signature, public_key, hash32)
|
77
|
+
|
78
|
+
Verifies the given `signature` ([Signature](signature.md)) was signed by
|
79
|
+
the private key corresponding to `public_key` ([PublicKey](public_key.md)) and signed `hash32`. Returns `true`
|
80
|
+
if `signature` is valid or `false` otherwise. Note that `data` can be either a
|
81
|
+
text or binary string.
|
@@ -0,0 +1,319 @@
|
|
1
|
+
rbsecp256k1 Reference
|
2
|
+
=====================
|
3
|
+
|
4
|
+
Find your topic in the index, or refer to one of the examples below.
|
5
|
+
|
6
|
+
Classes and Modules
|
7
|
+
-------------------
|
8
|
+
|
9
|
+
| Module | Classes | Utilities
|
10
|
+
|----------------------------|:-------------------------------------------------|:--------------------------------
|
11
|
+
| [Secp256k1](secp256k1.md) | [Context](context.md) | [Util](util.md)
|
12
|
+
| | [KeyPair](key_pair.md) |
|
13
|
+
| | [PublicKey](public_key.md) |
|
14
|
+
| | [PrivateKey](private_key.md) |
|
15
|
+
| | [SharedSecret](shared_secret.md) |
|
16
|
+
| | [Signature](signature.md) |
|
17
|
+
| | [RecoverableSignature](recoverable_signature.md) |
|
18
|
+
|
19
|
+
Glossary
|
20
|
+
--------
|
21
|
+
|
22
|
+
**[Context](context.md)** is a libsecp256k1 library context. It contains
|
23
|
+
pre-computed tables and values to make ECDSA signing and verification more
|
24
|
+
efficient.
|
25
|
+
|
26
|
+
**[KeyPair](key_pair.md)** is a Secp256k1 elliptic-curve key pair.
|
27
|
+
|
28
|
+
**[PublicKey](public_key.md)** is a Secp256k1 public key. It can come in either
|
29
|
+
compressed or uncompressed format.
|
30
|
+
|
31
|
+
**[PrivateKey](private_key.md)** is a 64-byte Secp256k1 private key.
|
32
|
+
|
33
|
+
**[SharedSecret](shared_secret.md)** A 32-byte shared secret computed from a
|
34
|
+
public key (point) and private key (scalar).
|
35
|
+
|
36
|
+
**[Signature](signature.md)** is an ECDSA signature of the SHA-256 message hash
|
37
|
+
of a piece of data.
|
38
|
+
|
39
|
+
**[RecoverableSignature](recoverable_signature.md)** is a recoverable ECDSA signature of the SHA-256 message
|
40
|
+
hash of a piece of data.
|
41
|
+
|
42
|
+
Examples
|
43
|
+
--------
|
44
|
+
|
45
|
+
### 1. Creating a libsecp256k1 context
|
46
|
+
|
47
|
+
This example demonstrates how to create a new libsecp256k1 context. This is the
|
48
|
+
first step of using this library:
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
context = Secp256k1::Context.create
|
52
|
+
# => #<Secp256k1::Context:0x0000559b0bd8f5d0>
|
53
|
+
```
|
54
|
+
|
55
|
+
### 2. Generating a key pair
|
56
|
+
|
57
|
+
This example shows how to generate a new public-private key pair:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
context = Secp256k1::Context.create
|
61
|
+
key_pair = context.generate_key_pair
|
62
|
+
# => #<Secp256k1::KeyPair:0x0000559b0bc876b0 @public_key=#<Secp256k1::PublicKey:0x0000559b0bc876d8>, @private_key=#<Secp256k1::PrivateKey:0x0000559b0bc87700 @data="\r\xA7\xB3<\x92\xCDw\xC1\xDB\xEB[BB;=\x80\xB83\xA8]\x06\xD9\x90\xF8v\xFFi\xF0/\x1E\x96\xF9">>
|
63
|
+
```
|
64
|
+
|
65
|
+
### 3. Getting compressed and uncompressed public key representations
|
66
|
+
|
67
|
+
This example shows how to generate compressed and uncompressed public keys:
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
context = Secp256k1::Context.create
|
71
|
+
key_pair = context.generate_key_pair
|
72
|
+
|
73
|
+
# 1. Get the binary representation of compressed public key
|
74
|
+
key_pair.public_key.compressed
|
75
|
+
# => "\x03D\x88\xD6 3|3\x836\xCB(\x9CW%\xF4T\xB7\xCD\x8AF T\xE7\xE8\xCE\xB0\xC7c{\xE2:\xFE"
|
76
|
+
|
77
|
+
# 2. Show hex representation of compressed public key
|
78
|
+
Secp256k1::Util.bin_to_hex(key_pair.public_key.compressed)
|
79
|
+
# => "034488d620337c338336cb289c5725f454b7cd8a462054e7e8ceb0c7637be23afe"
|
80
|
+
|
81
|
+
# 3. Get the binary representation of uncompressed public key
|
82
|
+
key_pair.public_key.uncompressed
|
83
|
+
# => "\x04D\x88\xD6 3|3\x836\xCB(\x9CW%\xF4T\xB7\xCD\x8AF T\xE7\xE8\xCE\xB0\xC7c{\xE2:\xFE XRew\x1F\e\x05\xC8\xDC\xA7\xE3\x8C\xBD\x91s?\xFCW\xD5\xB3\xA8aaCCG\xD4\x94m\xA5c"
|
84
|
+
|
85
|
+
# 4. Show hex representation of uncompressed public key
|
86
|
+
Secp256k1::Util.bin_to_hex(key_pair.public_key.uncompressed)
|
87
|
+
# => "044488d620337c338336cb289c5725f454b7cd8a462054e7e8ceb0c7637be23afe20585265771f1b05c8dca7e38cbd91733ffc57d5b3a86161434347d4946da563"
|
88
|
+
```
|
89
|
+
|
90
|
+
### 3. Signing a message
|
91
|
+
|
92
|
+
This example shows how to sign a message using your private key:
|
93
|
+
|
94
|
+
```ruby
|
95
|
+
require 'digest'
|
96
|
+
|
97
|
+
context = Secp256k1::Context.create
|
98
|
+
key_pair = context.generate_key_pair
|
99
|
+
|
100
|
+
signature = context.sign(key_pair.private_key, Digest::SHA256.digest("test message"))
|
101
|
+
# => #<Secp256k1::Signature:0x0000559b0bc79358>
|
102
|
+
```
|
103
|
+
|
104
|
+
### 4. Getting DER and Compact signature encodings
|
105
|
+
|
106
|
+
This example shows you how to get the DER encoded and compact encoded
|
107
|
+
representations of a signature:
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
require 'digest'
|
111
|
+
|
112
|
+
context = Secp256k1::Context.create
|
113
|
+
key_pair = context.generate_key_pair
|
114
|
+
|
115
|
+
signature = context.sign(key_pair.private_key, Digest::SHA256.digest("test message"))
|
116
|
+
|
117
|
+
# 1. Get the compact binary representation
|
118
|
+
signature.compact
|
119
|
+
# => "\xAB#e6_\x866\e\xAC\e\x92W\xC8a\x84N\xD4\xB6\x88\xF8\xEE\xDF\xFBC\xE8j\xB2\xF0\x10\xB8\xA0\x89\x13L\e\x9E\x91cB\xD7\xAC\x11\xF7\x02,Y&TM\xA5zp\xFD\xB3\xB1\xDCIV\xBB\\\xAF\x16@\xFC\x00"
|
120
|
+
|
121
|
+
# 2. Get the compact hex representation
|
122
|
+
Secp256k1::Util.bin_to_hex(signature.compact)
|
123
|
+
# => "ab2365365f86361bac1b9257c861844ed4b688f8eedffb43e86ab2f010b8a089134c1b9e916342d7ac11f7022c5926544da57a70fdb3b1dc4956bb5caf1640fc00"
|
124
|
+
|
125
|
+
# 3. Get the DER binary representation
|
126
|
+
signature.der_encoded
|
127
|
+
# => "0E\x02!\x00\xAB#e6_\x866\e\xAC\e\x92W\xC8a\x84N\xD4\xB6\x88\xF8\xEE\xDF\xFBC\xE8j\xB2\xF0\x10\xB8\xA0\x89\x02 \x13L\e\x9E\x91cB\xD7\xAC\x11\xF7\x02,Y&TM\xA5zp\xFD\xB3\xB1\xDCIV\xBB\\\xAF\x16@\xFC"
|
128
|
+
|
129
|
+
# 4. Get the DER hex representation
|
130
|
+
Secp256k1::Util.bin_to_hex(signature.der_encoded)
|
131
|
+
# => "3045022100ab2365365f86361bac1b9257c861844ed4b688f8eedffb43e86ab2f010b8a0890220134c1b9e916342d7ac11f7022c5926544da57a70fdb3b1dc4956bb5caf1640fc"
|
132
|
+
```
|
133
|
+
|
134
|
+
### 5. Verifying a signature
|
135
|
+
|
136
|
+
This example shows how to verify a signature using a public key:
|
137
|
+
|
138
|
+
```ruby
|
139
|
+
require 'digest'
|
140
|
+
|
141
|
+
context = Secp256k1::Context.create
|
142
|
+
key_pair = context.generate_key_pair
|
143
|
+
hash = Digest::SHA256.digest("test message")
|
144
|
+
|
145
|
+
signature = context.sign(key_pair.private_key, hash)
|
146
|
+
|
147
|
+
# 1. Verify signature against matching message
|
148
|
+
context.verify(signature, key_pair.public_key, hash)
|
149
|
+
# => true
|
150
|
+
|
151
|
+
# 2. Verify signature against different message
|
152
|
+
context.verify(signature, key_pair.public_key, hash)
|
153
|
+
# => false
|
154
|
+
```
|
155
|
+
|
156
|
+
### 6. Loading a private key or key pair from private key data
|
157
|
+
|
158
|
+
This example shows how to load a key pair from raw binary private key data:
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
context = Secp256k1::Context.create
|
162
|
+
|
163
|
+
#1. Load private key alone
|
164
|
+
private_key = Secp256k1::PrivateKey.from_data("I\nX\x85\xAEz}\n\x9B\xA4\\\x81)\xD4\x9Aq\xFDH\t\xBE\x8EP\xC5.\xC6\x1F7-\x86\xA0\xCB\xF9")
|
165
|
+
# => #<Secp256k1::PrivateKey:0x00005647df1bcd30 @data="I\nX\x85\xAEz}\n\x9B\xA4\\\x81)\xD4\x9Aq\xFDH\t\xBE\x8EP\xC5.\xC6\x1F7-\x86\xA0\xCB\xF9">
|
166
|
+
|
167
|
+
# 2. Load key pair from private key data
|
168
|
+
key_pair = context.key_pair_from_private_key("I\nX\x85\xAEz}\n\x9B\xA4\\\x81)\xD4\x9Aq\xFDH\t\xBE\x8EP\xC5.\xC6\x1F7-\x86\xA0\xCB\xF9")
|
169
|
+
# => #<Secp256k1::KeyPair:0x0000559b0bbf9a90 @public_key=#<Secp256k1::PublicKey:0x0000559b0bbf9ab8>, @private_key=#<Secp256k1::PrivateKey:0x0000559b0bbf9ae0 @data="I\nX\x85\xAEz}\n\x9B\xA4\\\x81)Ԛq\xFDH\t\xBE\x8EP\xC5.\xC6\u001F7-\x86\xA0\xCB\xF9">>
|
170
|
+
```
|
171
|
+
|
172
|
+
### 7. Loading a public key from binary data
|
173
|
+
|
174
|
+
This example shows how to load a public key from binary data:
|
175
|
+
|
176
|
+
```ruby
|
177
|
+
# 1. Load public key from uncompressed pubkey
|
178
|
+
public_key = Secp256k1::PublicKey.from_data("\x04$\xA2\xE7\xBB1\xC4|tN\xE6\xE4J-\xED\x9A[\xAFf-<\x14\x84^QQ\"\x14\xC3\x91\xE4\xF2\xB5\xEEEj\xAB\xD9\xFE\b\e7Zk\xC5{k\x12\xE3\xEA\xA2\xA5\xD7\xC1\xA5&\xE5|:K\xA9 X\xA3\x90")
|
179
|
+
# => #<Secp256k1::PublicKey:0x0000559b0bdc72f0>
|
180
|
+
|
181
|
+
# 2. Load public key from compressed pubkey
|
182
|
+
public_key = Secp256k1::PublicKey.from_data("\x02$\xA2\xE7\xBB1\xC4|tN\xE6\xE4J-\xED\x9A[\xAFf-<\x14\x84^QQ\"\x14\xC3\x91\xE4\xF2\xB5")
|
183
|
+
# => #<Secp256k1::PublicKey:0x0000559b0bdd3668>
|
184
|
+
```
|
185
|
+
|
186
|
+
### 8. Loading a DER or compact encoded signature
|
187
|
+
|
188
|
+
This example shows how to load signatures from binary data:
|
189
|
+
|
190
|
+
```ruby
|
191
|
+
# 1. From DER encoded signature
|
192
|
+
signature = Secp256k1::Signature.from_der_encoded("0D\x02 <\xC6\x7F/\x921l\x89Z\xFBs\x89p\xEE\x18u\x8B\x92\x9D\xA6\x84\xC5Y<t\xB7\xF1\f\xEE\f\x81J\x02 \t\"\xDF]\x1D\xA7W@^\xAAokH\b\x00\xE2L\xCF\x82\xA3\x05\x1E\x00\xF9\xFC\xB19\x0F\x93|\xB1f")
|
193
|
+
# => #<Secp256k1::Signature:0x0000559b0b823d58>
|
194
|
+
|
195
|
+
# 2. From compact signature
|
196
|
+
signature = Secp256k1::Signature.from_compact("<\xC6\x7F/\x921l\x89Z\xFBs\x89p\xEE\x18u\x8B\x92\x9D\xA6\x84\xC5Y<t\xB7\xF1\f\xEE\f\x81J\t\"\xDF]\x1D\xA7W@^\xAAokH\b\x00\xE2L\xCF\x82\xA3\x05\x1E\x00\xF9\xFC\xB19\x0F\x93|\xB1f\x00")
|
197
|
+
# => #<Secp256k1::Signature:0x0000559b0bdcaa68>
|
198
|
+
```
|
199
|
+
|
200
|
+
Recoverable Signature Examples
|
201
|
+
------------------------------
|
202
|
+
|
203
|
+
### 1. Checking for recovery module
|
204
|
+
|
205
|
+
To check if you have compiled the recovery module into your local libsecp256k1
|
206
|
+
run the following:
|
207
|
+
|
208
|
+
```ruby
|
209
|
+
Secp256k1.have_recovery?
|
210
|
+
# => true
|
211
|
+
```
|
212
|
+
|
213
|
+
### 2. Sign data producing recoverable signature
|
214
|
+
|
215
|
+
You can sign data producing a recoverable signature as follows:
|
216
|
+
|
217
|
+
```ruby
|
218
|
+
require 'digest'
|
219
|
+
|
220
|
+
hash = Digest::SHA256.digest('test message')
|
221
|
+
context = Secp256k1::Context.create
|
222
|
+
key_pair = context.generate_key_pair
|
223
|
+
|
224
|
+
signature = context.sign_recoverable(key_pair.private_key, hash)
|
225
|
+
# => #<Secp256k1::RecoverableSignature:0x000055f2ea76e548>
|
226
|
+
```
|
227
|
+
|
228
|
+
### 3. Serialize recoverable signature as compact representation
|
229
|
+
|
230
|
+
You can produce the compact binary serialization of a recoverable signature:
|
231
|
+
|
232
|
+
```ruby
|
233
|
+
require 'digest'
|
234
|
+
|
235
|
+
hash = Digest::SHA256.digest('test message')
|
236
|
+
context = Secp256k1::Context.create
|
237
|
+
key_pair = context.generate_key_pair
|
238
|
+
|
239
|
+
signature = context.sign_recoverable(key_pair.private_key, hash)
|
240
|
+
compact_data, recovery_id = signature.compact
|
241
|
+
# => ["D,\x9C\xA6%I\x14-\xCA\xC0\x11\x0F\xEB\x1E\xB0\xB6\\-\xE2\b\x98\xFB\xEA\xD5\x9BZ\xE6\xDF#\xC1\x1A\xEEL\xF02\xB1\xE9{\r\xEBhh<\\\xCF\xB6\x98\xEA\x8F\xF65\xF2\xBF\x84\xD8\xE5x\xF0\xA5)\xA2Wb\x9D", 1]
|
242
|
+
```
|
243
|
+
|
244
|
+
### 4. Recoverable signature from compact representation
|
245
|
+
|
246
|
+
You can load a recoverable signature give its compact representation and
|
247
|
+
recovery ID:
|
248
|
+
|
249
|
+
```ruby
|
250
|
+
context = Secp256k1::Context.create
|
251
|
+
|
252
|
+
compact_data = "D,\x9C\xA6%I\x14-\xCA\xC0\x11\x0F\xEB\x1E\xB0\xB6\\-\xE2\b\x98\xFB\xEA\xD5\x9BZ\xE6\xDF#\xC1\x1A\xEEL\xF02\xB1\xE9{\r\xEBhh<\\\xCF\xB6\x98\xEA\x8F\xF65\xF2\xBF\x84\xD8\xE5x\xF0\xA5)\xA2Wb\x9D"
|
253
|
+
recovery_id = 1
|
254
|
+
|
255
|
+
signature = context.recoverable_signature_from_compact(compact_data, recovery_id)
|
256
|
+
# => #<Secp256k1::RecoverableSignature:0x000055f2ea7615c8>
|
257
|
+
```
|
258
|
+
|
259
|
+
### 5. Convert recoverable signature to non-recoverable signature
|
260
|
+
|
261
|
+
You can convert a recoverable signature to a non-recoverable signature suitable
|
262
|
+
for use by all methods that take a [Signature](signature.md) object:
|
263
|
+
|
264
|
+
```ruby
|
265
|
+
require 'digest'
|
266
|
+
|
267
|
+
hash = Digest::SHA256.digest('test message')
|
268
|
+
context = Secp256k1::Context.create
|
269
|
+
key_pair = context.generate_key_pair
|
270
|
+
|
271
|
+
recoverable_signature = context.sign_recoverable(key_pair.private_key, hash)
|
272
|
+
signature = recoverable_signature.to_signature
|
273
|
+
# => #<Secp256k1::Signature:0x000055f2ea8ca4f0>
|
274
|
+
```
|
275
|
+
|
276
|
+
### 6. Recover public key from recoverable signature
|
277
|
+
|
278
|
+
You can recover the [PublicKey](public_key.md) associated with a recoverable signature:
|
279
|
+
|
280
|
+
```ruby
|
281
|
+
require 'digest'
|
282
|
+
|
283
|
+
hash = Digest::SHA256.digest('test message')
|
284
|
+
context = Secp256k1::Context.create
|
285
|
+
key_pair = context.generate_key_pair
|
286
|
+
|
287
|
+
recoverable_signature = context.sign_recoverable(key_pair.private_key, hash)
|
288
|
+
public_key = recoverable_signature.recover_public_key(hash)
|
289
|
+
# => #<Secp256k1::PublicKey:0x000055f2ea756678>
|
290
|
+
|
291
|
+
public_key == key_pair.public_key
|
292
|
+
# => true
|
293
|
+
```
|
294
|
+
|
295
|
+
EC Diffie-Hellman
|
296
|
+
-----------------
|
297
|
+
|
298
|
+
### 1. Checking for ECDH module
|
299
|
+
|
300
|
+
To check if you have compiled the ECDH module into your local libsecp256k1 run
|
301
|
+
the following:
|
302
|
+
|
303
|
+
```ruby
|
304
|
+
Secp256k1.have_ecdh?
|
305
|
+
# => true
|
306
|
+
```
|
307
|
+
|
308
|
+
### 2. Generating a shared secret
|
309
|
+
|
310
|
+
To generate a shared secret run the following:
|
311
|
+
|
312
|
+
```ruby
|
313
|
+
context = Secp256k1::Context.create
|
314
|
+
key_pair = context.generate_key_pair
|
315
|
+
|
316
|
+
shared_secret = context.ecdh(key_pair.public_key, key_pair.private_key)
|
317
|
+
shared_secret.data
|
318
|
+
# => "\x1FQ\x90X\xA5\xF2\xAEx;\xD7i\xB6\\T,2[\x90\xD1)a$\x1CA\x17\x8F\e\x91\xE3\x06C\x93"
|
319
|
+
```
|
@@ -0,0 +1,28 @@
|
|
1
|
+
[Index](index.md)
|
2
|
+
|
3
|
+
Secp256k1::KeyPair
|
4
|
+
==================
|
5
|
+
|
6
|
+
Secp256k1::KeyPair represents a public-private Secp256k1 key pair.
|
7
|
+
|
8
|
+
Initializers
|
9
|
+
------------
|
10
|
+
|
11
|
+
#### new(public_key, private_key)
|
12
|
+
|
13
|
+
Initializes a new key pair with `public_key` (type: [PublicKey](public_key.md)) and `private_key` (type: [PrivateKey](private_key.md)).
|
14
|
+
|
15
|
+
Instance Methods
|
16
|
+
----------------
|
17
|
+
|
18
|
+
#### public_key
|
19
|
+
|
20
|
+
Returns the [PublicKey](public_key.md) part of this key pair.
|
21
|
+
|
22
|
+
#### private_key
|
23
|
+
|
24
|
+
Returns the [PrivateKey](private_key.md) part of this key pair.
|
25
|
+
|
26
|
+
#### ==(other)
|
27
|
+
|
28
|
+
Returns `true` if the `other` has the same public and private key.
|
@@ -0,0 +1,25 @@
|
|
1
|
+
[Index](index.md)
|
2
|
+
|
3
|
+
Secp256k1::PrivateKey
|
4
|
+
=====================
|
5
|
+
|
6
|
+
Secp256k1::PrivateKey represents the private key part of a public-private key pair.
|
7
|
+
|
8
|
+
Class Methods
|
9
|
+
-------------
|
10
|
+
|
11
|
+
#### from_data(private_key_data)
|
12
|
+
|
13
|
+
Loads new private key from the given binary `private_key_data` string. Raises
|
14
|
+
`Secp256k1::Error` if the given data is invalid.
|
15
|
+
|
16
|
+
Instance Methods
|
17
|
+
----------------
|
18
|
+
|
19
|
+
#### data
|
20
|
+
|
21
|
+
Returns the binary private key data as a `String`.
|
22
|
+
|
23
|
+
#### ==(other)
|
24
|
+
|
25
|
+
Returns `true` if this private key matches `other`.
|
@@ -0,0 +1,32 @@
|
|
1
|
+
[Index](index.md)
|
2
|
+
|
3
|
+
Secp256k1::PublicKey
|
4
|
+
====================
|
5
|
+
|
6
|
+
Secp256k1::PublicKey represents the public key part of a public-private key pair.
|
7
|
+
|
8
|
+
See: [KeyPair](key_pair.md)
|
9
|
+
|
10
|
+
Class Methods
|
11
|
+
-------------
|
12
|
+
|
13
|
+
#### from_data(public_key_data)
|
14
|
+
|
15
|
+
Parses compressed or uncompressed from binary string `public_key_data` and
|
16
|
+
creates and returns a new public key from it. Raises a `Secp256k1::DeserializationError`
|
17
|
+
if the given public key data is invalid.
|
18
|
+
|
19
|
+
Instance Methods
|
20
|
+
----------------
|
21
|
+
|
22
|
+
#### compressed
|
23
|
+
|
24
|
+
Returns the binary compressed representation of this public key.
|
25
|
+
|
26
|
+
#### uncompressed
|
27
|
+
|
28
|
+
Returns the binary uncompressed representation of this public key.
|
29
|
+
|
30
|
+
#### ==(other)
|
31
|
+
|
32
|
+
Return `true` if this public key matches `other`.
|
@@ -0,0 +1,30 @@
|
|
1
|
+
[Index](index.md)
|
2
|
+
|
3
|
+
Secp256k1::RecoverableSignature
|
4
|
+
===============================
|
5
|
+
|
6
|
+
**Requires:** libsecp256k1 was build with recovery module.
|
7
|
+
|
8
|
+
Secp256k1::RecoverableSignature represents a recoverable ECDSA signature
|
9
|
+
signing the 32-byte SHA-256 hash of some data.
|
10
|
+
|
11
|
+
Instance Methods
|
12
|
+
----------------
|
13
|
+
|
14
|
+
#### compact
|
15
|
+
|
16
|
+
Returns an array whose first element is the 64-byte compact signature as a
|
17
|
+
binary string and whose second element is the integer recovery ID.
|
18
|
+
|
19
|
+
#### recover_public_key
|
20
|
+
|
21
|
+
Recovers the public key corresponding to the recoverable signature. Returns a
|
22
|
+
[PublicKey](public_key.md).
|
23
|
+
|
24
|
+
#### to_signature
|
25
|
+
|
26
|
+
Converts a recoverable signature to a non-recoverable [Signature](signature.md) object.
|
27
|
+
|
28
|
+
#### ==(other)
|
29
|
+
|
30
|
+
Returns `true` if this recoverable signature matches `other`.
|
@@ -0,0 +1,19 @@
|
|
1
|
+
[Index](index.md)
|
2
|
+
|
3
|
+
Secp256k1
|
4
|
+
=========
|
5
|
+
|
6
|
+
Secp256k1 is the top-level module for this library.
|
7
|
+
|
8
|
+
Class Methods
|
9
|
+
-------------
|
10
|
+
|
11
|
+
#### have_recovery?
|
12
|
+
|
13
|
+
Returns `true` if the recovery module was built with libsecp256k1, `false`
|
14
|
+
otherwise.
|
15
|
+
|
16
|
+
#### have_ecdh?
|
17
|
+
|
18
|
+
Returns `true` if the EC Diffie-Hellman module was built with libsecp256k1,
|
19
|
+
`false` otherwise.
|
@@ -0,0 +1,16 @@
|
|
1
|
+
[Index](index.md)
|
2
|
+
|
3
|
+
Secp256k1::SharedSecret
|
4
|
+
=======================
|
5
|
+
|
6
|
+
**Requires:** libsecp256k1 was build with ECDH module.
|
7
|
+
|
8
|
+
Secp256k1::SharedSecret represents a 32-byte shared secret computed from a
|
9
|
+
public key (point) and private key (scalar).
|
10
|
+
|
11
|
+
Instance Methods
|
12
|
+
----------------
|
13
|
+
|
14
|
+
#### data
|
15
|
+
|
16
|
+
Binary string containing the 32-byte shared secret.
|
@@ -0,0 +1,42 @@
|
|
1
|
+
[Index](index.md)
|
2
|
+
|
3
|
+
Secp256k1::Signature
|
4
|
+
====================
|
5
|
+
|
6
|
+
Secp256k1::Signature represents an ECDSA signature signing the 32-byte SHA-256
|
7
|
+
hash of some data.
|
8
|
+
|
9
|
+
Class Methods
|
10
|
+
-------------
|
11
|
+
|
12
|
+
#### from_compact(compact_signature)
|
13
|
+
|
14
|
+
Parses a signature from binary string `compact_signature`. Raises a
|
15
|
+
`Secp256k1::DeserializationError` if the signature data is invalid.
|
16
|
+
|
17
|
+
#### from_der_encoded(der_encoded_signature)
|
18
|
+
|
19
|
+
Parses a signature from binary string `der_encoded_signature`. Raises a
|
20
|
+
`Secp256k1::DeserializationError` if the signature data is invalid.
|
21
|
+
|
22
|
+
Instance Methods
|
23
|
+
----------------
|
24
|
+
|
25
|
+
#### der_encoded
|
26
|
+
|
27
|
+
Returns the DER encoded representation of this signature.
|
28
|
+
|
29
|
+
#### compact
|
30
|
+
|
31
|
+
Returns the compact 64-byte representation of this signature.
|
32
|
+
|
33
|
+
#### normalized
|
34
|
+
|
35
|
+
Returns an array containing two elements. The first is a Boolean indicating
|
36
|
+
whether or not the signature was normalized, false if it was already in lower-S
|
37
|
+
normal form. The second element is a `Signature` containing the normalized
|
38
|
+
signature object.
|
39
|
+
|
40
|
+
#### ==(other)
|
41
|
+
|
42
|
+
Returns `true` if this signature matches `other`.
|
@@ -0,0 +1,17 @@
|
|
1
|
+
[Index](index.md)
|
2
|
+
|
3
|
+
Secp256k1::Util
|
4
|
+
===============
|
5
|
+
|
6
|
+
Secp256k1::Util in a module containing generally useful methods for using the library.
|
7
|
+
|
8
|
+
Class Methods
|
9
|
+
-------------
|
10
|
+
|
11
|
+
#### bin_to_hex(binary_data)
|
12
|
+
|
13
|
+
Returns the hexadecimal string representation of `binary_data`
|
14
|
+
|
15
|
+
#### hex_to_bin(hex_string)
|
16
|
+
|
17
|
+
Returns the binary string representation of `hex_string`
|