Line data Source code
1 : #include "fd_curve25519.h"
2 : #include "../hex/fd_hex.h"
3 :
4 : /*
5 : * Secure implementations (const time + clean temp vars)
6 : */
7 : #include "fd_curve25519_secure.c"
8 :
9 : #if FD_HAS_AVX512
10 : #include "avx512/fd_curve25519.c"
11 : #else
12 : #include "ref/fd_curve25519.c"
13 : #endif
14 :
15 1340763 : #define WNAF_BIT_SZ 4
16 1173046 : #define WNAF_TBL_SZ (2*WNAF_BIT_SZ)
17 :
18 : /*
19 : * Ser/de
20 : */
21 :
22 : void
23 : fd_ed25519_debug( char const * name,
24 0 : fd_ed25519_point_t const * a ) {
25 0 : fd_f25519_t x[1], y[1], z[1], t[1];
26 0 : fd_ed25519_point_to( x, y, z, t, a );
27 0 : FD_LOG_WARNING(( "%s", name ));
28 0 : fd_f25519_debug( "x", x );
29 0 : fd_f25519_debug( "y", y );
30 0 : fd_f25519_debug( "z", z );
31 0 : fd_f25519_debug( "t", t );
32 0 : }
33 :
34 : fd_ed25519_point_t *
35 : fd_ed25519_point_frombytes( fd_ed25519_point_t * r,
36 944 : uchar const buf[ 32 ] ) {
37 944 : fd_f25519_t x[1], y[1], t[1];
38 944 : fd_f25519_frombytes( y, buf );
39 944 : uchar expected_x_sign = buf[31] >> 7;
40 :
41 944 : fd_f25519_t u[1];
42 944 : fd_f25519_t v[1];
43 944 : fd_f25519_sqr( u, y );
44 944 : fd_f25519_mul( v, u, fd_f25519_d );
45 944 : fd_f25519_sub( u, u, fd_f25519_one ); /* u = y^2-1 */
46 944 : fd_f25519_add( v, v, fd_f25519_one ); /* v = dy^2+1 */
47 :
48 944 : int was_square = fd_f25519_sqrt_ratio( x, u, v );
49 944 : if( FD_UNLIKELY( !was_square ) ) {
50 19 : return NULL;
51 19 : }
52 :
53 : /* Note: RFC 8032 Section 5.1.3 says "if x=0 and x_0=1, decoding
54 : fails", but Dalek does not enforce this — neg(0)==0 so it silently
55 : accepts the point. We match Dalek for compatibility.
56 : https://github.com/dalek-cryptography/curve25519-dalek/blob/curve25519-4.1.3/curve25519-dalek/src/edwards.rs#L194-L240
57 : https://github.com/dalek-cryptography/curve25519-dalek/blob/3.2.1/src/edwards.rs#L193-L209 */
58 925 : if( fd_f25519_sgn(x)!=expected_x_sign ) { /* 50% prob */
59 443 : fd_f25519_neg( x, x );
60 443 : }
61 :
62 925 : fd_f25519_mul( t, x, y );
63 925 : fd_ed25519_point_from( r, x, y, fd_f25519_one, t );
64 :
65 925 : return r;
66 944 : }
67 :
68 : /* fd_ed25519_point_frombytes (like Dalek's decompress) takes y mod p
69 : (non-canonical y accepted), ignores the sign bit for validity (x=0
70 : with sign 1 is accepted) and succeeds iff u/v is a square or zero,
71 : with u=y^2-1 and v=d*y^2+1. v is never 0 as d is a non-square and -1
72 : is a square, so this is the same as u*v being a square or zero, which
73 : a Jacobi symbol decides much faster than a square root. */
74 : int
75 2002 : fd_ed25519_point_validate( uchar const buf[ 32 ] ) {
76 2002 : fd_f25519_t y[1], u[1], v[1];
77 2002 : fd_f25519_frombytes( y, buf );
78 2002 : fd_f25519_sqr( u, y );
79 2002 : fd_f25519_mul( v, u, fd_f25519_d );
80 2002 : fd_f25519_sub( u, u, fd_f25519_one ); /* u = y^2-1 */
81 2002 : fd_f25519_add( v, v, fd_f25519_one ); /* v = dy^2+1 */
82 2002 : fd_f25519_mul( u, u, v );
83 2002 : return fd_f25519_is_square_var( u );
84 2002 : }
85 :
86 : uchar *
87 : fd_ed25519_point_tobytes_batch8( uchar out[], /* 32*n */
88 : fd_ed25519_point_t const * pt, /* n */
89 0 : ulong n ) { /* in [1,8] */
90 0 : FD_TEST( 0UL<n && n<=8UL );
91 :
92 0 : fd_f25519_t x[8], y[8], z[8], t[1];
93 0 : for( ulong i=0UL; i<n; i++ ) fd_ed25519_point_to( &x[i], &y[i], &z[i], t, &pt[i] );
94 :
95 : /* batch inv */
96 :
97 0 : fd_f25519_t c[8], iz[8], u[1];
98 0 : c[0] = z[0];
99 0 : for( ulong i=1UL; i<n; i++ ) fd_f25519_mul( &c[i], &c[i-1], &z[i] );
100 0 : fd_f25519_inv( u, &c[n-1UL] );
101 0 : for( ulong i=n-1UL; i>0UL; i-- ) {
102 0 : fd_f25519_mul( &iz[i], u, &c[i-1] );
103 0 : fd_f25519_mul( u, u, &z[i] );
104 0 : }
105 0 : iz[0] = *u;
106 :
107 0 : ulong i=0UL;
108 0 : for( ; i+2UL<=n; i+=2UL ) fd_f25519_mul4( &x[i ], &x[i ], &iz[i ],
109 0 : &y[i ], &y[i ], &iz[i ],
110 0 : &x[i+1], &x[i+1], &iz[i+1],
111 0 : &y[i+1], &y[i+1], &iz[i+1] );
112 0 : if( i<n ) fd_f25519_mul2( &x[i], &x[i], &iz[i],
113 0 : &y[i], &y[i], &iz[i] );
114 :
115 0 : for( ulong j=0UL; j<n; j++ ) {
116 0 : fd_f25519_tobytes( out+32UL*j, &y[j] );
117 0 : out[ 32UL*j+31UL ] ^= (uchar)(fd_f25519_sgn( &x[j] ) << 7);
118 0 : }
119 0 : return out;
120 0 : }
121 :
122 : uchar *
123 : fd_ed25519_point_tobytes( uchar out[ 32 ],
124 283 : fd_ed25519_point_t const * a ) {
125 : /* equivalent to: return fd_ed25519_point_tobytes_batch8( out, a, 1UL ) */
126 283 : fd_f25519_t x[1], y[1], z[1], t[1];
127 283 : fd_ed25519_point_to( x, y, z, t, a );
128 283 : fd_f25519_inv( t, z );
129 283 : fd_f25519_mul2( x, x, t,
130 283 : y, y, t );
131 283 : fd_f25519_tobytes( out, y );
132 283 : out[31] ^= (uchar)(fd_f25519_sgn( x ) << 7);
133 283 : return out;
134 283 : }
135 :
136 : /*
137 : * Scalar multiplication
138 : */
139 :
140 : fd_ed25519_point_t *
141 : fd_ed25519_scalar_mul( fd_ed25519_point_t * r,
142 : uchar const n[ 32 ],
143 104 : fd_ed25519_point_t const * a ) {
144 104 : short nslide[256];
145 104 : fd_curve25519_scalar_wnaf( nslide, n, WNAF_BIT_SZ );
146 :
147 104 : fd_ed25519_point_t ai[WNAF_TBL_SZ]; /* A,3A,5A,7A,9A,11A,13A,15A */
148 104 : fd_ed25519_point_t a2[1]; /* 2A (temp) */
149 104 : fd_ed25519_point_t t[1];
150 :
151 : /* pre-computed table */
152 104 : fd_ed25519_point_set( &ai[0], a );
153 104 : fd_ed25519_point_dbln( a2, a, 1 ); // note: a is affine, we could save 1mul
154 104 : fd_curve25519_into_precomputed( &ai[0] );
155 832 : for( int i=1; i<WNAF_TBL_SZ; i++ ) {
156 728 : fd_ed25519_point_add_with_opts( t, a2, &ai[i-1], i==1, 1, 1 );
157 728 : fd_ed25519_point_add_final_mul( &ai[i], t );
158 : /* pre-compute kT, to save 1mul during the loop */
159 728 : fd_curve25519_into_precomputed( &ai[i] );
160 728 : }
161 :
162 : /* main dbl-and-add loop. note: last iter unrolled */
163 104 : fd_ed25519_point_set_zero( r );
164 104 : int i;
165 2200 : for( i=255; i>=0; i-- ) { if( nslide[i] ) break; }
166 23995 : for( ; i>=0; i-- ) {
167 23891 : fd_ed25519_partial_dbl( t, r );
168 23891 : if( nslide[i] > 0 ) { fd_ed25519_point_add_final_mul( r, t ); fd_ed25519_point_add_with_opts( t, r, &ai[ nslide[i] / 2], nslide[i]==1, 1, 1 ); }
169 21746 : else if( nslide[i] < 0 ) { fd_ed25519_point_add_final_mul( r, t ); fd_ed25519_point_sub_with_opts( t, r, &ai[(-nslide[i]) / 2], nslide[i]==-1, 1, 1 ); }
170 :
171 : /* ignore r->T because dbl doesn't need it, except in the last cycle */
172 23891 : if (i == 0) {
173 101 : fd_ed25519_point_add_final_mul( r, t ); // compute r->T
174 23790 : } else {
175 23790 : fd_ed25519_point_add_final_mul_projective( r, t ); // ignore r->T
176 23790 : }
177 23891 : }
178 104 : return r;
179 104 : }
180 :
181 : fd_ed25519_point_t *
182 : fd_ed25519_double_scalar_mul_base( fd_ed25519_point_t * r,
183 : uchar const n1[ 32 ],
184 : fd_ed25519_point_t const * a,
185 2419 : uchar const n2[ 32 ] ) {
186 :
187 2419 : short n1slide[256]; fd_curve25519_scalar_wnaf( n1slide, n1, WNAF_BIT_SZ );
188 2419 : short n2slide[256]; fd_curve25519_scalar_wnaf( n2slide, n2, 8 );
189 :
190 2419 : fd_ed25519_point_t ai[WNAF_TBL_SZ]; /* A,3A,5A,7A,9A,11A,13A,15A */
191 2419 : fd_ed25519_point_t a2[1]; /* 2A (temp) */
192 2419 : fd_ed25519_point_t t[1];
193 :
194 : /* pre-computed table */
195 2419 : fd_ed25519_point_set( &ai[0], a );
196 2419 : fd_ed25519_point_dbln( a2, a, 1 ); // note: a is affine, we could save 1mul
197 2419 : fd_curve25519_into_precomputed( &ai[0] );
198 19327 : for( int i=1; i<WNAF_TBL_SZ; i++ ) {
199 16908 : fd_ed25519_point_add_with_opts( t, a2, &ai[i-1], i==1, 1, 1 );
200 16908 : fd_ed25519_point_add_final_mul( &ai[i], t );
201 : /* pre-compute kT, to save 1mul during the loop */
202 16908 : fd_curve25519_into_precomputed( &ai[i] );
203 16908 : }
204 :
205 : /* main dbl-and-add loop */
206 2419 : fd_ed25519_point_set_zero( r );
207 :
208 2419 : int i;
209 13999 : for( i=255; i>=0; i-- ) { if( n1slide[i] || n2slide[i] ) break; }
210 597521 : for( ; i>=0; i-- ) {
211 595102 : fd_ed25519_partial_dbl( t, r );
212 595102 : if( n1slide[i] > 0 ) { fd_ed25519_point_add_final_mul( r, t ); fd_ed25519_point_add_with_opts( t, r, &ai[ n1slide[i] / 2], n1slide[i]==1, 1, 1 ); }
213 544561 : else if( n1slide[i] < 0 ) { fd_ed25519_point_add_final_mul( r, t ); fd_ed25519_point_sub_with_opts( t, r, &ai[(-n1slide[i]) / 2], n1slide[i]==-1, 1, 1 ); }
214 595102 : if( n2slide[i] > 0 ) { fd_ed25519_point_add_final_mul( r, t ); fd_ed25519_point_add_with_opts( t, r, &fd_ed25519_base_point_wnaf_table[ n2slide[i] / 2], 1, 1, 1 ); }
215 563635 : else if( n2slide[i] < 0 ) { fd_ed25519_point_add_final_mul( r, t ); fd_ed25519_point_sub_with_opts( t, r, &fd_ed25519_base_point_wnaf_table[(-n2slide[i]) / 2], 1, 1, 1 ); }
216 :
217 : /* ignore r->T because dbl doesn't need it, except in the last cycle */
218 595102 : if (i == 0) {
219 2420 : fd_ed25519_point_add_final_mul( r, t ); // compute r->T
220 592682 : } else {
221 592682 : fd_ed25519_point_add_final_mul_projective( r, t ); // ignore r->T
222 592682 : }
223 595102 : }
224 2419 : return r;
225 2419 : }
226 :
227 :
228 : /* split_odd_table fills tbl[0,n) with p,3p,..,(2n-1)p in precomputed
229 : form. */
230 :
231 : static void
232 : split_odd_table( fd_ed25519_point_t * tbl,
233 : fd_ed25519_point_t const * p,
234 0 : int n ) {
235 0 : fd_ed25519_point_t p2[1];
236 0 : fd_ed25519_point_set( &tbl[0], p );
237 0 : fd_ed25519_point_dbln( p2, p, 1 );
238 0 : for( int i=1; i<n; i++ ) fd_ed25519_point_add( &tbl[i], p2, &tbl[i-1] );
239 0 : for( int i=0; i<n; i++ ) fd_curve25519_into_precomputed( &tbl[i] );
240 0 : }
241 :
242 : void
243 : fd_ed25519_split_table_a( fd_ed25519_point_t tbl[ FD_ED25519_SPLIT_A_TBL_CNT ],
244 0 : fd_ed25519_point_t const * a ) {
245 0 : fd_ed25519_point_t p[1];
246 0 : fd_ed25519_point_set( p, a );
247 0 : for( int j=0; j<FD_ED25519_SPLIT_SEG_CNT; j++ ) {
248 0 : if( j ) fd_ed25519_point_dbln( p, p, FD_ED25519_SPLIT_SEG_BITS );
249 0 : split_odd_table( tbl+FD_ED25519_SPLIT_A_SEG_CNT*j, p, FD_ED25519_SPLIT_A_SEG_CNT );
250 0 : }
251 0 : }
252 :
253 : void
254 0 : fd_ed25519_split_table_b( fd_ed25519_point_t tbl[ FD_ED25519_SPLIT_B_TBL_CNT ] ) {
255 0 : fd_ed25519_point_t p[1];
256 0 : fd_ed25519_point_set( p, fd_ed25519_base_point );
257 0 : for( int j=1; j<FD_ED25519_SPLIT_SEG_CNT; j++ ) {
258 0 : fd_ed25519_point_dbln( p, p, FD_ED25519_SPLIT_SEG_BITS );
259 0 : split_odd_table( tbl+128*(j-1), p, 128 );
260 0 : }
261 0 : }
262 :
263 : /* double_scalar_mul_base_split also advances dec (if non-NULL) by
264 : DEC_STEP chain ops after each point op (3 measured best). */
265 :
266 0 : #define DEC_STEP (3UL)
267 :
268 : static inline fd_ed25519_point_t *
269 : double_scalar_mul_base_split( fd_ed25519_point_t * r,
270 : uchar const n1[ 32 ],
271 : fd_ed25519_point_t const * a_tbl,
272 : uchar const n2[ 32 ],
273 : fd_ed25519_point_t const * b_tbl,
274 0 : fd_ed25519_point_decode_t * dec ) {
275 :
276 : /* Digit d at position b*j+i contributes [d 2^i][2^(b*j)]P, so the
277 : segments of each wNAF share a single b doubling loop. */
278 :
279 0 : short n1slide[256]; fd_curve25519_scalar_wnaf( n1slide, n1, FD_ED25519_SPLIT_A_BITS );
280 0 : short n2slide[256]; fd_curve25519_scalar_wnaf( n2slide, n2, 8 );
281 :
282 0 : fd_ed25519_point_t const * bt[ FD_ED25519_SPLIT_SEG_CNT ];
283 0 : bt[0] = fd_ed25519_base_point_wnaf_table;
284 0 : for( int j=1; j<FD_ED25519_SPLIT_SEG_CNT; j++ ) bt[j] = b_tbl + 128*(j-1);
285 0 : fd_ed25519_point_t t[1];
286 :
287 0 : fd_ed25519_point_set_zero( r );
288 :
289 0 : int i;
290 0 : for( i=FD_ED25519_SPLIT_SEG_BITS-1; i>=0; i-- ) {
291 0 : short nz = 0;
292 0 : for( int j=0; j<FD_ED25519_SPLIT_SEG_CNT; j++ ) nz |= n1slide[ FD_ED25519_SPLIT_SEG_BITS*j+i ] | n2slide[ FD_ED25519_SPLIT_SEG_BITS*j+i ];
293 0 : if( nz ) break;
294 0 : }
295 0 : for( ; i>=0; i-- ) {
296 0 : fd_ed25519_partial_dbl( t, r );
297 0 : if( dec ) fd_ed25519_point_decode_step( dec, DEC_STEP );
298 0 : for( int j=0; j<FD_ED25519_SPLIT_SEG_CNT; j++ ) {
299 0 : short d1 = n1slide[ FD_ED25519_SPLIT_SEG_BITS*j+i ];
300 0 : short d2 = n2slide[ FD_ED25519_SPLIT_SEG_BITS*j+i ];
301 0 : if( d1 > 0 ) { fd_ed25519_point_add_final_mul( r, t ); fd_ed25519_point_add_with_opts( t, r, &a_tbl[ FD_ED25519_SPLIT_A_SEG_CNT*j + d1/2 ], 0, 1, 1 ); if( dec ) fd_ed25519_point_decode_step( dec, DEC_STEP ); }
302 0 : else if( d1 < 0 ) { fd_ed25519_point_add_final_mul( r, t ); fd_ed25519_point_sub_with_opts( t, r, &a_tbl[ FD_ED25519_SPLIT_A_SEG_CNT*j + (-d1)/2 ], 0, 1, 1 ); if( dec ) fd_ed25519_point_decode_step( dec, DEC_STEP ); }
303 0 : if( d2 > 0 ) { fd_ed25519_point_add_final_mul( r, t ); fd_ed25519_point_add_with_opts( t, r, &bt[j][ d2/2 ], j==0, 1, 1 ); if( dec ) fd_ed25519_point_decode_step( dec, DEC_STEP ); }
304 0 : else if( d2 < 0 ) { fd_ed25519_point_add_final_mul( r, t ); fd_ed25519_point_sub_with_opts( t, r, &bt[j][ (-d2)/2 ], j==0, 1, 1 ); if( dec ) fd_ed25519_point_decode_step( dec, DEC_STEP ); }
305 0 : }
306 :
307 : /* ignore r->T because dbl doesn't need it, except in the last cycle */
308 0 : if( i==0 ) fd_ed25519_point_add_final_mul( r, t );
309 0 : else fd_ed25519_point_add_final_mul_projective( r, t );
310 0 : }
311 0 : return r;
312 0 : }
313 :
314 : fd_ed25519_point_t *
315 : fd_ed25519_double_scalar_mul_base_split( fd_ed25519_point_t * r,
316 : uchar const n1[ 32 ],
317 : fd_ed25519_point_t const * a_tbl,
318 : uchar const n2[ 32 ],
319 0 : fd_ed25519_point_t const * b_tbl ) {
320 0 : return double_scalar_mul_base_split( r, n1, a_tbl, n2, b_tbl, NULL );
321 0 : }
322 :
323 : fd_ed25519_point_t *
324 : fd_ed25519_double_scalar_mul_base_split_decode( fd_ed25519_point_t * r,
325 : uchar const n1[ 32 ],
326 : fd_ed25519_point_t const * a_tbl,
327 : uchar const n2[ 32 ],
328 : fd_ed25519_point_t const * b_tbl,
329 0 : fd_ed25519_point_decode_t * dec ) {
330 0 : return double_scalar_mul_base_split( r, n1, a_tbl, n2, b_tbl, dec );
331 0 : }
332 :
333 : FD_25519_INLINE fd_ed25519_point_t *
334 : fd_ed25519_multi_scalar_mul_with_opts( fd_ed25519_point_t * r,
335 : uchar const n[], /* sz * 32 */
336 : fd_ed25519_point_t const a[], /* sz */
337 : ulong const sz,
338 7461 : ulong const base_sz ) {
339 7461 : short nslide[FD_BALLET_CURVE25519_MSM_BATCH_SZ][256];
340 7461 : fd_ed25519_point_t ai[FD_BALLET_CURVE25519_MSM_BATCH_SZ][WNAF_TBL_SZ]; /* A,3A,5A,7A,9A,11A,13A,15A */
341 7461 : fd_ed25519_point_t a2[1]; /* 2A (temp) */
342 7461 : fd_ed25519_point_t t[1]; /* temp */
343 :
344 7461 : if( base_sz ) {
345 0 : fd_curve25519_scalar_wnaf( nslide[0], &n[32*0], 8 );
346 0 : }
347 172655 : for( ulong j=base_sz; j<sz; j++ ) {
348 165194 : fd_curve25519_scalar_wnaf( nslide[j], &n[32*j], WNAF_BIT_SZ );
349 :
350 : /* pre-computed table */
351 165194 : fd_ed25519_point_set( &ai[j][0], &a[j] );
352 165194 : fd_ed25519_point_dbln( a2, &a[j], 1 ); // note: a is affine, we could save 1mul
353 165194 : fd_curve25519_into_precomputed( &ai[j][0] );
354 1152887 : for( int i=1; i<WNAF_TBL_SZ; i++ ) {
355 987693 : fd_ed25519_point_add_with_opts( t, a2, &ai[j][i-1], i==1, 1, 1 );
356 987693 : fd_ed25519_point_add_final_mul( &ai[j][i], t );
357 : /* pre-compute kT, to save 1mul during the loop */
358 987693 : fd_curve25519_into_precomputed( &ai[j][i] );
359 987693 : }
360 165194 : }
361 :
362 : /* main dbl-and-add loop */
363 7461 : fd_ed25519_point_set_zero( r );
364 612901 : for( int i=255; i>=0; i-- ) {
365 605440 : fd_ed25519_partial_dbl( t, r );
366 605440 : if( base_sz ) {
367 0 : if( nslide[0][i] > 0 ) { fd_ed25519_point_add_final_mul( r, t ); fd_ed25519_point_add_with_opts( t, r, &fd_ed25519_base_point_wnaf_table[ nslide[0][i] / 2], 1, 1, 1 ); }
368 0 : else if( nslide[0][i] < 0 ) { fd_ed25519_point_add_final_mul( r, t ); fd_ed25519_point_sub_with_opts( t, r, &fd_ed25519_base_point_wnaf_table[(-nslide[0][i]) / 2], 1, 1, 1 ); }
369 0 : }
370 13756160 : for( ulong j=base_sz; j<sz; j++ ) {
371 13150720 : short n = nslide[j][i];
372 13150720 : if( n > 0 ) { fd_ed25519_point_add_final_mul( r, t ); fd_ed25519_point_add_with_opts( t, r, &ai[j][ n / 2], (n==1), 1, 1 ); }
373 11759906 : else if( n < 0 ) { fd_ed25519_point_add_final_mul( r, t ); fd_ed25519_point_sub_with_opts( t, r, &ai[j][(-n) / 2], (n==-1), 1, 1 ); }
374 13150720 : }
375 :
376 : /* ignore r->T because dbl doesn't need it, except in the last cycle */
377 605440 : if (i == 0) {
378 7382 : fd_ed25519_point_add_final_mul( r, t ); // compute r->T
379 598058 : } else {
380 598058 : fd_ed25519_point_add_final_mul_projective( r, t ); // ignore r->T
381 598058 : }
382 605440 : }
383 7461 : return r;
384 7461 : }
385 :
386 : fd_ed25519_point_t *
387 : fd_ed25519_multi_scalar_mul( fd_ed25519_point_t * r,
388 : uchar const n[], /* sz * 32 */
389 : fd_ed25519_point_t const a[], /* sz */
390 2712 : ulong const sz ) {
391 :
392 2712 : fd_ed25519_point_t h[1];
393 2712 : fd_ed25519_point_set_zero( r );
394 :
395 10175 : for( ulong i=0; i<sz; i+=FD_BALLET_CURVE25519_MSM_BATCH_SZ ) {
396 7463 : ulong batch_sz = fd_ulong_min(sz-i, FD_BALLET_CURVE25519_MSM_BATCH_SZ);
397 :
398 7463 : fd_ed25519_multi_scalar_mul_with_opts( h, &n[ 32*i ], &a[ i ], batch_sz, 0 );
399 7463 : fd_ed25519_point_add( r, r, h );
400 7463 : }
401 :
402 2712 : return r;
403 2712 : }
404 :
405 : /*
406 : * Init
407 : */
408 :
409 : fd_ed25519_point_t *
410 : fd_curve25519_affine_add( fd_ed25519_point_t * r,
411 : fd_ed25519_point_t const * a,
412 0 : fd_ed25519_point_t const * b ) {
413 0 : fd_ed25519_point_add_with_opts( r, a, b, 1, 0, 0 );
414 0 : return fd_curve25519_into_affine( r );
415 0 : }
416 :
417 : fd_ed25519_point_t *
418 : fd_curve25519_affine_dbln( fd_ed25519_point_t * r,
419 : fd_ed25519_point_t const * a,
420 0 : int const n ) {
421 0 : fd_ed25519_point_dbln( r, a, n );
422 0 : return fd_curve25519_into_affine( r );
423 0 : }
|