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