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