x25519 0.0.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.
@@ -0,0 +1,244 @@
1
+ /**
2
+ * Copyright (c) 2017 Armando Faz <armfazh@ic.unicamp.br>.
3
+ * Institute of Computing.
4
+ * University of Campinas, Brazil.
5
+ *
6
+ * This program is free software: you can redistribute it and/or modify
7
+ * it under the terms of the GNU Lesser General Public License as
8
+ * published by the Free Software Foundation, version 3.
9
+ *
10
+ * This program is distributed in the hope that it will be useful, but
11
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ * Lesser General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Lesser General Public License
16
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+ #include <fp25519_x64.h>
19
+ #include <table_ladder_x25519.h>
20
+ #include "rfc7748_precompted.h"
21
+ #include "random.h"
22
+
23
+ void print_X25519_key(argKey key)
24
+ {
25
+ print_bytes(key,X25519_KEYSIZE_BYTES);
26
+ }
27
+ void random_X25519_key(argKey key)
28
+ {
29
+ random_bytes(key,X25519_KEYSIZE_BYTES);
30
+ }
31
+
32
+ /****** Implementation of Montgomery Ladder Algorithm ************/
33
+ static inline void cswap_x64(uint64_t bit, uint64_t *const px, uint64_t *const py)
34
+ {
35
+ int i=0;
36
+ uint64_t mask = (uint64_t)0-bit;
37
+ for(i=0;i<NUM_WORDS_ELTFP25519_X64;i++)
38
+ {
39
+ uint64_t t = mask & (px[i] ^ py[i]);
40
+ px[i] = px[i] ^ t;
41
+ py[i] = py[i] ^ t;
42
+ }
43
+ }
44
+
45
+ static void x25519_shared_secret_x64(argKey shared, argKey session_key, argKey private_key)
46
+ {
47
+ ALIGN uint64_t buffer[4*NUM_WORDS_ELTFP25519_X64];
48
+ ALIGN uint64_t coordinates[4*NUM_WORDS_ELTFP25519_X64];
49
+ ALIGN uint64_t workspace[6*NUM_WORDS_ELTFP25519_X64];
50
+ uint64_t save=0;
51
+
52
+ int i=0, j=0;
53
+ uint64_t prev = 0;
54
+ uint64_t *const X1 = (uint64_t*)session_key;
55
+ uint64_t *const key = (uint64_t*)private_key;
56
+ uint64_t *const Px = coordinates+0;
57
+ uint64_t *const Pz = coordinates+4;
58
+ uint64_t *const Qx = coordinates+8;
59
+ uint64_t *const Qz = coordinates+12;
60
+ uint64_t *const X2 = Qx;
61
+ uint64_t *const Z2 = Qz;
62
+ uint64_t *const X3 = Px;
63
+ uint64_t *const Z3 = Pz;
64
+ uint64_t *const X2Z2 = Qx;
65
+ uint64_t *const X3Z3 = Px;
66
+
67
+ uint64_t *const A = workspace+0;
68
+ uint64_t *const B = workspace+4;
69
+ uint64_t *const D = workspace+8;
70
+ uint64_t *const C = workspace+12;
71
+ uint64_t *const DA = workspace+16;
72
+ uint64_t *const CB = workspace+20;
73
+ uint64_t *const AB = A;
74
+ uint64_t *const DC = D;
75
+ uint64_t *const DACB = DA;
76
+ uint64_t *const buffer_1w = buffer;
77
+ uint64_t *const buffer_2w = buffer;
78
+
79
+ /* clampC function */
80
+ save = private_key[X25519_KEYSIZE_BYTES-1]<<16 | private_key[0];
81
+ private_key[0] = private_key[0] & (~(uint8_t)0x7);
82
+ private_key[X25519_KEYSIZE_BYTES-1] = (uint8_t)64 | (private_key[X25519_KEYSIZE_BYTES-1] & (uint8_t)0x7F);
83
+
84
+ /**
85
+ * As in the draft:
86
+ * When receiving such an array, implementations of curve25519
87
+ * MUST mask the most-significant bit in the final byte. This
88
+ * is done to preserve compatibility with point formats which
89
+ * reserve the sign bit for use in other protocols and to
90
+ * increase resistance to implementation fingerprinting
91
+ **/
92
+ session_key[X25519_KEYSIZE_BYTES-1] &= (1<<(255%8))-1;
93
+
94
+ copy_EltFp25519_1w_x64(Px,(uint64_t*)session_key);
95
+ setzero_EltFp25519_1w_x64(Pz);
96
+ setzero_EltFp25519_1w_x64(Qx);
97
+ setzero_EltFp25519_1w_x64(Qz);
98
+
99
+ Pz[0] = 1;
100
+ Qx[0] = 1;
101
+
102
+ /* main-loop */
103
+ prev = 0;
104
+ j = 62;
105
+ for(i=3;i>=0;i--)
106
+ {
107
+ while(j >= 0)
108
+ {
109
+ uint64_t bit = (key[i]>>j)&0x1;
110
+ uint64_t swap = bit^prev;
111
+ prev = bit;
112
+
113
+ add_EltFp25519_1w_x64(A, X2, Z2); /* A = (X2+Z2) */
114
+ sub_EltFp25519_1w_x64(B, X2, Z2); /* B = (X2-Z2) */
115
+ add_EltFp25519_1w_x64(C, X3, Z3); /* C = (X3+Z3) */
116
+ sub_EltFp25519_1w_x64(D, X3, Z3); /* D = (X3-Z3) */
117
+ mul_EltFp25519_2w_x64(DACB,AB,DC); /* [DA|CB] = [A|B]*[D|C] */
118
+
119
+ cswap_x64(swap, A, C);
120
+ cswap_x64(swap, B, D);
121
+
122
+ sqr_EltFp25519_2w_x64(AB); /* [AA|BB] = [A^2|B^2] */
123
+ add_EltFp25519_1w_x64(X3, DA, CB); /* X3 = (DA+CB) */
124
+ sub_EltFp25519_1w_x64(Z3, DA, CB); /* Z3 = (DA-CB) */
125
+ sqr_EltFp25519_2w_x64(X3Z3); /* [X3|Z3] = [(DA+CB)|(DA+CB)]^2 */
126
+
127
+ copy_EltFp25519_1w_x64(X2,B); /* X2 = B^2 */
128
+ sub_EltFp25519_1w_x64(Z2, A, B); /* Z2 = E = AA-BB */
129
+ mul_a24_EltFp25519_1w_x64(B, Z2); /* B = a24*E */
130
+ add_EltFp25519_1w_x64(B, B, X2); /* B = a24*E+B */
131
+ mul_EltFp25519_2w_x64(X2Z2,X2Z2,AB); /* [X2|Z2] = [B|E]*[A|a24*E+B] */
132
+ mul_EltFp25519_1w_x64(Z3,Z3,X1); /* Z3 = Z3*X1 */
133
+
134
+ j--;
135
+ }
136
+ j = 63;
137
+ }
138
+
139
+ inv_EltFp25519_1w_x64(A, Qz);
140
+ mul_EltFp25519_1w_x64((uint64_t*)shared,Qx,A);
141
+ fred_EltFp25519_1w_x64((uint64_t *) shared);
142
+ private_key[X25519_KEYSIZE_BYTES-1] = (uint8_t)((save>>16) & 0xFF);
143
+ private_key[0] = (uint8_t)(save & 0xFF);
144
+ }
145
+
146
+ static void x25519_keygen_precmp_x64(argKey session_key, argKey private_key)
147
+ {
148
+ ALIGN uint64_t buffer[4*NUM_WORDS_ELTFP25519_X64];
149
+ ALIGN uint64_t coordinates[4*NUM_WORDS_ELTFP25519_X64];
150
+ ALIGN uint64_t workspace[4*NUM_WORDS_ELTFP25519_X64];
151
+ uint64_t save;
152
+
153
+ int i=0, j=0, k=0;
154
+ uint64_t *const key = (uint64_t*)private_key;
155
+ uint64_t *const Ur1 = coordinates+0;
156
+ uint64_t *const Zr1 = coordinates+4;
157
+ uint64_t *const Ur2 = coordinates+8;
158
+ uint64_t *const Zr2 = coordinates+12;
159
+
160
+ uint64_t *const UZr1 = coordinates+0;
161
+ uint64_t *const ZUr2 = coordinates+8;
162
+
163
+ uint64_t *const A = workspace+0;
164
+ uint64_t *const B = workspace+4;
165
+ uint64_t *const C = workspace+8;
166
+ uint64_t *const D = workspace+12;
167
+
168
+ uint64_t *const AB = workspace+0;
169
+ uint64_t *const CD = workspace+8;
170
+
171
+ uint64_t *const buffer_1w = buffer;
172
+ uint64_t *const buffer_2w = buffer;
173
+ uint64_t * P = (uint64_t *)Table_Ladder_8k;
174
+
175
+ /* clampC function */
176
+ save = private_key[X25519_KEYSIZE_BYTES-1]<<16 | private_key[0];
177
+ private_key[0] = private_key[0] & (~(uint8_t)0x7);
178
+ private_key[X25519_KEYSIZE_BYTES-1] = (uint8_t)64 | (private_key[X25519_KEYSIZE_BYTES-1] & (uint8_t)0x7F);
179
+
180
+ setzero_EltFp25519_1w_x64(Ur1);
181
+ setzero_EltFp25519_1w_x64(Zr1);
182
+ setzero_EltFp25519_1w_x64(Zr2);
183
+ Ur1[0] = 1;
184
+ Zr1[0] = 1;
185
+ Zr2[0] = 1;
186
+
187
+ /* G-S */
188
+ Ur2[3] = 0x1eaecdeee27cab34;
189
+ Ur2[2] = 0xadc7a0b9235d48e2;
190
+ Ur2[1] = 0xbbf095ae14b2edf8;
191
+ Ur2[0] = 0x7e94e1fec82faabd;
192
+
193
+ /* main-loop */
194
+ const int ite[4] = {64,64,64,63};
195
+ const int q = 3;
196
+ uint64_t swap = 1;
197
+
198
+ j = q;
199
+ for(i=0;i<NUM_WORDS_ELTFP25519_X64;i++)
200
+ {
201
+ while(j < ite[i])
202
+ {
203
+ k = (64*i+j-q);
204
+ uint64_t bit = (key[i]>>j)&0x1;
205
+ swap = swap ^ bit;
206
+ cswap_x64(swap, Ur1, Ur2);
207
+ cswap_x64(swap, Zr1, Zr2);
208
+ swap = bit;
209
+ /** Addition */
210
+ sub_EltFp25519_1w_x64(B, Ur1, Zr1); /* B = Ur1-Zr1 */
211
+ add_EltFp25519_1w_x64(A, Ur1, Zr1); /* A = Ur1+Zr1 */
212
+ mul_EltFp25519_1w_x64(C,&P[4*k],B); /* C = M0-B */
213
+ sub_EltFp25519_1w_x64(B, A, C); /* B = (Ur1+Zr1) - M*(Ur1-Zr1) */
214
+ add_EltFp25519_1w_x64(A, A, C); /* A = (Ur1+Zr1) + M*(Ur1-Zr1) */
215
+ sqr_EltFp25519_2w_x64(AB); /* A = A^2 | B = B^2 */
216
+ mul_EltFp25519_2w_x64(UZr1,ZUr2,AB); /* Ur1 = Zr2*A | Zr1 = Ur2*B */
217
+ j++;
218
+ }
219
+ j = 0;
220
+ }
221
+
222
+ /** Doubling */
223
+ for(i=0;i<q;i++)
224
+ {
225
+ add_EltFp25519_1w_x64(A, Ur1, Zr1); /* A = Ur1+Zr1 */
226
+ sub_EltFp25519_1w_x64(B, Ur1, Zr1); /* B = Ur1-Zr1 */
227
+ sqr_EltFp25519_2w_x64(AB); /* A = A**2 B = B**2 */
228
+ copy_EltFp25519_1w_x64(C,B); /* C = B */
229
+ sub_EltFp25519_1w_x64(B, A, B); /* B = A-B */
230
+ mul_a24_EltFp25519_1w_x64(D, B); /* D = my_a24*B */
231
+ add_EltFp25519_1w_x64(D, D, C); /* D = D+C */
232
+ mul_EltFp25519_2w_x64(UZr1,AB,CD); /* Ur1 = A*B Zr1 = Zr1*A */
233
+ }
234
+
235
+ /* Convert to affine coordinates */
236
+ inv_EltFp25519_1w_x64(A, Zr1);
237
+ mul_EltFp25519_1w_x64((uint64_t*)session_key,Ur1,A);
238
+ fred_EltFp25519_1w_x64((uint64_t *) session_key);
239
+ private_key[X25519_KEYSIZE_BYTES-1] = (uint8_t)((save>>16) & 0xFF);
240
+ private_key[0] = (uint8_t)(save & 0xFF);
241
+ }
242
+
243
+ const KeyGen X25519_KeyGen_x64 = x25519_keygen_precmp_x64;
244
+ const Shared X25519_Shared_x64 = x25519_shared_secret_x64;
data/lib/x25519.rb ADDED
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "x25519/version"
4
+
5
+ # The X25519 Elliptic Curve Diffie-Hellman Function (described in RFC7748)
6
+ module X25519
7
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module X25519
4
+ VERSION = "0.0.0"
5
+ end
data/x25519.gemspec ADDED
@@ -0,0 +1,28 @@
1
+
2
+ # frozen_string_literal: true
3
+
4
+ lib = File.expand_path("../lib", __FILE__)
5
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
6
+ require "x25519/version"
7
+
8
+ Gem::Specification.new do |spec|
9
+ spec.name = "x25519"
10
+ spec.version = X25519::VERSION
11
+ spec.authors = ["Tony Arcieri"]
12
+ spec.email = ["bascule@gmail.com"]
13
+ spec.summary = "Public key cryptography library providing the X25519 D-H function"
14
+ spec.description = <<-DESCRIPTION.strip.gsub(/\s+/, " ")
15
+ An efficient public key cryptography library for Ruby providing key
16
+ exchange/agreement via the X25519 (a.k.a. Curve25519) Elliptic Curve
17
+ Diffie-Hellman function as described in [RFC7748].
18
+ DESCRIPTION
19
+ spec.homepage = "https://github.com/cryptosphere/x25519"
20
+ spec.license = "MIT"
21
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
22
+ spec.bindir = "exe"
23
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
+ spec.require_paths = ["lib"]
25
+
26
+ spec.required_ruby_version = ">= 2.2.2"
27
+ spec.add_development_dependency "bundler", "~> 1.16"
28
+ end
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: x25519
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Tony Arcieri
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-12-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.16'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
27
+ description: An efficient public key cryptography library for Ruby providing key exchange/agreement
28
+ via the X25519 (a.k.a. Curve25519) Elliptic Curve Diffie-Hellman function as described
29
+ in [RFC7748].
30
+ email:
31
+ - bascule@gmail.com
32
+ executables: []
33
+ extensions: []
34
+ extra_rdoc_files: []
35
+ files:
36
+ - ".gitignore"
37
+ - ".rspec"
38
+ - ".rubocop.yml"
39
+ - ".travis.yml"
40
+ - CODE_OF_CONDUCT.md
41
+ - Gemfile
42
+ - LICENSE
43
+ - README.md
44
+ - Rakefile
45
+ - ext/x25519/bytes.c
46
+ - ext/x25519/bytes.h
47
+ - ext/x25519/fp25519_x64.c
48
+ - ext/x25519/fp25519_x64.h
49
+ - ext/x25519/random.c
50
+ - ext/x25519/random.h
51
+ - ext/x25519/rfc7748_precompted.h
52
+ - ext/x25519/rfc7748_precomputed.c
53
+ - ext/x25519/table_ladder_x25519.h
54
+ - ext/x25519/x25519_x64.c
55
+ - lib/x25519.rb
56
+ - lib/x25519/version.rb
57
+ - x25519.gemspec
58
+ homepage: https://github.com/cryptosphere/x25519
59
+ licenses:
60
+ - MIT
61
+ metadata: {}
62
+ post_install_message:
63
+ rdoc_options: []
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: 2.2.2
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ requirements: []
77
+ rubyforge_project:
78
+ rubygems_version: 2.6.13
79
+ signing_key:
80
+ specification_version: 4
81
+ summary: Public key cryptography library providing the X25519 D-H function
82
+ test_files: []