x25519 0.0.0 → 0.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/.gitignore +3 -0
- data/.rubocop.yml +3 -0
- data/CHANGES.md +3 -0
- data/Gemfile +3 -2
- data/README.md +205 -14
- data/Rakefile +9 -1
- data/ext/x25519/cputest.c +68 -0
- data/ext/x25519/extconf.rb +31 -0
- data/ext/x25519/ref10/api.h +2 -0
- data/ext/x25519/ref10/base.c +12 -0
- data/ext/x25519/ref10/fe.h +44 -0
- data/ext/x25519/ref10/fe_0.c +19 -0
- data/ext/x25519/ref10/fe_1.c +19 -0
- data/ext/x25519/ref10/fe_add.c +57 -0
- data/ext/x25519/ref10/fe_copy.c +29 -0
- data/ext/x25519/ref10/fe_cswap.c +73 -0
- data/ext/x25519/ref10/fe_frombytes.c +67 -0
- data/ext/x25519/ref10/fe_invert.c +14 -0
- data/ext/x25519/ref10/fe_mul.c +252 -0
- data/ext/x25519/ref10/fe_mul121666.c +69 -0
- data/ext/x25519/ref10/fe_sq.c +148 -0
- data/ext/x25519/ref10/fe_sub.c +57 -0
- data/ext/x25519/ref10/fe_tobytes.c +119 -0
- data/ext/x25519/ref10/montgomery.h +140 -0
- data/ext/x25519/ref10/pow225521.h +160 -0
- data/ext/x25519/ref10/scalarmult.c +46 -0
- data/ext/x25519/{fp25519_x64.c → rfc7748_precomputed/fp25519_x64.c} +14 -16
- data/ext/x25519/{fp25519_x64.h → rfc7748_precomputed/fp25519_x64.h} +6 -10
- data/ext/x25519/{bytes.h → rfc7748_precomputed/rfc7748_precomputed.h} +13 -5
- data/ext/x25519/{table_ladder_x25519.h → rfc7748_precomputed/table_ladder_x25519.h} +0 -0
- data/ext/x25519/{x25519_x64.c → rfc7748_precomputed/x25519_x64.c} +16 -29
- data/ext/x25519/x25519.c +325 -0
- data/ext/x25519/x25519.h +24 -0
- data/x25519.gemspec +3 -6
- metadata +32 -15
- data/ext/x25519/bytes.c +0 -42
- data/ext/x25519/random.c +0 -51
- data/ext/x25519/random.h +0 -24
- data/ext/x25519/rfc7748_precompted.h +0 -49
- data/ext/x25519/rfc7748_precomputed.c +0 -20
- data/lib/x25519.rb +0 -7
- data/lib/x25519/version.rb +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 15e4b54930cad9efae470089ed69b14837394163
|
4
|
+
data.tar.gz: b64d42b7a3d9f39ebc2668ce489799ba2f849bef
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f1ccbe8cf45e64fa096399e1814059078a52c0148f51e299abf3b6faeeea88b81c5e913c668a467df999393bbe99ba5dbb67914094b6eda2634bb52690d4421d
|
7
|
+
data.tar.gz: 910e1e2d8a354c4d19a0c8b4bba50f4e452c64addcf7119f9359786eb640d94f73abfd1916ebaeb48fef8c77e034798afb337b1a10c64ce74587880232f0d548
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
data/CHANGES.md
ADDED
data/Gemfile
CHANGED
@@ -5,7 +5,8 @@ source "https://rubygems.org"
|
|
5
5
|
gemspec
|
6
6
|
|
7
7
|
group :development, :test do
|
8
|
-
gem "rake"
|
9
|
-
gem "
|
8
|
+
gem "rake", require: false
|
9
|
+
gem "rake-compiler", "~> 1.0", require: false
|
10
|
+
gem "rspec", "~> 3.7", require: false
|
10
11
|
gem "rubocop", "0.51.0", require: false
|
11
12
|
end
|
data/README.md
CHANGED
@@ -1,23 +1,35 @@
|
|
1
|
-
# x25519.rb
|
1
|
+
# x25519.rb [![Latest Version][gem-shield]][gem-link] [![Build Status][build-image]][build-link] [![License: LGPL v3][license-image]][license-link]
|
2
|
+
|
3
|
+
[gem-shield]: https://badge.fury.io/rb/x25519.svg
|
4
|
+
[gem-link]: https://rubygems.org/gems/x25519
|
5
|
+
[build-image]: https://travis-ci.org/cryptosphere/x25519.svg?branch=master
|
6
|
+
[build-link]: https://travis-ci.org/cryptosphere/x25519
|
7
|
+
[license-image]: https://img.shields.io/badge/License-LGPL%20v3-blue.svg
|
8
|
+
[license-link]: https://www.gnu.org/licenses/lgpl-3.0
|
2
9
|
|
3
10
|
An efficient public key cryptography library for Ruby providing key
|
4
11
|
exchange/agreement.
|
5
12
|
|
6
13
|
This gem implements X25519 (a.k.a. Curve25519) Elliptic Curve Diffie-Hellman
|
7
14
|
function as described in [RFC7748] as a C extension using the
|
8
|
-
high performance [
|
9
|
-
[How to (pre-)compute a ladder]
|
15
|
+
high performance [rfc7748_precomputed] implementation based on the paper
|
16
|
+
[How to (pre-)compute a ladder]
|
17
|
+
(with fallback to the ref10 C implementation).
|
10
18
|
|
11
19
|
[RFC7748]: https://tools.ietf.org/html/rfc7748
|
12
20
|
[How to (pre-)compute a ladder]: https://eprint.iacr.org/2017/264
|
13
21
|
[rfc7748_precomputed]: https://github.com/armfazh/rfc7748_precomputed
|
14
22
|
|
23
|
+
## Requirements
|
24
|
+
|
25
|
+
* MRI 2.2+
|
26
|
+
|
15
27
|
## Installation
|
16
28
|
|
17
29
|
Add this line to your application's Gemfile:
|
18
30
|
|
19
31
|
```ruby
|
20
|
-
gem
|
32
|
+
gem "x25519"
|
21
33
|
```
|
22
34
|
|
23
35
|
And then execute:
|
@@ -30,7 +42,165 @@ Or install it yourself as:
|
|
30
42
|
|
31
43
|
## Usage
|
32
44
|
|
33
|
-
|
45
|
+
The example below shows how to perform a full Diffie-Hellman key exchange:
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
require "x25519"
|
49
|
+
|
50
|
+
# Alice generates random scalar (private key)
|
51
|
+
alice_sk = X25519::Scalar.generate
|
52
|
+
|
53
|
+
# Alice obtains public key for her private key/scalar
|
54
|
+
alice_pk = alice_sk.public_key
|
55
|
+
|
56
|
+
# Bob generates random scalar (private key)
|
57
|
+
# Ostensibly this would be on a different computer somewhere
|
58
|
+
bob_sk = X25519::Scalar.generate
|
59
|
+
bob_pk = bob_sk.public_key
|
60
|
+
|
61
|
+
# Alice can perform Diffie-Hellman with Bob's public key
|
62
|
+
alice_secret = alice_sk.diffie_hellman(bob_pk).to_bytes
|
63
|
+
|
64
|
+
# Bob can perform Diffie-Hellman with Alice's public key
|
65
|
+
bob_secret = bob_sk.diffie_hellman(alice_pk).to_bytes
|
66
|
+
|
67
|
+
# The resulting secrets should be the same
|
68
|
+
alice_secret == bob_secret # true
|
69
|
+
```
|
70
|
+
|
71
|
+
## API
|
72
|
+
|
73
|
+
### `X25519::Scalar`: private keys
|
74
|
+
|
75
|
+
The `X25519::Scalar` class represents secret integers used as X25519 private
|
76
|
+
keys. These secret integers are multiplied by a well-known base point to
|
77
|
+
obtain X25519 public keys (`X25519::MontgomeryU`).
|
78
|
+
|
79
|
+
#### `X25519::Scalar.generate()`: make a random private key
|
80
|
+
|
81
|
+
Generate a random private scalar (using `SecureRandom`)
|
82
|
+
|
83
|
+
##### Example
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
secret_key = X25519::Scalar.generate
|
87
|
+
```
|
88
|
+
|
89
|
+
#### `X25519::Scalar.new(bytes)`: load existing private key
|
90
|
+
|
91
|
+
* `bytes`: a 32-byte `String` value containing the private key
|
92
|
+
|
93
|
+
##### Example
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
secret_key = X25519::Scalar.new(File.read("alice.key"))
|
97
|
+
```
|
98
|
+
|
99
|
+
#### `X25519::Scalar#public_key()`: obtain public key for this scalar
|
100
|
+
|
101
|
+
NOTE: The `#multiply_base` method is an alias of this one.
|
102
|
+
|
103
|
+
Performs fixed-base scalar multiplication (i.e. calculates public key)
|
104
|
+
|
105
|
+
##### Return Value
|
106
|
+
|
107
|
+
Returns a `X25519::MontgomeryU` object which represents the public key for this private key/scalar.
|
108
|
+
|
109
|
+
##### Example
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
secret_key = X25519::Scalar.generate
|
113
|
+
public_key = secret_key.public_key
|
114
|
+
```
|
115
|
+
|
116
|
+
#### `X25519::Scalar#diffie_hellman(other_public_key)`: obtain public key for this scalar
|
117
|
+
|
118
|
+
NOTE: The `#multiply` method is an alias of this one.
|
119
|
+
|
120
|
+
Performs variable-base scalar multiplication, computing a shared secret between
|
121
|
+
our private scalar and someone else's public key/point.
|
122
|
+
|
123
|
+
##### Return Value
|
124
|
+
|
125
|
+
Returns a `X25519::MontgomeryU` object which represents the shared secret.
|
126
|
+
|
127
|
+
##### Arguments
|
128
|
+
|
129
|
+
* `other_public_key`: a `X25519::MontgomeryU` object containing the public key
|
130
|
+
with which we'd like to compute a shared secret.
|
131
|
+
|
132
|
+
##### Example
|
133
|
+
|
134
|
+
```ruby
|
135
|
+
secret_key = X25519::Scalar.generate
|
136
|
+
public_key = X25519::MontgomeryU.new(File.read("bob.pub"))
|
137
|
+
|
138
|
+
# Returns an X25519::MontgomeryU
|
139
|
+
shared_secret = secret_key.multiply(public_key)
|
140
|
+
|
141
|
+
# Obtain the shared secret as a serialized byte representation
|
142
|
+
shared_secret_bytes = shared_secret.to_bytes
|
143
|
+
```
|
144
|
+
|
145
|
+
#### `X25519::Scalar#to_bytes`: serialize a scalar as a `String`
|
146
|
+
|
147
|
+
##### Return Value
|
148
|
+
|
149
|
+
Returns a `String` containing a byte representation of this scalar:
|
150
|
+
|
151
|
+
##### Example
|
152
|
+
|
153
|
+
```ruby
|
154
|
+
secret_key = X25519::Scalar.new(...)
|
155
|
+
File.write("alice.key", secret_key.to_bytes)
|
156
|
+
```
|
157
|
+
|
158
|
+
### `X25519::MontgomeryU`: public keys and shared secrets
|
159
|
+
|
160
|
+
The `X25519::MontgomeryU` class represents a coordinate (specifically a
|
161
|
+
Montgomery-u coordinate) on the elliptic curve. In the X25519 Diffie-Hellman
|
162
|
+
function, these serve both as public keys and as shared secrets.
|
163
|
+
|
164
|
+
#### `X25519::MontgomeryU.new(bytes)`: load existing public key
|
165
|
+
|
166
|
+
##### Arguments
|
167
|
+
|
168
|
+
* `bytes`: a 32-byte `String` value containing the public key
|
169
|
+
|
170
|
+
##### Example
|
171
|
+
|
172
|
+
```ruby
|
173
|
+
public_key = X25519::MontgomeryU.new(File.read("bob.pub"))
|
174
|
+
```
|
175
|
+
|
176
|
+
#### `X25519::MontgomeryU#to_bytes`: serialize a Montgomery-u coordinate as a `String`
|
177
|
+
|
178
|
+
##### Return Value
|
179
|
+
|
180
|
+
Returns a `String` containing a byte representation of a compressed Montgomery-u coordinate:
|
181
|
+
|
182
|
+
##### Example
|
183
|
+
|
184
|
+
```ruby
|
185
|
+
public_key = X25519::MontgomeryU..new(...)
|
186
|
+
File.write("bob.pub", public_key.to_bytes)
|
187
|
+
```
|
188
|
+
|
189
|
+
### `X25519`: module-level functionality
|
190
|
+
|
191
|
+
#### `X25519.diffie_hellman(secret_key, public_key)`: shorthand `String`-oriented API
|
192
|
+
|
193
|
+
If you'd like to avoid the object-oriented API, you can use a simplified API which
|
194
|
+
acts entirely on bytestrings.
|
195
|
+
|
196
|
+
##### Arguments
|
197
|
+
|
198
|
+
* `secret_key`: a 32-byte `String` containing a private scalar
|
199
|
+
* `public_key`: a 32-byte `String` containing a compressed Montgomery-u coordinate
|
200
|
+
|
201
|
+
##### Return Value
|
202
|
+
|
203
|
+
Returns a `String` containing a 32-byte compressed Montgomery-u coordinate
|
34
204
|
|
35
205
|
## Contributing
|
36
206
|
|
@@ -41,27 +211,48 @@ code of conduct.
|
|
41
211
|
|
42
212
|
## Implementation Details
|
43
213
|
|
214
|
+
This gem contains two implementations of X25519: an optimized assembly
|
215
|
+
implementation and a portable C implementation. Implementations are selected
|
216
|
+
based on available CPU features.
|
217
|
+
|
218
|
+
### [rfc7748_precomputed]: optimized assembly implementation
|
219
|
+
|
44
220
|
* Prime field arithmetic is optimized for the 4th and 6th generation of Intel Core processors (Haswell and Skylake micro-architectures).
|
45
221
|
* Efficient integer multiplication using MULX instruction.
|
46
222
|
* Integer additions accelerated with ADCX/ADOX instructions.
|
47
|
-
* Key generation uses a read-only table of 8 KB
|
223
|
+
* Key generation uses a read-only table of 8 KB for X25519.
|
224
|
+
|
225
|
+
### ref10: portable C implementation
|
226
|
+
|
227
|
+
* Taken from the [SUPERCOP] cryptographic benchmarking suite (supercop-20171020)
|
228
|
+
* Portable C code which should compile on any architecture
|
229
|
+
|
230
|
+
[SUPERCOP]: https://bench.cr.yp.to/supercop.html
|
48
231
|
|
49
232
|
## Designers
|
50
233
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
234
|
+
The X25519 Diffie-Hellman function was originally designed by Dan Bernstein:
|
235
|
+
|
236
|
+
https://cr.yp.to/ecdh.html
|
237
|
+
|
238
|
+
The optimized [rfc7748_precomputed] implementation was designed by:
|
239
|
+
|
240
|
+
* Thomaz Oliveira, Computer Science Department, Cinvestav-IPN, Mexico.
|
241
|
+
* Julio López, University of Campinas, Brazil.
|
242
|
+
* Hüseyin Hisil, Yasar University, Turkey.
|
243
|
+
* Armando Faz-Hernández, University of Campinas, Brazil.
|
244
|
+
* Francisco Rodríguez-Henríquez, Computer Science Department, Cinvestav-IPN, Mexico.
|
245
|
+
|
246
|
+
## Copyright and License
|
56
247
|
|
57
|
-
|
248
|
+
Copyright (c) 2017 Armando Faz, Tony Arcieri
|
58
249
|
|
59
|
-
|
250
|
+
This gem is available as open source under the terms of the
|
60
251
|
GNU Lesser General Public License v3.0 ([LICENSE](https://www.gnu.org/licenses/lgpl-3.0.txt))
|
61
252
|
|
62
253
|
## Code of Conduct
|
63
254
|
|
64
|
-
Everyone interacting in the
|
255
|
+
Everyone interacting in the x25519.rb project’s codebases, issue trackers, chat
|
65
256
|
rooms and mailing lists is expected to follow the [code of conduct].
|
66
257
|
|
67
258
|
[code of conduct]: https://github.com/cryptosphere/x25519/blob/master/CODE_OF_CONDUCT.md
|
data/Rakefile
CHANGED
@@ -2,10 +2,18 @@
|
|
2
2
|
|
3
3
|
require "bundler/gem_tasks"
|
4
4
|
|
5
|
+
require "rake/clean"
|
6
|
+
CLEAN.include("**/*.o", "**/*.so", "**/*.bundle", "pkg", "tmp")
|
7
|
+
|
8
|
+
require "rake/extensiontask"
|
9
|
+
Rake::ExtensionTask.new("x25519") do |ext|
|
10
|
+
ext.ext_dir = "ext/x25519"
|
11
|
+
end
|
12
|
+
|
5
13
|
require "rspec/core/rake_task"
|
6
14
|
RSpec::Core::RakeTask.new
|
7
15
|
|
8
16
|
require "rubocop/rake_task"
|
9
17
|
RuboCop::RakeTask.new
|
10
18
|
|
11
|
-
task default: %w[spec rubocop]
|
19
|
+
task default: %w[compile spec rubocop]
|
@@ -0,0 +1,68 @@
|
|
1
|
+
/*
|
2
|
+
Test for 4th generation Intel Core processor family features (e.g. Haswell)
|
3
|
+
From https://software.intel.com/en-us/articles/how-to-detect-new-instruction-support-in-the-4th-generation-intel-core-processor-family
|
4
|
+
*/
|
5
|
+
|
6
|
+
#include <stdint.h>
|
7
|
+
#if defined(_MSC_VER)
|
8
|
+
# include <intrin.h>
|
9
|
+
#endif
|
10
|
+
|
11
|
+
static void run_cpuid(uint32_t eax, uint32_t ecx, uint32_t* abcd)
|
12
|
+
{
|
13
|
+
#if defined(_MSC_VER)
|
14
|
+
__cpuidex(abcd, eax, ecx);
|
15
|
+
#else
|
16
|
+
uint32_t ebx = 0, edx;
|
17
|
+
# if defined( __i386__ ) && defined ( __PIC__ )
|
18
|
+
/* in case of PIC under 32-bit EBX cannot be clobbered */
|
19
|
+
__asm__ ( "movl %%ebx, %%edi \n\t cpuid \n\t xchgl %%ebx, %%edi" : "=D" (ebx),
|
20
|
+
# else
|
21
|
+
__asm__ ( "cpuid" : "+b" (ebx),
|
22
|
+
# endif
|
23
|
+
"+a" (eax), "+c" (ecx), "=d" (edx) );
|
24
|
+
abcd[0] = eax; abcd[1] = ebx; abcd[2] = ecx; abcd[3] = edx;
|
25
|
+
#endif
|
26
|
+
}
|
27
|
+
|
28
|
+
static int check_xcr0_ymm()
|
29
|
+
{
|
30
|
+
uint32_t xcr0;
|
31
|
+
#if defined(_MSC_VER)
|
32
|
+
xcr0 = (uint32_t)_xgetbv(0); /* min VS2010 SP1 compiler is required */
|
33
|
+
#else
|
34
|
+
__asm__ ("xgetbv" : "=a" (xcr0) : "c" (0) : "%edx" );
|
35
|
+
#endif
|
36
|
+
return ((xcr0 & 6) == 6); /* checking if xmm and ymm state are enabled in XCR0 */
|
37
|
+
}
|
38
|
+
|
39
|
+
int check_4th_gen_intel_core_features()
|
40
|
+
{
|
41
|
+
uint32_t abcd[4];
|
42
|
+
uint32_t fma_movbe_osxsave_mask = ((1 << 12) | (1 << 22) | (1 << 27));
|
43
|
+
uint32_t avx2_bmi12_mask = (1 << 5) | (1 << 3) | (1 << 8);
|
44
|
+
|
45
|
+
/* CPUID.(EAX=01H, ECX=0H):ECX.FMA[bit 12]==1 &&
|
46
|
+
CPUID.(EAX=01H, ECX=0H):ECX.MOVBE[bit 22]==1 &&
|
47
|
+
CPUID.(EAX=01H, ECX=0H):ECX.OSXSAVE[bit 27]==1 */
|
48
|
+
run_cpuid( 1, 0, abcd );
|
49
|
+
if ( (abcd[2] & fma_movbe_osxsave_mask) != fma_movbe_osxsave_mask )
|
50
|
+
return 0;
|
51
|
+
|
52
|
+
if ( ! check_xcr0_ymm() )
|
53
|
+
return 0;
|
54
|
+
|
55
|
+
/* CPUID.(EAX=07H, ECX=0H):EBX.AVX2[bit 5]==1 &&
|
56
|
+
CPUID.(EAX=07H, ECX=0H):EBX.BMI1[bit 3]==1 &&
|
57
|
+
CPUID.(EAX=07H, ECX=0H):EBX.BMI2[bit 8]==1 */
|
58
|
+
run_cpuid( 7, 0, abcd );
|
59
|
+
if ( (abcd[1] & avx2_bmi12_mask) != avx2_bmi12_mask )
|
60
|
+
return 0;
|
61
|
+
|
62
|
+
/* CPUID.(EAX=80000001H):ECX.LZCNT[bit 5]==1 */
|
63
|
+
run_cpuid( 0x80000001, 0, abcd );
|
64
|
+
if ( (abcd[2] & (1 << 5)) == 0)
|
65
|
+
return 0;
|
66
|
+
|
67
|
+
return 1;
|
68
|
+
}
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# rubocop:disable Style/GlobalVars
|
4
|
+
|
5
|
+
require "mkmf"
|
6
|
+
|
7
|
+
abort("missing posix_memalign()") unless have_func("posix_memalign", "stdlib.h")
|
8
|
+
|
9
|
+
$INCFLAGS << " -I$(srcdir)/ref10 -I$(srcdir)/rfc7748_precomputed"
|
10
|
+
|
11
|
+
# Check for Intel 4th Gen Core CPU features
|
12
|
+
# TODO: move this detection completely to runtime
|
13
|
+
cputest_c = <<SRC
|
14
|
+
#{File.read(File.expand_path('cputest.c', __dir__))}
|
15
|
+
int main() {
|
16
|
+
return check_4th_gen_intel_core_features() != 1;
|
17
|
+
}
|
18
|
+
SRC
|
19
|
+
|
20
|
+
if try_run(cputest_c)
|
21
|
+
$defs.push("-DHAVE_4TH_GEN_INTEL_CORE")
|
22
|
+
$CFLAGS << " -Wall -O3 -pedantic -std=c99 -mbmi -mbmi2 -march=native -mtune=native"
|
23
|
+
$srcs = Dir.glob(File.join(__dir__, "**", "*.c"))
|
24
|
+
else
|
25
|
+
# Do not include the rfc7748_precomputed sources if we do not have a 4th gen+ Core CPU
|
26
|
+
$srcs = Dir.glob(File.join(__dir__, "*.c")) + Dir.glob(File.expand_path("ref10/*.c", __dir__))
|
27
|
+
end
|
28
|
+
|
29
|
+
$objs = $srcs.map { |src| src.sub(/\.c$/, ".o") }
|
30
|
+
|
31
|
+
create_makefile "x25519"
|
@@ -0,0 +1,12 @@
|
|
1
|
+
#include "fe.h"
|
2
|
+
|
3
|
+
int x25519_ref10_scalarmult(uint8_t *q,
|
4
|
+
const uint8_t *n,
|
5
|
+
const uint8_t *p);
|
6
|
+
|
7
|
+
static const uint8_t x25519_basepoint[32] = {9};
|
8
|
+
|
9
|
+
int x25519_ref10_scalarmult_base(uint8_t *q, const uint8_t *n)
|
10
|
+
{
|
11
|
+
return x25519_ref10_scalarmult(q,n,x25519_basepoint);
|
12
|
+
}
|