x25519 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []