1*b077aed3SPierre Pronchery /*
2*b077aed3SPierre Pronchery * Copyright 2006-2020 The OpenSSL Project Authors. All Rights Reserved.
3*b077aed3SPierre Pronchery *
4*b077aed3SPierre Pronchery * Licensed under the Apache License 2.0 (the "License"). You may not use
5*b077aed3SPierre Pronchery * this file except in compliance with the License. You can obtain a copy
6*b077aed3SPierre Pronchery * in the file LICENSE in the source distribution or at
7*b077aed3SPierre Pronchery * https://www.openssl.org/source/license.html
8*b077aed3SPierre Pronchery */
9*b077aed3SPierre Pronchery
10*b077aed3SPierre Pronchery #include <stdio.h>
11*b077aed3SPierre Pronchery #include "internal/cryptlib.h"
12*b077aed3SPierre Pronchery #include <openssl/ec.h>
13*b077aed3SPierre Pronchery #include <openssl/rand.h>
14*b077aed3SPierre Pronchery #include "crypto/ecx.h"
15*b077aed3SPierre Pronchery #include "ec_local.h"
16*b077aed3SPierre Pronchery #include "curve448/curve448_local.h"
17*b077aed3SPierre Pronchery #include "ecx_backend.h"
18*b077aed3SPierre Pronchery #include "s390x_arch.h"
19*b077aed3SPierre Pronchery #include "internal/constant_time.h"
20*b077aed3SPierre Pronchery
s390x_x25519_mod_p(unsigned char u[32])21*b077aed3SPierre Pronchery static void s390x_x25519_mod_p(unsigned char u[32])
22*b077aed3SPierre Pronchery {
23*b077aed3SPierre Pronchery unsigned char u_red[32];
24*b077aed3SPierre Pronchery unsigned int c = 0;
25*b077aed3SPierre Pronchery int i;
26*b077aed3SPierre Pronchery
27*b077aed3SPierre Pronchery memcpy(u_red, u, sizeof(u_red));
28*b077aed3SPierre Pronchery
29*b077aed3SPierre Pronchery c += (unsigned int)u_red[31] + 19;
30*b077aed3SPierre Pronchery u_red[31] = (unsigned char)c;
31*b077aed3SPierre Pronchery c >>= 8;
32*b077aed3SPierre Pronchery
33*b077aed3SPierre Pronchery for (i = 30; i >= 0; i--) {
34*b077aed3SPierre Pronchery c += (unsigned int)u_red[i];
35*b077aed3SPierre Pronchery u_red[i] = (unsigned char)c;
36*b077aed3SPierre Pronchery c >>= 8;
37*b077aed3SPierre Pronchery }
38*b077aed3SPierre Pronchery
39*b077aed3SPierre Pronchery c = (u_red[0] & 0x80) >> 7;
40*b077aed3SPierre Pronchery u_red[0] &= 0x7f;
41*b077aed3SPierre Pronchery constant_time_cond_swap_buff(0 - (unsigned char)c,
42*b077aed3SPierre Pronchery u, u_red, sizeof(u_red));
43*b077aed3SPierre Pronchery }
44*b077aed3SPierre Pronchery
s390x_x448_mod_p(unsigned char u[56])45*b077aed3SPierre Pronchery static void s390x_x448_mod_p(unsigned char u[56])
46*b077aed3SPierre Pronchery {
47*b077aed3SPierre Pronchery unsigned char u_red[56];
48*b077aed3SPierre Pronchery unsigned int c = 0;
49*b077aed3SPierre Pronchery int i;
50*b077aed3SPierre Pronchery
51*b077aed3SPierre Pronchery memcpy(u_red, u, sizeof(u_red));
52*b077aed3SPierre Pronchery
53*b077aed3SPierre Pronchery c += (unsigned int)u_red[55] + 1;
54*b077aed3SPierre Pronchery u_red[55] = (unsigned char)c;
55*b077aed3SPierre Pronchery c >>= 8;
56*b077aed3SPierre Pronchery
57*b077aed3SPierre Pronchery for (i = 54; i >= 28; i--) {
58*b077aed3SPierre Pronchery c += (unsigned int)u_red[i];
59*b077aed3SPierre Pronchery u_red[i] = (unsigned char)c;
60*b077aed3SPierre Pronchery c >>= 8;
61*b077aed3SPierre Pronchery }
62*b077aed3SPierre Pronchery
63*b077aed3SPierre Pronchery c += (unsigned int)u_red[27] + 1;
64*b077aed3SPierre Pronchery u_red[27] = (unsigned char)c;
65*b077aed3SPierre Pronchery c >>= 8;
66*b077aed3SPierre Pronchery
67*b077aed3SPierre Pronchery for (i = 26; i >= 0; i--) {
68*b077aed3SPierre Pronchery c += (unsigned int)u_red[i];
69*b077aed3SPierre Pronchery u_red[i] = (unsigned char)c;
70*b077aed3SPierre Pronchery c >>= 8;
71*b077aed3SPierre Pronchery }
72*b077aed3SPierre Pronchery
73*b077aed3SPierre Pronchery constant_time_cond_swap_buff(0 - (unsigned char)c,
74*b077aed3SPierre Pronchery u, u_red, sizeof(u_red));
75*b077aed3SPierre Pronchery }
76*b077aed3SPierre Pronchery
s390x_x25519_mul(unsigned char u_dst[32],const unsigned char u_src[32],const unsigned char d_src[32])77*b077aed3SPierre Pronchery int s390x_x25519_mul(unsigned char u_dst[32],
78*b077aed3SPierre Pronchery const unsigned char u_src[32],
79*b077aed3SPierre Pronchery const unsigned char d_src[32])
80*b077aed3SPierre Pronchery {
81*b077aed3SPierre Pronchery union {
82*b077aed3SPierre Pronchery struct {
83*b077aed3SPierre Pronchery unsigned char u_dst[32];
84*b077aed3SPierre Pronchery unsigned char u_src[32];
85*b077aed3SPierre Pronchery unsigned char d_src[32];
86*b077aed3SPierre Pronchery } x25519;
87*b077aed3SPierre Pronchery unsigned long long buff[512];
88*b077aed3SPierre Pronchery } param;
89*b077aed3SPierre Pronchery int rc;
90*b077aed3SPierre Pronchery
91*b077aed3SPierre Pronchery memset(¶m, 0, sizeof(param));
92*b077aed3SPierre Pronchery
93*b077aed3SPierre Pronchery s390x_flip_endian32(param.x25519.u_src, u_src);
94*b077aed3SPierre Pronchery param.x25519.u_src[0] &= 0x7f;
95*b077aed3SPierre Pronchery s390x_x25519_mod_p(param.x25519.u_src);
96*b077aed3SPierre Pronchery
97*b077aed3SPierre Pronchery s390x_flip_endian32(param.x25519.d_src, d_src);
98*b077aed3SPierre Pronchery param.x25519.d_src[31] &= 248;
99*b077aed3SPierre Pronchery param.x25519.d_src[0] &= 127;
100*b077aed3SPierre Pronchery param.x25519.d_src[0] |= 64;
101*b077aed3SPierre Pronchery
102*b077aed3SPierre Pronchery rc = s390x_pcc(S390X_SCALAR_MULTIPLY_X25519, ¶m.x25519) ? 0 : 1;
103*b077aed3SPierre Pronchery if (rc == 1)
104*b077aed3SPierre Pronchery s390x_flip_endian32(u_dst, param.x25519.u_dst);
105*b077aed3SPierre Pronchery
106*b077aed3SPierre Pronchery OPENSSL_cleanse(param.x25519.d_src, sizeof(param.x25519.d_src));
107*b077aed3SPierre Pronchery return rc;
108*b077aed3SPierre Pronchery }
109*b077aed3SPierre Pronchery
s390x_x448_mul(unsigned char u_dst[56],const unsigned char u_src[56],const unsigned char d_src[56])110*b077aed3SPierre Pronchery int s390x_x448_mul(unsigned char u_dst[56],
111*b077aed3SPierre Pronchery const unsigned char u_src[56],
112*b077aed3SPierre Pronchery const unsigned char d_src[56])
113*b077aed3SPierre Pronchery {
114*b077aed3SPierre Pronchery union {
115*b077aed3SPierre Pronchery struct {
116*b077aed3SPierre Pronchery unsigned char u_dst[64];
117*b077aed3SPierre Pronchery unsigned char u_src[64];
118*b077aed3SPierre Pronchery unsigned char d_src[64];
119*b077aed3SPierre Pronchery } x448;
120*b077aed3SPierre Pronchery unsigned long long buff[512];
121*b077aed3SPierre Pronchery } param;
122*b077aed3SPierre Pronchery int rc;
123*b077aed3SPierre Pronchery
124*b077aed3SPierre Pronchery memset(¶m, 0, sizeof(param));
125*b077aed3SPierre Pronchery
126*b077aed3SPierre Pronchery memcpy(param.x448.u_src, u_src, 56);
127*b077aed3SPierre Pronchery memcpy(param.x448.d_src, d_src, 56);
128*b077aed3SPierre Pronchery
129*b077aed3SPierre Pronchery s390x_flip_endian64(param.x448.u_src, param.x448.u_src);
130*b077aed3SPierre Pronchery s390x_x448_mod_p(param.x448.u_src + 8);
131*b077aed3SPierre Pronchery
132*b077aed3SPierre Pronchery s390x_flip_endian64(param.x448.d_src, param.x448.d_src);
133*b077aed3SPierre Pronchery param.x448.d_src[63] &= 252;
134*b077aed3SPierre Pronchery param.x448.d_src[8] |= 128;
135*b077aed3SPierre Pronchery
136*b077aed3SPierre Pronchery rc = s390x_pcc(S390X_SCALAR_MULTIPLY_X448, ¶m.x448) ? 0 : 1;
137*b077aed3SPierre Pronchery if (rc == 1) {
138*b077aed3SPierre Pronchery s390x_flip_endian64(param.x448.u_dst, param.x448.u_dst);
139*b077aed3SPierre Pronchery memcpy(u_dst, param.x448.u_dst, 56);
140*b077aed3SPierre Pronchery }
141*b077aed3SPierre Pronchery
142*b077aed3SPierre Pronchery OPENSSL_cleanse(param.x448.d_src, sizeof(param.x448.d_src));
143*b077aed3SPierre Pronchery return rc;
144*b077aed3SPierre Pronchery }
145*b077aed3SPierre Pronchery
s390x_ed25519_mul(unsigned char x_dst[32],unsigned char y_dst[32],const unsigned char x_src[32],const unsigned char y_src[32],const unsigned char d_src[32])146*b077aed3SPierre Pronchery int s390x_ed25519_mul(unsigned char x_dst[32],
147*b077aed3SPierre Pronchery unsigned char y_dst[32],
148*b077aed3SPierre Pronchery const unsigned char x_src[32],
149*b077aed3SPierre Pronchery const unsigned char y_src[32],
150*b077aed3SPierre Pronchery const unsigned char d_src[32])
151*b077aed3SPierre Pronchery {
152*b077aed3SPierre Pronchery union {
153*b077aed3SPierre Pronchery struct {
154*b077aed3SPierre Pronchery unsigned char x_dst[32];
155*b077aed3SPierre Pronchery unsigned char y_dst[32];
156*b077aed3SPierre Pronchery unsigned char x_src[32];
157*b077aed3SPierre Pronchery unsigned char y_src[32];
158*b077aed3SPierre Pronchery unsigned char d_src[32];
159*b077aed3SPierre Pronchery } ed25519;
160*b077aed3SPierre Pronchery unsigned long long buff[512];
161*b077aed3SPierre Pronchery } param;
162*b077aed3SPierre Pronchery int rc;
163*b077aed3SPierre Pronchery
164*b077aed3SPierre Pronchery memset(¶m, 0, sizeof(param));
165*b077aed3SPierre Pronchery
166*b077aed3SPierre Pronchery s390x_flip_endian32(param.ed25519.x_src, x_src);
167*b077aed3SPierre Pronchery s390x_flip_endian32(param.ed25519.y_src, y_src);
168*b077aed3SPierre Pronchery s390x_flip_endian32(param.ed25519.d_src, d_src);
169*b077aed3SPierre Pronchery
170*b077aed3SPierre Pronchery rc = s390x_pcc(S390X_SCALAR_MULTIPLY_ED25519, ¶m.ed25519) ? 0 : 1;
171*b077aed3SPierre Pronchery if (rc == 1) {
172*b077aed3SPierre Pronchery s390x_flip_endian32(x_dst, param.ed25519.x_dst);
173*b077aed3SPierre Pronchery s390x_flip_endian32(y_dst, param.ed25519.y_dst);
174*b077aed3SPierre Pronchery }
175*b077aed3SPierre Pronchery
176*b077aed3SPierre Pronchery OPENSSL_cleanse(param.ed25519.d_src, sizeof(param.ed25519.d_src));
177*b077aed3SPierre Pronchery return rc;
178*b077aed3SPierre Pronchery }
179*b077aed3SPierre Pronchery
s390x_ed448_mul(unsigned char x_dst[57],unsigned char y_dst[57],const unsigned char x_src[57],const unsigned char y_src[57],const unsigned char d_src[57])180*b077aed3SPierre Pronchery int s390x_ed448_mul(unsigned char x_dst[57],
181*b077aed3SPierre Pronchery unsigned char y_dst[57],
182*b077aed3SPierre Pronchery const unsigned char x_src[57],
183*b077aed3SPierre Pronchery const unsigned char y_src[57],
184*b077aed3SPierre Pronchery const unsigned char d_src[57])
185*b077aed3SPierre Pronchery {
186*b077aed3SPierre Pronchery union {
187*b077aed3SPierre Pronchery struct {
188*b077aed3SPierre Pronchery unsigned char x_dst[64];
189*b077aed3SPierre Pronchery unsigned char y_dst[64];
190*b077aed3SPierre Pronchery unsigned char x_src[64];
191*b077aed3SPierre Pronchery unsigned char y_src[64];
192*b077aed3SPierre Pronchery unsigned char d_src[64];
193*b077aed3SPierre Pronchery } ed448;
194*b077aed3SPierre Pronchery unsigned long long buff[512];
195*b077aed3SPierre Pronchery } param;
196*b077aed3SPierre Pronchery int rc;
197*b077aed3SPierre Pronchery
198*b077aed3SPierre Pronchery memset(¶m, 0, sizeof(param));
199*b077aed3SPierre Pronchery
200*b077aed3SPierre Pronchery memcpy(param.ed448.x_src, x_src, 57);
201*b077aed3SPierre Pronchery memcpy(param.ed448.y_src, y_src, 57);
202*b077aed3SPierre Pronchery memcpy(param.ed448.d_src, d_src, 57);
203*b077aed3SPierre Pronchery s390x_flip_endian64(param.ed448.x_src, param.ed448.x_src);
204*b077aed3SPierre Pronchery s390x_flip_endian64(param.ed448.y_src, param.ed448.y_src);
205*b077aed3SPierre Pronchery s390x_flip_endian64(param.ed448.d_src, param.ed448.d_src);
206*b077aed3SPierre Pronchery
207*b077aed3SPierre Pronchery rc = s390x_pcc(S390X_SCALAR_MULTIPLY_ED448, ¶m.ed448) ? 0 : 1;
208*b077aed3SPierre Pronchery if (rc == 1) {
209*b077aed3SPierre Pronchery s390x_flip_endian64(param.ed448.x_dst, param.ed448.x_dst);
210*b077aed3SPierre Pronchery s390x_flip_endian64(param.ed448.y_dst, param.ed448.y_dst);
211*b077aed3SPierre Pronchery memcpy(x_dst, param.ed448.x_dst, 57);
212*b077aed3SPierre Pronchery memcpy(y_dst, param.ed448.y_dst, 57);
213*b077aed3SPierre Pronchery }
214*b077aed3SPierre Pronchery
215*b077aed3SPierre Pronchery OPENSSL_cleanse(param.ed448.d_src, sizeof(param.ed448.d_src));
216*b077aed3SPierre Pronchery return rc;
217*b077aed3SPierre Pronchery }
218