diff --git a/cipher/asm-inline-s390x.h b/cipher/asm-inline-s390x.h index bacb45fe..001cb965 100644 --- a/cipher/asm-inline-s390x.h +++ b/cipher/asm-inline-s390x.h @@ -1,157 +1,205 @@ /* asm-inline-s390x.h - Common macros for zSeries inline assembly * * Copyright (C) 2020 Jussi Kivilinna * * This file is part of Libgcrypt. * * Libgcrypt is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * Libgcrypt is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . */ #ifndef GCRY_ASM_INLINE_S390X_H #define GCRY_ASM_INLINE_S390X_H #include #define ALWAYS_INLINE inline __attribute__((always_inline)) typedef unsigned int u128_t __attribute__ ((mode (TI))); enum kmxx_functions_e { KM_FUNCTION_AES_128 = 18, KM_FUNCTION_AES_192 = 19, KM_FUNCTION_AES_256 = 20, KM_FUNCTION_XTS_AES_128 = 50, KM_FUNCTION_XTS_AES_256 = 52, KMID_FUNCTION_SHA1 = 1, KMID_FUNCTION_SHA256 = 2, KMID_FUNCTION_SHA512 = 3, KMID_FUNCTION_SHA3_224 = 32, KMID_FUNCTION_SHA3_256 = 33, KMID_FUNCTION_SHA3_384 = 34, KMID_FUNCTION_SHA3_512 = 35, KMID_FUNCTION_SHAKE128 = 36, KMID_FUNCTION_SHAKE256 = 37, KMID_FUNCTION_GHASH = 65, + + PCC_FUNCTION_NIST_P256 = 64, + PCC_FUNCTION_NIST_P384 = 65, + PCC_FUNCTION_NIST_P521 = 66, + PCC_FUNCTION_ED25519 = 72, + PCC_FUNCTION_ED448 = 73, + PCC_FUNCTION_X25519 = 80, + PCC_FUNCTION_X448 = 81 }; enum kmxx_function_flags_e { KM_ENCRYPT = 0 << 7, KM_DECRYPT = 1 << 7, KMF_LCFB_16 = 16 << 24, KMA_LPC = 1 << 8, KMA_LAAD = 1 << 9, KMA_HS = 1 << 10, KLMD_PADDING_STATE = 1 << 8, }; static ALWAYS_INLINE u128_t km_function_to_mask(enum kmxx_functions_e func) { return (u128_t)1 << (127 - func); } static inline u128_t kimd_query(void) { static u128_t function_codes = 0; static int initialized = 0; register unsigned long reg0 asm("0") = 0; register void *reg1 asm("1") = &function_codes; u128_t r1; if (initialized) return function_codes; asm volatile ("0: .insn rre,0xb93e << 16, 0, %[r1]\n\t" " brc 1,0b\n\t" : [r1] "=a" (r1) : [reg0] "r" (reg0), [reg1] "r" (reg1) : "cc", "memory"); initialized = 1; return function_codes; } static inline u128_t klmd_query(void) { static u128_t function_codes = 0; static int initialized = 0; register unsigned long reg0 asm("0") = 0; register void *reg1 asm("1") = &function_codes; u128_t r1; if (initialized) return function_codes; asm volatile ("0: .insn rre,0xb93f << 16, 0, %[r1]\n\t" " brc 1,0b\n\t" : [r1] "=a" (r1) : [reg0] "r" (reg0), [reg1] "r" (reg1) : "cc", "memory"); initialized = 1; return function_codes; } +static inline u128_t pcc_query(void) +{ + static u128_t function_codes = 0; + static int initialized = 0; + register unsigned long reg0 asm("0") = 0; + register void *reg1 asm("1") = &function_codes; + + if (initialized) + return function_codes; + + asm volatile ("0: .insn rre,0xb92c << 16, 0, 0\n\t" + " brc 1,0b\n\t" + : + : [reg0] "r" (reg0), [reg1] "r" (reg1) + : "cc", "memory"); + + initialized = 1; + return function_codes; +} + static ALWAYS_INLINE void kimd_execute(unsigned int func, void *param_block, const void *src, size_t src_len) { register unsigned long reg0 asm("0") = func; register byte *reg1 asm("1") = param_block; u128_t r1 = ((u128_t)(uintptr_t)src << 64) | (u64)src_len; asm volatile ("0: .insn rre,0xb93e << 16, 0, %[r1]\n\t" " brc 1,0b\n\t" : [r1] "+a" (r1) : [func] "r" (reg0), [param_ptr] "r" (reg1) : "cc", "memory"); } static ALWAYS_INLINE void klmd_execute(unsigned int func, void *param_block, const void *src, size_t src_len) { register unsigned long reg0 asm("0") = func; register byte *reg1 asm("1") = param_block; u128_t r1 = ((u128_t)(uintptr_t)src << 64) | (u64)src_len; asm volatile ("0: .insn rre,0xb93f << 16, 0, %[r1]\n\t" " brc 1,0b\n\t" : [func] "+r" (reg0), [r1] "+a" (r1) : [param_ptr] "r" (reg1) : "cc", "memory"); } static ALWAYS_INLINE void klmd_shake_execute(unsigned int func, void *param_block, void *dst, size_t dst_len, const void *src, size_t src_len) { register unsigned long reg0 asm("0") = func; register byte *reg1 asm("1") = param_block; u128_t r1 = ((u128_t)(uintptr_t)dst << 64) | (u64)dst_len; u128_t r2 = ((u128_t)(uintptr_t)src << 64) | (u64)src_len; asm volatile ("0: .insn rre,0xb93f << 16, %[r1], %[r2]\n\t" " brc 1,0b\n\t" : [func] "+r" (reg0), [r1] "+a" (r1), [r2] "+a" (r2) : [param_ptr] "r" (reg1) : "cc", "memory"); } +static ALWAYS_INLINE unsigned int +pcc_scalar_multiply(unsigned int func, void *param_block) +{ + register unsigned long reg0 asm("0") = func; + register byte *reg1 asm("1") = param_block; + register unsigned long error = 0; + + asm volatile ("0: .insn rre,0xb92c << 16, 0, 0\n\t" + " brc 1,0b\n\t" + " brc 7,1f\n\t" + " j 2f\n\t" + "1: lhi %[error], 1\n\t" + "2:\n\t" + : [func] "+r" (reg0), [error] "+r" (error) + : [param_ptr] "r" (reg1) + : "cc", "memory"); + + return error; +} + #endif /* GCRY_ASM_INLINE_S390X_H */ diff --git a/mpi/Makefile.am b/mpi/Makefile.am index d06594e1..fe4caedc 100644 --- a/mpi/Makefile.am +++ b/mpi/Makefile.am @@ -1,179 +1,180 @@ ## Process this file with automake to produce Makefile.in # Copyright (C) 1992, 1999, 2000, 2002 Free Software Foundation, Inc. # # This file is part of Libgcrypt. # # Libgcrypt is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as # published by the Free Software Foundation; either version 2.1 of # the License, or (at your option) any later version. # # Libgcrypt is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA # 1.5 leads to a combinatorial explosion due to all the conditionals # I was not able to build it with 64Megs - 1.6 fixes this. # not anymore required: AUTOMAKE_OPTIONS = 1.6 # Need to include ../src in addition to top_srcdir because gcrypt.h is # a built header. AM_CPPFLAGS = -I../src -I$(top_srcdir)/src AM_CFLAGS = $(GPG_ERROR_CFLAGS) AM_ASFLAGS = $(MPI_SFLAGS) AM_CCASFLAGS = $(NOEXECSTACK_FLAGS) EXTRA_DIST = config.links DISTCLEANFILES = mpi-asm-defs.h \ mpih-add1-asm.S mpih-mul1-asm.S mpih-mul2-asm.S mpih-mul3-asm.S \ mpih-lshift-asm.S mpih-rshift-asm.S mpih-sub1-asm.S asm-syntax.h \ mpih-add1.c mpih-mul1.c mpih-mul2.c mpih-mul3.c \ mpih-lshift.c mpih-rshift.c mpih-sub1.c \ sysdep.h mod-source-info.h # Beware: The following list is not a comment but grepped by # config.links to get the list of symlinked modules # Optional modules are marked with an O in the second column. #BEGIN_ASM_LIST # mpih-add1 C # mpih-sub1 C # mpih-mul1 C # mpih-mul2 C # mpih-mul3 C # mpih-lshift C # mpih-rshift C # udiv O # udiv-qrnnd O #END_ASM_LIST # Note: This function has not yet been implemented. There is only a dummy in # generic/ # udiv-w-sdiv O # And we need to have conditionals for all modules because # we don't know whether they are .c or .S. Very ugly; I know. # Remember to define them all in configure.ac if MPI_MOD_ASM_MPIH_ADD1 mpih_add1 = mpih-add1-asm.S else if MPI_MOD_C_MPIH_ADD1 mpih_add1 = mpih-add1.c else mpih_add1 = endif endif if MPI_MOD_ASM_MPIH_SUB1 mpih_sub1 = mpih-sub1-asm.S else if MPI_MOD_C_MPIH_SUB1 mpih_sub1 = mpih-sub1.c else mpih_sub1 = endif endif if MPI_MOD_ASM_MPIH_MUL1 mpih_mul1 = mpih-mul1-asm.S else if MPI_MOD_C_MPIH_MUL1 mpih_mul1 = mpih-mul1.c else mpih_mul1 = endif endif if MPI_MOD_ASM_MPIH_MUL2 mpih_mul2 = mpih-mul2-asm.S else if MPI_MOD_C_MPIH_MUL2 mpih_mul2 = mpih-mul2.c else mpih_mul2 = endif endif if MPI_MOD_ASM_MPIH_MUL3 mpih_mul3 = mpih-mul3-asm.S else if MPI_MOD_C_MPIH_MUL3 mpih_mul3 = mpih-mul3.c else mpih_mul3 = endif endif if MPI_MOD_ASM_MPIH_LSHIFT mpih_lshift = mpih-lshift-asm.S else if MPI_MOD_C_MPIH_LSHIFT mpih_lshift = mpih-lshift.c else mpih_lshift = endif endif if MPI_MOD_ASM_MPIH_RSHIFT mpih_rshift = mpih-rshift-asm.S else if MPI_MOD_C_MPIH_RSHIFT mpih_rshift = mpih-rshift.c else mpih_rshift = endif endif if MPI_MOD_ASM_UDIV udiv = udiv-asm.S else if MPI_MOD_C_UDIV udiv = udiv.c else udiv = endif endif if MPI_MOD_ASM_UDIV_QRNND udiv_qrnnd = udiv-qrnnd-asm.S else if MPI_MOD_C_UDIV_QRNND udiv_qrnnd = udiv-qrnnd.c else udiv_qrnnd = endif endif noinst_LTLIBRARIES = libmpi.la libmpi_la_LDFLAGS = nodist_libmpi_la_SOURCES = $(mpih_add1) $(mpih_sub1) $(mpih_mul1) \ $(mpih_mul2) $(mpih_mul3) $(mpih_lshift) $(mpih_rshift) \ $(udiv) $(udiv_qrnnd) libmpi_la_SOURCES = longlong.h \ mpi-add.c \ mpi-bit.c \ mpi-cmp.c \ mpi-div.c \ mpi-gcd.c \ mpi-internal.h \ mpi-inline.h \ mpi-inline.c \ mpi-inv.c \ mpi-mul.c \ mpi-mod.c \ mpi-pow.c \ mpi-mpow.c \ mpi-scan.c \ mpicoder.c \ mpih-div.c \ mpih-mul.c \ mpih-const-time.c \ mpiutil.c \ - ec.c ec-internal.h ec-ed25519.c + ec.c ec-internal.h ec-ed25519.c \ + ec-hw-s390x.c EXTRA_libmpi_la_SOURCES = asm-common-aarch64.h diff --git a/mpi/ec-hw-s390x.c b/mpi/ec-hw-s390x.c new file mode 100644 index 00000000..149a061d --- /dev/null +++ b/mpi/ec-hw-s390x.c @@ -0,0 +1,412 @@ +/* ec-hw-s390x.c - zSeries ECC acceleration + * Copyright (C) 2021 Jussi Kivilinna + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ + +#include +#include +#include +#include + +#ifdef HAVE_GCC_INLINE_ASM_S390X + +#include "mpi-internal.h" +#include "g10lib.h" +#include "context.h" +#include "ec-context.h" +#include "ec-internal.h" + +#include "../cipher/bufhelp.h" +#include "../cipher/asm-inline-s390x.h" + + +#define S390X_PCC_PARAM_BLOCK_SIZE 4096 + + +extern void reverse_buffer (unsigned char *buffer, unsigned int length); + +static int s390_mul_point_montgomery (mpi_point_t result, gcry_mpi_t scalar, + mpi_point_t point, mpi_ec_t ctx, + byte *param_block_buf); + + +static int +mpi_copy_to_raw(byte *raw, unsigned int raw_nbytes, gcry_mpi_t a) +{ + unsigned int num_to_zero; + unsigned int nbytes; + int i, j; + + if (mpi_has_sign (a)) + return -1; + + if (mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE)) + { + unsigned int nbits; + byte *buf; + + buf = mpi_get_opaque (a, &nbits); + nbytes = (nbits + 7) / 8; + + if (raw_nbytes < nbytes) + return -1; + + num_to_zero = raw_nbytes - nbytes; + if (num_to_zero > 0) + memset (raw, 0, num_to_zero); + if (nbytes > 0) + memcpy (raw + num_to_zero, buf, nbytes); + + return 0; + } + + nbytes = a->nlimbs * BYTES_PER_MPI_LIMB; + if (raw_nbytes < nbytes) + return -1; + + num_to_zero = raw_nbytes - nbytes; + if (num_to_zero > 0) + memset (raw, 0, num_to_zero); + + for (j = a->nlimbs - 1, i = 0; i < a->nlimbs; i++, j--) + { + buf_put_be64(raw + num_to_zero + i * BYTES_PER_MPI_LIMB, a->d[j]); + } + + return 0; +} + +int +_gcry_s390x_ec_hw_mul_point (mpi_point_t result, gcry_mpi_t scalar, + mpi_point_t point, mpi_ec_t ctx) +{ + byte param_block_buf[S390X_PCC_PARAM_BLOCK_SIZE]; + byte *param_out_x = NULL; + byte *param_out_y = NULL; + byte *param_in_x = NULL; + byte *param_in_y = NULL; + byte *param_scalar = NULL; + unsigned int field_nbits; + unsigned int pcc_func; + gcry_mpi_t x, y; + gcry_mpi_t d = NULL; + int rc = -1; + + if (ctx->name == NULL) + return -1; + + if (!(_gcry_get_hw_features () & HWF_S390X_MSA_9)) + return -1; /* ECC acceleration not supported by HW. */ + + if (ctx->model == MPI_EC_MONTGOMERY) + return s390_mul_point_montgomery (result, scalar, point, ctx, + param_block_buf); + + if (ctx->model == MPI_EC_WEIERSTRASS && ctx->nbits == 256 && + strcmp (ctx->name, "NIST P-256") == 0) + { + struct pcc_param_block_nistp256_s + { + byte out_x[256 / 8]; + byte out_y[256 / 8]; + byte in_x[256 / 8]; + byte in_y[256 / 8]; + byte scalar[256 / 8]; + byte c_and_ribm[64]; + } *params = (void *)param_block_buf; + + memset (params->c_and_ribm, 0, sizeof(params->c_and_ribm)); + + pcc_func = PCC_FUNCTION_NIST_P256; + field_nbits = 256; + param_out_x = params->out_x; + param_out_y = params->out_y; + param_in_x = params->in_x; + param_in_y = params->in_y; + param_scalar = params->scalar; + } + else if (ctx->model == MPI_EC_WEIERSTRASS && ctx->nbits == 384 && + strcmp (ctx->name, "NIST P-384") == 0) + { + struct pcc_param_block_nistp384_s + { + byte out_x[384 / 8]; + byte out_y[384 / 8]; + byte in_x[384 / 8]; + byte in_y[384 / 8]; + byte scalar[384 / 8]; + byte c_and_ribm[64]; + } *params = (void *)param_block_buf; + + memset (params->c_and_ribm, 0, sizeof(params->c_and_ribm)); + + pcc_func = PCC_FUNCTION_NIST_P384; + field_nbits = 384; + param_out_x = params->out_x; + param_out_y = params->out_y; + param_in_x = params->in_x; + param_in_y = params->in_y; + param_scalar = params->scalar; + } + else if (ctx->model == MPI_EC_WEIERSTRASS && ctx->nbits == 521 && + strcmp (ctx->name, "NIST P-521") == 0) + { + struct pcc_param_block_nistp521_s + { + byte out_x[640 / 8]; /* note: first 14 bytes not modified by pcc */ + byte out_y[640 / 8]; /* note: first 14 bytes not modified by pcc */ + byte in_x[640 / 8]; + byte in_y[640 / 8]; + byte scalar[640 / 8]; + byte c_and_ribm[64]; + } *params = (void *)param_block_buf; + + memset (params->out_x, 0, 14); + memset (params->out_y, 0, 14); + memset (params->c_and_ribm, 0, sizeof(params->c_and_ribm)); + + pcc_func = PCC_FUNCTION_NIST_P521; + field_nbits = 640; + param_out_x = params->out_x; + param_out_y = params->out_y; + param_in_x = params->in_x; + param_in_y = params->in_y; + param_scalar = params->scalar; + } + else if (ctx->model == MPI_EC_EDWARDS && ctx->nbits == 255 && + strcmp (ctx->name, "Ed25519") == 0) + { + struct pcc_param_block_ed25519_s + { + byte out_x[256 / 8]; + byte out_y[256 / 8]; + byte in_x[256 / 8]; + byte in_y[256 / 8]; + byte scalar[256 / 8]; + byte c_and_ribm[64]; + } *params = (void *)param_block_buf; + + memset (params->c_and_ribm, 0, sizeof(params->c_and_ribm)); + + pcc_func = PCC_FUNCTION_ED25519; + field_nbits = 256; + param_out_x = params->out_x; + param_out_y = params->out_y; + param_in_x = params->in_x; + param_in_y = params->in_y; + param_scalar = params->scalar; + } + else if (ctx->model == MPI_EC_EDWARDS && ctx->nbits == 448 && + strcmp (ctx->name, "Ed448") == 0) + { + struct pcc_param_block_ed448_s + { + byte out_x[512 / 8]; /* note: first 8 bytes not modified by pcc */ + byte out_y[512 / 8]; /* note: first 8 bytes not modified by pcc */ + byte in_x[512 / 8]; + byte in_y[512 / 8]; + byte scalar[512 / 8]; + byte c_and_ribm[64]; + } *params = (void *)param_block_buf; + + memset (params->out_x, 0, 8); + memset (params->out_y, 0, 8); + memset (params->c_and_ribm, 0, sizeof(params->c_and_ribm)); + + pcc_func = PCC_FUNCTION_ED448; + field_nbits = 512; + param_out_x = params->out_x; + param_out_y = params->out_y; + param_in_x = params->in_x; + param_in_y = params->in_y; + param_scalar = params->scalar; + } + + if (param_scalar == NULL) + return -1; /* No curve match. */ + + if (!(pcc_query () & km_function_to_mask (pcc_func))) + return -1; /* HW does not support acceleration for this curve. */ + + x = mpi_new (0); + y = mpi_new (0); + + if (_gcry_mpi_ec_get_affine (x, y, point, ctx) < 0) + { + /* Point at infinity. */ + goto out; + } + + if (mpi_has_sign (scalar) || mpi_cmp (scalar, ctx->n) >= 0) + { + d = mpi_is_secure (scalar) ? mpi_snew (ctx->nbits) : mpi_new (ctx->nbits); + _gcry_mpi_mod (d, scalar, ctx->n); + } + else + { + d = scalar; + } + + if (mpi_copy_to_raw (param_in_x, field_nbits / 8, x) < 0) + goto out; + + if (mpi_copy_to_raw (param_in_y, field_nbits / 8, y) < 0) + goto out; + + if (mpi_copy_to_raw (param_scalar, field_nbits / 8, d) < 0) + goto out; + + if (pcc_scalar_multiply (pcc_func, param_block_buf) != 0) + goto out; + + _gcry_mpi_set_buffer (result->x, param_out_x, field_nbits / 8, 0); + _gcry_mpi_set_buffer (result->y, param_out_y, field_nbits / 8, 0); + mpi_set_ui (result->z, 1); + mpi_normalize (result->x); + mpi_normalize (result->y); + if (ctx->model == MPI_EC_EDWARDS) + mpi_point_resize (result, ctx); + + rc = 0; + +out: + if (d != scalar) + mpi_release (d); + mpi_release (y); + mpi_release (x); + wipememory (param_block_buf, S390X_PCC_PARAM_BLOCK_SIZE); + + return rc; +} + + +static int +s390_mul_point_montgomery (mpi_point_t result, gcry_mpi_t scalar, + mpi_point_t point, mpi_ec_t ctx, + byte *param_block_buf) +{ + byte *param_out_x = NULL; + byte *param_in_x = NULL; + byte *param_scalar = NULL; + unsigned int field_nbits; + unsigned int pcc_func; + gcry_mpi_t x; + gcry_mpi_t d = NULL; + int rc = -1; + + if (ctx->nbits == 255 && strcmp (ctx->name, "Curve25519") == 0) + { + struct pcc_param_block_x25519_s + { + byte out_x[256 / 8]; + byte in_x[256 / 8]; + byte scalar[256 / 8]; + byte c_and_ribm[64]; + } *params = (void *)param_block_buf; + + memset (params->c_and_ribm, 0, sizeof(params->c_and_ribm)); + + pcc_func = PCC_FUNCTION_X25519; + field_nbits = 256; + param_out_x = params->out_x; + param_in_x = params->in_x; + param_scalar = params->scalar; + } + else if (ctx->nbits == 448 && strcmp (ctx->name, "X448") == 0) + { + struct pcc_param_block_x448_s + { + byte out_x[512 / 8]; /* note: first 8 bytes not modified by pcc */ + byte in_x[512 / 8]; + byte scalar[512 / 8]; + byte c_and_ribm[64]; + } *params = (void *)param_block_buf; + + memset (params->out_x, 0, 8); + memset (params->c_and_ribm, 0, sizeof(params->c_and_ribm)); + + pcc_func = PCC_FUNCTION_X448; + field_nbits = 512; + param_out_x = params->out_x; + param_in_x = params->in_x; + param_scalar = params->scalar; + } + + if (param_scalar == NULL) + return -1; /* No curve match. */ + + if (!(pcc_query () & km_function_to_mask (pcc_func))) + return -1; /* HW does not support acceleration for this curve. */ + + x = mpi_new (0); + + if (mpi_is_opaque (scalar)) + { + const unsigned int pbits = ctx->nbits; + unsigned int n; + unsigned char *raw; + + raw = _gcry_mpi_get_opaque_copy (scalar, &n); + if ((n + 7) / 8 != (pbits + 7) / 8) + log_fatal ("scalar size (%d) != prime size (%d)\n", + (n + 7) / 8, (pbits + 7) / 8); + + reverse_buffer (raw, (n + 7 ) / 8); + if ((pbits % 8)) + raw[0] &= (1 << (pbits % 8)) - 1; + raw[0] |= (1 << ((pbits + 7) % 8)); + raw[(pbits + 7) / 8 - 1] &= (256 - ctx->h); + d = mpi_is_secure (scalar) ? mpi_snew (pbits) : mpi_new (pbits); + _gcry_mpi_set_buffer (d, raw, (n + 7) / 8, 0); + xfree (raw); + } + else + { + d = scalar; + } + + if (_gcry_mpi_ec_get_affine (x, NULL, point, ctx) < 0) + { + /* Point at infinity. */ + goto out; + } + + if (mpi_copy_to_raw (param_in_x, field_nbits / 8, x) < 0) + goto out; + + if (mpi_copy_to_raw (param_scalar, field_nbits / 8, d) < 0) + goto out; + + if (pcc_scalar_multiply (pcc_func, param_block_buf) != 0) + goto out; + + _gcry_mpi_set_buffer (result->x, param_out_x, field_nbits / 8, 0); + mpi_set_ui (result->z, 1); + mpi_point_resize (result, ctx); + + rc = 0; + +out: + if (d != scalar) + mpi_release (d); + mpi_release (x); + wipememory (param_block_buf, S390X_PCC_PARAM_BLOCK_SIZE); + + return rc; +} + +#endif /* HAVE_GCC_INLINE_ASM_S390X */ diff --git a/mpi/ec-internal.h b/mpi/ec-internal.h index 759335aa..5dc5b071 100644 --- a/mpi/ec-internal.h +++ b/mpi/ec-internal.h @@ -1,25 +1,33 @@ /* ec-internal.h - Internal declarations of ec*.c * Copyright (C) 2013 g10 Code GmbH * * This file is part of Libgcrypt. * * Libgcrypt is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * Libgcrypt is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . */ #ifndef GCRY_EC_INTERNAL_H #define GCRY_EC_INTERNAL_H void _gcry_mpi_ec_ed25519_mod (gcry_mpi_t a); +#ifdef HAVE_GCC_INLINE_ASM_S390X +int _gcry_s390x_ec_hw_mul_point (mpi_point_t result, gcry_mpi_t scalar, + mpi_point_t point, mpi_ec_t ctx); +# define mpi_ec_hw_mul_point _gcry_s390x_ec_hw_mul_point +#else +# define mpi_ec_hw_mul_point(r,s,p,c) (-1) +#endif + #endif /*GCRY_EC_INTERNAL_H*/ diff --git a/mpi/ec.c b/mpi/ec.c index 0b6ae9a9..d1b0286c 100644 --- a/mpi/ec.c +++ b/mpi/ec.c @@ -1,2062 +1,2070 @@ /* ec.c - Elliptic Curve functions * Copyright (C) 2007 Free Software Foundation, Inc. * Copyright (C) 2013 g10 Code GmbH * * This file is part of Libgcrypt. * * Libgcrypt is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * Libgcrypt is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . */ #include #include #include #include #include "mpi-internal.h" #include "longlong.h" #include "g10lib.h" #include "context.h" #include "ec-context.h" #include "ec-internal.h" extern void reverse_buffer (unsigned char *buffer, unsigned int length); #define point_init(a) _gcry_mpi_point_init ((a)) #define point_free(a) _gcry_mpi_point_free_parts ((a)) /* Print a point using the log functions. If CTX is not NULL affine coordinates will be printed. */ void _gcry_mpi_point_log (const char *name, mpi_point_t point, mpi_ec_t ctx) { gcry_mpi_t x, y; char buf[100]; if (!point) { snprintf (buf, sizeof buf - 1, "%s.*", name); log_mpidump (buf, NULL); return; } snprintf (buf, sizeof buf - 1, "%s.X", name); if (ctx) { x = mpi_new (0); y = mpi_new (0); } if (!ctx || _gcry_mpi_ec_get_affine (x, y, point, ctx)) { log_mpidump (buf, point->x); buf[strlen(buf)-1] = 'Y'; log_mpidump (buf, point->y); buf[strlen(buf)-1] = 'Z'; log_mpidump (buf, point->z); } else { buf[strlen(buf)-1] = 'x'; log_mpidump (buf, x); buf[strlen(buf)-1] = 'y'; log_mpidump (buf, y); } if (ctx) { _gcry_mpi_release (x); _gcry_mpi_release (y); } } /* Create a new point option. NBITS gives the size in bits of one coordinate; it is only used to pre-allocate some resources and might also be passed as 0 to use a default value. */ mpi_point_t _gcry_mpi_point_new (unsigned int nbits) { mpi_point_t p; (void)nbits; /* Currently not used. */ p = xmalloc (sizeof *p); _gcry_mpi_point_init (p); return p; } /* Release the point object P. P may be NULL. */ void _gcry_mpi_point_release (mpi_point_t p) { if (p) { _gcry_mpi_point_free_parts (p); xfree (p); } } /* Initialize the fields of a point object. gcry_mpi_point_free_parts may be used to release the fields. */ void _gcry_mpi_point_init (mpi_point_t p) { p->x = mpi_new (0); p->y = mpi_new (0); p->z = mpi_new (0); } /* Release the parts of a point object. */ void _gcry_mpi_point_free_parts (mpi_point_t p) { mpi_free (p->x); p->x = NULL; mpi_free (p->y); p->y = NULL; mpi_free (p->z); p->z = NULL; } /* Set the value from S into D. */ static void point_set (mpi_point_t d, mpi_point_t s) { mpi_set (d->x, s->x); mpi_set (d->y, s->y); mpi_set (d->z, s->z); } /* Return a copy of POINT. */ gcry_mpi_point_t _gcry_mpi_point_copy (gcry_mpi_point_t point) { mpi_point_t newpoint; newpoint = _gcry_mpi_point_new (0); if (point) point_set (newpoint, point); return newpoint; } void _gcry_mpi_ec_point_resize (mpi_point_t p, mpi_ec_t ctx) { size_t nlimbs = ctx->p->nlimbs; mpi_resize (p->x, nlimbs); p->x->nlimbs = nlimbs; mpi_resize (p->z, nlimbs); p->z->nlimbs = nlimbs; if (ctx->model != MPI_EC_MONTGOMERY) { mpi_resize (p->y, nlimbs); p->y->nlimbs = nlimbs; } } static void point_swap_cond (mpi_point_t d, mpi_point_t s, unsigned long swap, mpi_ec_t ctx) { mpi_swap_cond (d->x, s->x, swap); if (ctx->model != MPI_EC_MONTGOMERY) mpi_swap_cond (d->y, s->y, swap); mpi_swap_cond (d->z, s->z, swap); } /* Set the projective coordinates from POINT into X, Y, and Z. If a coordinate is not required, X, Y, or Z may be passed as NULL. */ void _gcry_mpi_point_get (gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t z, mpi_point_t point) { if (x) mpi_set (x, point->x); if (y) mpi_set (y, point->y); if (z) mpi_set (z, point->z); } /* Set the projective coordinates from POINT into X, Y, and Z and release POINT. If a coordinate is not required, X, Y, or Z may be passed as NULL. */ void _gcry_mpi_point_snatch_get (gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t z, mpi_point_t point) { mpi_snatch (x, point->x); mpi_snatch (y, point->y); mpi_snatch (z, point->z); xfree (point); } /* Set the projective coordinates from X, Y, and Z into POINT. If a coordinate is given as NULL, the value 0 is stored into point. If POINT is given as NULL a new point object is allocated. Returns POINT or the newly allocated point object. */ mpi_point_t _gcry_mpi_point_set (mpi_point_t point, gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t z) { if (!point) point = mpi_point_new (0); if (x) mpi_set (point->x, x); else mpi_clear (point->x); if (y) mpi_set (point->y, y); else mpi_clear (point->y); if (z) mpi_set (point->z, z); else mpi_clear (point->z); return point; } /* Set the projective coordinates from X, Y, and Z into POINT. If a coordinate is given as NULL, the value 0 is stored into point. If POINT is given as NULL a new point object is allocated. The coordinates X, Y, and Z are released. Returns POINT or the newly allocated point object. */ mpi_point_t _gcry_mpi_point_snatch_set (mpi_point_t point, gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t z) { if (!point) point = mpi_point_new (0); if (x) mpi_snatch (point->x, x); else mpi_clear (point->x); if (y) mpi_snatch (point->y, y); else mpi_clear (point->y); if (z) mpi_snatch (point->z, z); else mpi_clear (point->z); return point; } /* W = W mod P. */ static void ec_mod (gcry_mpi_t w, mpi_ec_t ec) { if (0 && ec->dialect == ECC_DIALECT_ED25519) _gcry_mpi_ec_ed25519_mod (w); else if (ec->t.p_barrett) _gcry_mpi_mod_barrett (w, w, ec->t.p_barrett); else _gcry_mpi_mod (w, w, ec->p); } static void ec_addm (gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, mpi_ec_t ctx) { mpi_add (w, u, v); ec_mod (w, ctx); } static void ec_subm (gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, mpi_ec_t ec) { mpi_sub (w, u, v); while (w->sign) mpi_add (w, w, ec->p); /*ec_mod (w, ec);*/ } static void ec_mulm (gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, mpi_ec_t ctx) { mpi_mul (w, u, v); ec_mod (w, ctx); } /* W = 2 * U mod P. */ static void ec_mul2 (gcry_mpi_t w, gcry_mpi_t u, mpi_ec_t ctx) { mpi_lshift (w, u, 1); ec_mod (w, ctx); } static void ec_powm (gcry_mpi_t w, const gcry_mpi_t b, const gcry_mpi_t e, mpi_ec_t ctx) { mpi_powm (w, b, e, ctx->p); /* _gcry_mpi_abs (w); */ } /* Shortcut for ec_powm (B, B, mpi_const (MPI_C_TWO), ctx); for easier optimization. */ static void ec_pow2 (gcry_mpi_t w, const gcry_mpi_t b, mpi_ec_t ctx) { /* Using mpi_mul is slightly faster (at least on amd64). */ /* mpi_powm (w, b, mpi_const (MPI_C_TWO), ctx->p); */ ec_mulm (w, b, b, ctx); } /* Shortcut for ec_powm (B, B, mpi_const (MPI_C_THREE), ctx); for easier optimization. */ static void ec_pow3 (gcry_mpi_t w, const gcry_mpi_t b, mpi_ec_t ctx) { mpi_powm (w, b, mpi_const (MPI_C_THREE), ctx->p); } static void ec_invm (gcry_mpi_t x, gcry_mpi_t a, mpi_ec_t ctx) { if (!mpi_invm (x, a, ctx->p)) { log_error ("ec_invm: inverse does not exist:\n"); log_mpidump (" a", a); log_mpidump (" p", ctx->p); } } /* Routines for 2^255 - 19. */ #define LIMB_SIZE_25519 ((256+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB) static void ec_addm_25519 (gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, mpi_ec_t ctx) { mpi_ptr_t wp, up, vp; mpi_size_t wsize = LIMB_SIZE_25519; mpi_limb_t n[LIMB_SIZE_25519]; mpi_limb_t borrow; if (w->nlimbs != wsize || u->nlimbs != wsize || v->nlimbs != wsize) log_bug ("addm_25519: different sizes\n"); memset (n, 0, sizeof n); up = u->d; vp = v->d; wp = w->d; _gcry_mpih_add_n (wp, up, vp, wsize); borrow = _gcry_mpih_sub_n (wp, wp, ctx->p->d, wsize); mpih_set_cond (n, ctx->p->d, wsize, (borrow != 0UL)); _gcry_mpih_add_n (wp, wp, n, wsize); wp[LIMB_SIZE_25519-1] &= ~((mpi_limb_t)1 << (255 % BITS_PER_MPI_LIMB)); } static void ec_subm_25519 (gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, mpi_ec_t ctx) { mpi_ptr_t wp, up, vp; mpi_size_t wsize = LIMB_SIZE_25519; mpi_limb_t n[LIMB_SIZE_25519]; mpi_limb_t borrow; if (w->nlimbs != wsize || u->nlimbs != wsize || v->nlimbs != wsize) log_bug ("subm_25519: different sizes\n"); memset (n, 0, sizeof n); up = u->d; vp = v->d; wp = w->d; borrow = _gcry_mpih_sub_n (wp, up, vp, wsize); mpih_set_cond (n, ctx->p->d, wsize, (borrow != 0UL)); _gcry_mpih_add_n (wp, wp, n, wsize); wp[LIMB_SIZE_25519-1] &= ~((mpi_limb_t)1 << (255 % BITS_PER_MPI_LIMB)); } static void ec_mulm_25519 (gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, mpi_ec_t ctx) { mpi_ptr_t wp, up, vp; mpi_size_t wsize = LIMB_SIZE_25519; mpi_limb_t n[LIMB_SIZE_25519*2]; mpi_limb_t m[LIMB_SIZE_25519+1]; mpi_limb_t cy; int msb; (void)ctx; if (w->nlimbs != wsize || u->nlimbs != wsize || v->nlimbs != wsize) log_bug ("mulm_25519: different sizes\n"); up = u->d; vp = v->d; wp = w->d; _gcry_mpih_mul_n (n, up, vp, wsize); memcpy (wp, n, wsize * BYTES_PER_MPI_LIMB); wp[LIMB_SIZE_25519-1] &= ~((mpi_limb_t)1 << (255 % BITS_PER_MPI_LIMB)); memcpy (m, n+LIMB_SIZE_25519-1, (wsize+1) * BYTES_PER_MPI_LIMB); _gcry_mpih_rshift (m, m, LIMB_SIZE_25519+1, (255 % BITS_PER_MPI_LIMB)); memcpy (n, m, wsize * BYTES_PER_MPI_LIMB); cy = _gcry_mpih_lshift (m, m, LIMB_SIZE_25519, 4); m[LIMB_SIZE_25519] = cy; cy = _gcry_mpih_add_n (m, m, n, wsize); m[LIMB_SIZE_25519] += cy; cy = _gcry_mpih_add_n (m, m, n, wsize); m[LIMB_SIZE_25519] += cy; cy = _gcry_mpih_add_n (m, m, n, wsize); m[LIMB_SIZE_25519] += cy; cy = _gcry_mpih_add_n (wp, wp, m, wsize); m[LIMB_SIZE_25519] += cy; memset (m, 0, wsize * BYTES_PER_MPI_LIMB); msb = (wp[LIMB_SIZE_25519-1] >> (255 % BITS_PER_MPI_LIMB)); m[0] = (m[LIMB_SIZE_25519] * 2 + msb) * 19; wp[LIMB_SIZE_25519-1] &= ~((mpi_limb_t)1 << (255 % BITS_PER_MPI_LIMB)); _gcry_mpih_add_n (wp, wp, m, wsize); m[0] = 0; cy = _gcry_mpih_sub_n (wp, wp, ctx->p->d, wsize); mpih_set_cond (m, ctx->p->d, wsize, (cy != 0UL)); _gcry_mpih_add_n (wp, wp, m, wsize); } static void ec_mul2_25519 (gcry_mpi_t w, gcry_mpi_t u, mpi_ec_t ctx) { ec_addm_25519 (w, u, u, ctx); } static void ec_pow2_25519 (gcry_mpi_t w, const gcry_mpi_t b, mpi_ec_t ctx) { ec_mulm_25519 (w, b, b, ctx); } /* Routines for 2^448 - 2^224 - 1. */ #define LIMB_SIZE_448 ((448+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB) #define LIMB_SIZE_HALF_448 ((LIMB_SIZE_448+1)/2) static void ec_addm_448 (gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, mpi_ec_t ctx) { mpi_ptr_t wp, up, vp; mpi_size_t wsize = LIMB_SIZE_448; mpi_limb_t n[LIMB_SIZE_448]; mpi_limb_t cy; if (w->nlimbs != wsize || u->nlimbs != wsize || v->nlimbs != wsize) log_bug ("addm_448: different sizes\n"); memset (n, 0, sizeof n); up = u->d; vp = v->d; wp = w->d; cy = _gcry_mpih_add_n (wp, up, vp, wsize); mpih_set_cond (n, ctx->p->d, wsize, (cy != 0UL)); _gcry_mpih_sub_n (wp, wp, n, wsize); } static void ec_subm_448 (gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, mpi_ec_t ctx) { mpi_ptr_t wp, up, vp; mpi_size_t wsize = LIMB_SIZE_448; mpi_limb_t n[LIMB_SIZE_448]; mpi_limb_t borrow; if (w->nlimbs != wsize || u->nlimbs != wsize || v->nlimbs != wsize) log_bug ("subm_448: different sizes\n"); memset (n, 0, sizeof n); up = u->d; vp = v->d; wp = w->d; borrow = _gcry_mpih_sub_n (wp, up, vp, wsize); mpih_set_cond (n, ctx->p->d, wsize, (borrow != 0UL)); _gcry_mpih_add_n (wp, wp, n, wsize); } static void ec_mulm_448 (gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, mpi_ec_t ctx) { mpi_ptr_t wp, up, vp; mpi_size_t wsize = LIMB_SIZE_448; mpi_limb_t n[LIMB_SIZE_448*2]; mpi_limb_t a2[LIMB_SIZE_HALF_448]; mpi_limb_t a3[LIMB_SIZE_HALF_448]; mpi_limb_t b0[LIMB_SIZE_HALF_448]; mpi_limb_t b1[LIMB_SIZE_HALF_448]; mpi_limb_t cy; int i; #if (LIMB_SIZE_HALF_448 > LIMB_SIZE_448/2) mpi_limb_t b1_rest, a3_rest; #endif if (w->nlimbs != wsize || u->nlimbs != wsize || v->nlimbs != wsize) log_bug ("mulm_448: different sizes\n"); up = u->d; vp = v->d; wp = w->d; _gcry_mpih_mul_n (n, up, vp, wsize); for (i = 0; i < (wsize + 1)/ 2; i++) { b0[i] = n[i]; b1[i] = n[i+wsize/2]; a2[i] = n[i+wsize]; a3[i] = n[i+wsize+wsize/2]; } #if (LIMB_SIZE_HALF_448 > LIMB_SIZE_448/2) b0[LIMB_SIZE_HALF_448-1] &= ((mpi_limb_t)1UL<<32)-1; a2[LIMB_SIZE_HALF_448-1] &= ((mpi_limb_t)1UL<<32)-1; b1_rest = 0; a3_rest = 0; for (i = (wsize + 1)/ 2 -1; i >= 0; i--) { mpi_limb_t b1v, a3v; b1v = b1[i]; a3v = a3[i]; b1[i] = (b1_rest<<32) | (b1v >> 32); a3[i] = (a3_rest<<32) | (a3v >> 32); b1_rest = b1v & (((mpi_limb_t)1UL <<32)-1); a3_rest = a3v & (((mpi_limb_t)1UL <<32)-1); } #endif cy = _gcry_mpih_add_n (b0, b0, a2, LIMB_SIZE_HALF_448); cy += _gcry_mpih_add_n (b0, b0, a3, LIMB_SIZE_HALF_448); for (i = 0; i < (wsize + 1)/ 2; i++) wp[i] = b0[i]; #if (LIMB_SIZE_HALF_448 > LIMB_SIZE_448/2) wp[LIMB_SIZE_HALF_448-1] &= (((mpi_limb_t)1UL <<32)-1); #endif #if (LIMB_SIZE_HALF_448 > LIMB_SIZE_448/2) cy = b0[LIMB_SIZE_HALF_448-1] >> 32; #endif cy = _gcry_mpih_add_1 (b1, b1, LIMB_SIZE_HALF_448, cy); cy += _gcry_mpih_add_n (b1, b1, a2, LIMB_SIZE_HALF_448); cy += _gcry_mpih_add_n (b1, b1, a3, LIMB_SIZE_HALF_448); cy += _gcry_mpih_add_n (b1, b1, a3, LIMB_SIZE_HALF_448); #if (LIMB_SIZE_HALF_448 > LIMB_SIZE_448/2) b1_rest = 0; for (i = (wsize + 1)/ 2 -1; i >= 0; i--) { mpi_limb_t b1v = b1[i]; b1[i] = (b1_rest<<32) | (b1v >> 32); b1_rest = b1v & (((mpi_limb_t)1UL <<32)-1); } wp[LIMB_SIZE_HALF_448-1] |= (b1_rest << 32); #endif for (i = 0; i < wsize / 2; i++) wp[i+(wsize + 1) / 2] = b1[i]; #if (LIMB_SIZE_HALF_448 > LIMB_SIZE_448/2) cy = b1[LIMB_SIZE_HALF_448-1]; #endif memset (n, 0, wsize * BYTES_PER_MPI_LIMB); #if (LIMB_SIZE_HALF_448 > LIMB_SIZE_448/2) n[LIMB_SIZE_HALF_448-1] = cy << 32; #else n[LIMB_SIZE_HALF_448] = cy; #endif n[0] = cy; _gcry_mpih_add_n (wp, wp, n, wsize); memset (n, 0, wsize * BYTES_PER_MPI_LIMB); cy = _gcry_mpih_sub_n (wp, wp, ctx->p->d, wsize); mpih_set_cond (n, ctx->p->d, wsize, (cy != 0UL)); _gcry_mpih_add_n (wp, wp, n, wsize); } static void ec_mul2_448 (gcry_mpi_t w, gcry_mpi_t u, mpi_ec_t ctx) { ec_addm_448 (w, u, u, ctx); } static void ec_pow2_448 (gcry_mpi_t w, const gcry_mpi_t b, mpi_ec_t ctx) { ec_mulm_448 (w, b, b, ctx); } struct field_table { const char *p; /* computation routines for the field. */ void (* addm) (gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, mpi_ec_t ctx); void (* subm) (gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, mpi_ec_t ctx); void (* mulm) (gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, mpi_ec_t ctx); void (* mul2) (gcry_mpi_t w, gcry_mpi_t u, mpi_ec_t ctx); void (* pow2) (gcry_mpi_t w, const gcry_mpi_t b, mpi_ec_t ctx); }; static const struct field_table field_table[] = { { "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED", ec_addm_25519, ec_subm_25519, ec_mulm_25519, ec_mul2_25519, ec_pow2_25519 }, { "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", ec_addm_448, ec_subm_448, ec_mulm_448, ec_mul2_448, ec_pow2_448 }, { NULL, NULL, NULL, NULL, NULL, NULL }, }; /* Force recomputation of all helper variables. */ void _gcry_mpi_ec_get_reset (mpi_ec_t ec) { ec->t.valid.a_is_pminus3 = 0; ec->t.valid.two_inv_p = 0; } /* Accessor for helper variable. */ static int ec_get_a_is_pminus3 (mpi_ec_t ec) { gcry_mpi_t tmp; if (!ec->t.valid.a_is_pminus3) { ec->t.valid.a_is_pminus3 = 1; tmp = mpi_alloc_like (ec->p); mpi_sub_ui (tmp, ec->p, 3); ec->t.a_is_pminus3 = !mpi_cmp (ec->a, tmp); mpi_free (tmp); } return ec->t.a_is_pminus3; } /* Accessor for helper variable. */ static gcry_mpi_t ec_get_two_inv_p (mpi_ec_t ec) { if (!ec->t.valid.two_inv_p) { ec->t.valid.two_inv_p = 1; if (!ec->t.two_inv_p) ec->t.two_inv_p = mpi_alloc (0); ec_invm (ec->t.two_inv_p, mpi_const (MPI_C_TWO), ec); } return ec->t.two_inv_p; } static const char *const curve25519_bad_points[] = { "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000001", "0x00b8495f16056286fdb1329ceb8d09da6ac49ff1fae35616aeb8413b7c7aebe0", "0x57119fd0dd4e22d8868e1c58c45c44045bef839c55b1d0b1248c50a3bc959c5f", "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec", "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee", NULL }; static const char *const curve448_bad_points[] = { "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffe" "ffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0x00000000000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000000000", "0x00000000000000000000000000000000000000000000000000000000" "00000000000000000000000000000000000000000000000000000001", "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffe" "fffffffffffffffffffffffffffffffffffffffffffffffffffffffe", "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff" "00000000000000000000000000000000000000000000000000000000", NULL }; static const char *const *bad_points_table[] = { curve25519_bad_points, curve448_bad_points, }; static gcry_mpi_t scanval (const char *string) { gpg_err_code_t rc; gcry_mpi_t val; rc = _gcry_mpi_scan (&val, GCRYMPI_FMT_HEX, string, 0, NULL); if (rc) log_fatal ("scanning ECC parameter failed: %s\n", gpg_strerror (rc)); return val; } /* This function initialized a context for elliptic curve based on the field GF(p). P is the prime specifying this field, A is the first coefficient. CTX is expected to be zeroized. */ static void ec_p_init (mpi_ec_t ctx, enum gcry_mpi_ec_models model, enum ecc_dialects dialect, int flags, gcry_mpi_t p, gcry_mpi_t a, gcry_mpi_t b) { int i; static int use_barrett; if (!use_barrett) { if (getenv ("GCRYPT_BARRETT")) use_barrett = 1; else use_barrett = -1; } /* Fixme: Do we want to check some constraints? e.g. a < p */ ctx->model = model; ctx->dialect = dialect; ctx->flags = flags; ctx->nbits = mpi_get_nbits (p); ctx->p = mpi_copy (p); ctx->a = mpi_copy (a); ctx->b = mpi_copy (b); ctx->t.p_barrett = use_barrett > 0? _gcry_mpi_barrett_init (ctx->p, 0):NULL; _gcry_mpi_ec_get_reset (ctx); if (model == MPI_EC_MONTGOMERY) { for (i=0; i< DIM(bad_points_table); i++) { gcry_mpi_t p_candidate = scanval (bad_points_table[i][0]); int match_p = !mpi_cmp (ctx->p, p_candidate); int j; mpi_free (p_candidate); if (!match_p) continue; for (j=0; i< DIM(ctx->t.scratch) && bad_points_table[i][j]; j++) ctx->t.scratch[j] = scanval (bad_points_table[i][j]); } } else { /* Allocate scratch variables. */ for (i=0; i< DIM(ctx->t.scratch); i++) ctx->t.scratch[i] = mpi_alloc_like (ctx->p); } ctx->addm = ec_addm; ctx->subm = ec_subm; ctx->mulm = ec_mulm; ctx->mul2 = ec_mul2; ctx->pow2 = ec_pow2; for (i=0; field_table[i].p; i++) { gcry_mpi_t f_p; gpg_err_code_t rc; rc = _gcry_mpi_scan (&f_p, GCRYMPI_FMT_HEX, field_table[i].p, 0, NULL); if (rc) log_fatal ("scanning ECC parameter failed: %s\n", gpg_strerror (rc)); if (!mpi_cmp (p, f_p)) { ctx->addm = field_table[i].addm; ctx->subm = field_table[i].subm; ctx->mulm = field_table[i].mulm; ctx->mul2 = field_table[i].mul2; ctx->pow2 = field_table[i].pow2; _gcry_mpi_release (f_p); mpi_resize (ctx->a, ctx->p->nlimbs); ctx->a->nlimbs = ctx->p->nlimbs; mpi_resize (ctx->b, ctx->p->nlimbs); ctx->b->nlimbs = ctx->p->nlimbs; for (i=0; i< DIM(ctx->t.scratch) && ctx->t.scratch[i]; i++) ctx->t.scratch[i]->nlimbs = ctx->p->nlimbs; break; } _gcry_mpi_release (f_p); } /* Prepare for fast reduction. */ /* FIXME: need a test for NIST values. However it does not gain us any real advantage, for 384 bits it is actually slower than using mpi_mulm. */ /* ctx->nist_nbits = mpi_get_nbits (ctx->p); */ /* if (ctx->nist_nbits == 192) */ /* { */ /* for (i=0; i < 4; i++) */ /* ctx->s[i] = mpi_new (192); */ /* ctx->c = mpi_new (192*2); */ /* } */ /* else if (ctx->nist_nbits == 384) */ /* { */ /* for (i=0; i < 10; i++) */ /* ctx->s[i] = mpi_new (384); */ /* ctx->c = mpi_new (384*2); */ /* } */ } static void ec_deinit (void *opaque) { mpi_ec_t ctx = opaque; int i; _gcry_mpi_barrett_free (ctx->t.p_barrett); /* Domain parameter. */ mpi_free (ctx->p); mpi_free (ctx->a); mpi_free (ctx->b); _gcry_mpi_point_release (ctx->G); mpi_free (ctx->n); /* The key. */ _gcry_mpi_point_release (ctx->Q); mpi_free (ctx->d); /* Private data of ec.c. */ mpi_free (ctx->t.two_inv_p); for (i=0; i< DIM(ctx->t.scratch); i++) mpi_free (ctx->t.scratch[i]); /* if (ctx->nist_nbits == 192) */ /* { */ /* for (i=0; i < 4; i++) */ /* mpi_free (ctx->s[i]); */ /* mpi_free (ctx->c); */ /* } */ /* else if (ctx->nist_nbits == 384) */ /* { */ /* for (i=0; i < 10; i++) */ /* mpi_free (ctx->s[i]); */ /* mpi_free (ctx->c); */ /* } */ } /* This function returns a new context for elliptic curve based on the field GF(p). P is the prime specifying this field, A is the first coefficient, B is the second coefficient, and MODEL is the model for the curve. This function is only used within Libgcrypt and not part of the public API. This context needs to be released using _gcry_mpi_ec_free. */ mpi_ec_t _gcry_mpi_ec_p_internal_new (enum gcry_mpi_ec_models model, enum ecc_dialects dialect, int flags, gcry_mpi_t p, gcry_mpi_t a, gcry_mpi_t b) { mpi_ec_t ctx; ctx = xcalloc (1, sizeof *ctx); ec_p_init (ctx, model, dialect, flags, p, a, b); return ctx; } /* This is a variant of _gcry_mpi_ec_p_internal_new which returns an public context and does some error checking on the supplied arguments. On success the new context is stored at R_CTX and 0 is returned; on error NULL is stored at R_CTX and an error code is returned. The context needs to be released using gcry_ctx_release. */ gpg_err_code_t _gcry_mpi_ec_p_new (gcry_ctx_t *r_ctx, enum gcry_mpi_ec_models model, enum ecc_dialects dialect, int flags, gcry_mpi_t p, gcry_mpi_t a, gcry_mpi_t b) { gcry_ctx_t ctx; mpi_ec_t ec; *r_ctx = NULL; if (!p || !a) return GPG_ERR_EINVAL; ctx = _gcry_ctx_alloc (CONTEXT_TYPE_EC, sizeof *ec, ec_deinit); if (!ctx) return gpg_err_code_from_syserror (); ec = _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC); ec_p_init (ec, model, dialect, flags, p, a, b); *r_ctx = ctx; return 0; } void _gcry_mpi_ec_free (mpi_ec_t ctx) { if (ctx) { ec_deinit (ctx); xfree (ctx); } } gcry_mpi_t _gcry_mpi_ec_get_mpi (const char *name, gcry_ctx_t ctx, int copy) { mpi_ec_t ec = _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC); return _gcry_ecc_get_mpi (name, ec, copy); } gcry_mpi_point_t _gcry_mpi_ec_get_point (const char *name, gcry_ctx_t ctx, int copy) { mpi_ec_t ec = _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC); (void)copy; /* Not used. */ return _gcry_ecc_get_point (name, ec); } gpg_err_code_t _gcry_mpi_ec_set_mpi (const char *name, gcry_mpi_t newvalue, gcry_ctx_t ctx) { mpi_ec_t ec = _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC); return _gcry_ecc_set_mpi (name, newvalue, ec); } gpg_err_code_t _gcry_mpi_ec_set_point (const char *name, gcry_mpi_point_t newvalue, gcry_ctx_t ctx) { mpi_ec_t ec = _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC); return _gcry_ecc_set_point (name, newvalue, ec); } /* Given an encoded point in the MPI VALUE and a context EC, decode * the point according to the context and store it in RESULT. On * error an error code is return but RESULT might have been changed. * If no context is given the function tries to decode VALUE by * assuming a 0x04 prefixed uncompressed encoding. */ gpg_err_code_t _gcry_mpi_ec_decode_point (mpi_point_t result, gcry_mpi_t value, mpi_ec_t ec) { gpg_err_code_t rc; if (ec && (ec->dialect == ECC_DIALECT_ED25519 || (ec->model == MPI_EC_EDWARDS && ec->dialect == ECC_DIALECT_SAFECURVE))) rc = _gcry_ecc_eddsa_decodepoint (value, ec, result, NULL, NULL); else if (ec && ec->model == MPI_EC_MONTGOMERY) rc = _gcry_ecc_mont_decodepoint (value, ec, result); else rc = _gcry_ecc_sec_decodepoint (value, ec, result); return rc; } /* Compute the affine coordinates from the projective coordinates in POINT. Set them into X and Y. If one coordinate is not required, X or Y may be passed as NULL. CTX is the usual context. Returns: 0 on success or !0 if POINT is at infinity. */ int _gcry_mpi_ec_get_affine (gcry_mpi_t x, gcry_mpi_t y, mpi_point_t point, mpi_ec_t ctx) { if (!mpi_cmp_ui (point->z, 0)) return -1; switch (ctx->model) { case MPI_EC_WEIERSTRASS: /* Using Jacobian coordinates. */ { gcry_mpi_t z1, z2, z3; z1 = mpi_new (0); z2 = mpi_new (0); ec_invm (z1, point->z, ctx); /* z1 = z^(-1) mod p */ ec_mulm (z2, z1, z1, ctx); /* z2 = z^(-2) mod p */ if (x) ec_mulm (x, point->x, z2, ctx); if (y) { z3 = mpi_new (0); ec_mulm (z3, z2, z1, ctx); /* z3 = z^(-3) mod p */ ec_mulm (y, point->y, z3, ctx); mpi_free (z3); } mpi_free (z2); mpi_free (z1); } return 0; case MPI_EC_MONTGOMERY: { if (x) mpi_set (x, point->x); if (y) { log_fatal ("%s: Getting Y-coordinate on %s is not supported\n", "_gcry_mpi_ec_get_affine", "Montgomery"); return -1; } } return 0; case MPI_EC_EDWARDS: { gcry_mpi_t z; z = mpi_new (0); ec_invm (z, point->z, ctx); mpi_resize (z, ctx->p->nlimbs); z->nlimbs = ctx->p->nlimbs; if (x) { mpi_resize (x, ctx->p->nlimbs); x->nlimbs = ctx->p->nlimbs; ctx->mulm (x, point->x, z, ctx); } if (y) { mpi_resize (y, ctx->p->nlimbs); y->nlimbs = ctx->p->nlimbs; ctx->mulm (y, point->y, z, ctx); } _gcry_mpi_release (z); } return 0; default: return -1; } } /* RESULT = 2 * POINT (Weierstrass version). */ static void dup_point_weierstrass (mpi_point_t result, mpi_point_t point, mpi_ec_t ctx) { #define x3 (result->x) #define y3 (result->y) #define z3 (result->z) #define t1 (ctx->t.scratch[0]) #define t2 (ctx->t.scratch[1]) #define t3 (ctx->t.scratch[2]) #define l1 (ctx->t.scratch[3]) #define l2 (ctx->t.scratch[4]) #define l3 (ctx->t.scratch[5]) if (!mpi_cmp_ui (point->y, 0) || !mpi_cmp_ui (point->z, 0)) { /* P_y == 0 || P_z == 0 => [1:1:0] */ mpi_set_ui (x3, 1); mpi_set_ui (y3, 1); mpi_set_ui (z3, 0); } else { if (ec_get_a_is_pminus3 (ctx)) /* Use the faster case. */ { /* L1 = 3(X - Z^2)(X + Z^2) */ /* T1: used for Z^2. */ /* T2: used for the right term. */ ec_pow2 (t1, point->z, ctx); ec_subm (l1, point->x, t1, ctx); ec_mulm (l1, l1, mpi_const (MPI_C_THREE), ctx); ec_addm (t2, point->x, t1, ctx); ec_mulm (l1, l1, t2, ctx); } else /* Standard case. */ { /* L1 = 3X^2 + aZ^4 */ /* T1: used for aZ^4. */ ec_pow2 (l1, point->x, ctx); ec_mulm (l1, l1, mpi_const (MPI_C_THREE), ctx); ec_powm (t1, point->z, mpi_const (MPI_C_FOUR), ctx); ec_mulm (t1, t1, ctx->a, ctx); ec_addm (l1, l1, t1, ctx); } /* Z3 = 2YZ */ ec_mulm (z3, point->y, point->z, ctx); ec_mul2 (z3, z3, ctx); /* L2 = 4XY^2 */ /* T2: used for Y2; required later. */ ec_pow2 (t2, point->y, ctx); ec_mulm (l2, t2, point->x, ctx); ec_mulm (l2, l2, mpi_const (MPI_C_FOUR), ctx); /* X3 = L1^2 - 2L2 */ /* T1: used for L2^2. */ ec_pow2 (x3, l1, ctx); ec_mul2 (t1, l2, ctx); ec_subm (x3, x3, t1, ctx); /* L3 = 8Y^4 */ /* T2: taken from above. */ ec_pow2 (t2, t2, ctx); ec_mulm (l3, t2, mpi_const (MPI_C_EIGHT), ctx); /* Y3 = L1(L2 - X3) - L3 */ ec_subm (y3, l2, x3, ctx); ec_mulm (y3, y3, l1, ctx); ec_subm (y3, y3, l3, ctx); } #undef x3 #undef y3 #undef z3 #undef t1 #undef t2 #undef t3 #undef l1 #undef l2 #undef l3 } /* RESULT = 2 * POINT (Montgomery version). */ static void dup_point_montgomery (mpi_point_t result, mpi_point_t point, mpi_ec_t ctx) { (void)result; (void)point; (void)ctx; log_fatal ("%s: %s not yet supported\n", "_gcry_mpi_ec_dup_point", "Montgomery"); } /* RESULT = 2 * POINT (Twisted Edwards version). */ static void dup_point_edwards (mpi_point_t result, mpi_point_t point, mpi_ec_t ctx) { #define X1 (point->x) #define Y1 (point->y) #define Z1 (point->z) #define X3 (result->x) #define Y3 (result->y) #define Z3 (result->z) #define B (ctx->t.scratch[0]) #define C (ctx->t.scratch[1]) #define D (ctx->t.scratch[2]) #define E (ctx->t.scratch[3]) #define F (ctx->t.scratch[4]) #define H (ctx->t.scratch[5]) #define J (ctx->t.scratch[6]) /* Compute: (X_3 : Y_3 : Z_3) = 2( X_1 : Y_1 : Z_1 ) */ /* B = (X_1 + Y_1)^2 */ ctx->addm (B, X1, Y1, ctx); ctx->pow2 (B, B, ctx); /* C = X_1^2 */ /* D = Y_1^2 */ ctx->pow2 (C, X1, ctx); ctx->pow2 (D, Y1, ctx); /* E = aC */ if (ctx->dialect == ECC_DIALECT_ED25519) ctx->subm (E, ctx->p, C, ctx); else ctx->mulm (E, ctx->a, C, ctx); /* F = E + D */ ctx->addm (F, E, D, ctx); /* H = Z_1^2 */ ctx->pow2 (H, Z1, ctx); /* J = F - 2H */ ctx->mul2 (J, H, ctx); ctx->subm (J, F, J, ctx); /* X_3 = (B - C - D) · J */ ctx->subm (X3, B, C, ctx); ctx->subm (X3, X3, D, ctx); ctx->mulm (X3, X3, J, ctx); /* Y_3 = F · (E - D) */ ctx->subm (Y3, E, D, ctx); ctx->mulm (Y3, Y3, F, ctx); /* Z_3 = F · J */ ctx->mulm (Z3, F, J, ctx); #undef X1 #undef Y1 #undef Z1 #undef X3 #undef Y3 #undef Z3 #undef B #undef C #undef D #undef E #undef F #undef H #undef J } /* RESULT = 2 * POINT */ void _gcry_mpi_ec_dup_point (mpi_point_t result, mpi_point_t point, mpi_ec_t ctx) { switch (ctx->model) { case MPI_EC_WEIERSTRASS: dup_point_weierstrass (result, point, ctx); break; case MPI_EC_MONTGOMERY: dup_point_montgomery (result, point, ctx); break; case MPI_EC_EDWARDS: dup_point_edwards (result, point, ctx); break; } } /* RESULT = P1 + P2 (Weierstrass version).*/ static void add_points_weierstrass (mpi_point_t result, mpi_point_t p1, mpi_point_t p2, mpi_ec_t ctx) { #define x1 (p1->x ) #define y1 (p1->y ) #define z1 (p1->z ) #define x2 (p2->x ) #define y2 (p2->y ) #define z2 (p2->z ) #define x3 (result->x) #define y3 (result->y) #define z3 (result->z) #define l1 (ctx->t.scratch[0]) #define l2 (ctx->t.scratch[1]) #define l3 (ctx->t.scratch[2]) #define l4 (ctx->t.scratch[3]) #define l5 (ctx->t.scratch[4]) #define l6 (ctx->t.scratch[5]) #define l7 (ctx->t.scratch[6]) #define l8 (ctx->t.scratch[7]) #define l9 (ctx->t.scratch[8]) #define t1 (ctx->t.scratch[9]) #define t2 (ctx->t.scratch[10]) if ( (!mpi_cmp (x1, x2)) && (!mpi_cmp (y1, y2)) && (!mpi_cmp (z1, z2)) ) { /* Same point; need to call the duplicate function. */ _gcry_mpi_ec_dup_point (result, p1, ctx); } else if (!mpi_cmp_ui (z1, 0)) { /* P1 is at infinity. */ mpi_set (x3, p2->x); mpi_set (y3, p2->y); mpi_set (z3, p2->z); } else if (!mpi_cmp_ui (z2, 0)) { /* P2 is at infinity. */ mpi_set (x3, p1->x); mpi_set (y3, p1->y); mpi_set (z3, p1->z); } else { int z1_is_one = !mpi_cmp_ui (z1, 1); int z2_is_one = !mpi_cmp_ui (z2, 1); /* l1 = x1 z2^2 */ /* l2 = x2 z1^2 */ if (z2_is_one) mpi_set (l1, x1); else { ec_pow2 (l1, z2, ctx); ec_mulm (l1, l1, x1, ctx); } if (z1_is_one) mpi_set (l2, x2); else { ec_pow2 (l2, z1, ctx); ec_mulm (l2, l2, x2, ctx); } /* l3 = l1 - l2 */ ec_subm (l3, l1, l2, ctx); /* l4 = y1 z2^3 */ ec_powm (l4, z2, mpi_const (MPI_C_THREE), ctx); ec_mulm (l4, l4, y1, ctx); /* l5 = y2 z1^3 */ ec_powm (l5, z1, mpi_const (MPI_C_THREE), ctx); ec_mulm (l5, l5, y2, ctx); /* l6 = l4 - l5 */ ec_subm (l6, l4, l5, ctx); if (!mpi_cmp_ui (l3, 0)) { if (!mpi_cmp_ui (l6, 0)) { /* P1 and P2 are the same - use duplicate function. */ _gcry_mpi_ec_dup_point (result, p1, ctx); } else { /* P1 is the inverse of P2. */ mpi_set_ui (x3, 1); mpi_set_ui (y3, 1); mpi_set_ui (z3, 0); } } else { /* l7 = l1 + l2 */ ec_addm (l7, l1, l2, ctx); /* l8 = l4 + l5 */ ec_addm (l8, l4, l5, ctx); /* z3 = z1 z2 l3 */ ec_mulm (z3, z1, z2, ctx); ec_mulm (z3, z3, l3, ctx); /* x3 = l6^2 - l7 l3^2 */ ec_pow2 (t1, l6, ctx); ec_pow2 (t2, l3, ctx); ec_mulm (t2, t2, l7, ctx); ec_subm (x3, t1, t2, ctx); /* l9 = l7 l3^2 - 2 x3 */ ec_mul2 (t1, x3, ctx); ec_subm (l9, t2, t1, ctx); /* y3 = (l9 l6 - l8 l3^3)/2 */ ec_mulm (l9, l9, l6, ctx); ec_powm (t1, l3, mpi_const (MPI_C_THREE), ctx); /* fixme: Use saved value*/ ec_mulm (t1, t1, l8, ctx); ec_subm (y3, l9, t1, ctx); ec_mulm (y3, y3, ec_get_two_inv_p (ctx), ctx); } } #undef x1 #undef y1 #undef z1 #undef x2 #undef y2 #undef z2 #undef x3 #undef y3 #undef z3 #undef l1 #undef l2 #undef l3 #undef l4 #undef l5 #undef l6 #undef l7 #undef l8 #undef l9 #undef t1 #undef t2 } /* RESULT = P1 + P2 (Montgomery version).*/ static void add_points_montgomery (mpi_point_t result, mpi_point_t p1, mpi_point_t p2, mpi_ec_t ctx) { (void)result; (void)p1; (void)p2; (void)ctx; log_fatal ("%s: %s not yet supported\n", "_gcry_mpi_ec_add_points", "Montgomery"); } /* RESULT = P1 + P2 (Twisted Edwards version).*/ static void add_points_edwards (mpi_point_t result, mpi_point_t p1, mpi_point_t p2, mpi_ec_t ctx) { #define X1 (p1->x) #define Y1 (p1->y) #define Z1 (p1->z) #define X2 (p2->x) #define Y2 (p2->y) #define Z2 (p2->z) #define X3 (result->x) #define Y3 (result->y) #define Z3 (result->z) #define A (ctx->t.scratch[0]) #define B (ctx->t.scratch[1]) #define C (ctx->t.scratch[2]) #define D (ctx->t.scratch[3]) #define E (ctx->t.scratch[4]) #define F (ctx->t.scratch[5]) #define G (ctx->t.scratch[6]) #define tmp (ctx->t.scratch[7]) mpi_point_resize (result, ctx); /* Compute: (X_3 : Y_3 : Z_3) = (X_1 : Y_1 : Z_1) + (X_2 : Y_2 : Z_3) */ /* A = Z1 · Z2 */ ctx->mulm (A, Z1, Z2, ctx); /* B = A^2 */ ctx->pow2 (B, A, ctx); /* C = X1 · X2 */ ctx->mulm (C, X1, X2, ctx); /* D = Y1 · Y2 */ ctx->mulm (D, Y1, Y2, ctx); /* E = d · C · D */ ctx->mulm (E, ctx->b, C, ctx); ctx->mulm (E, E, D, ctx); /* F = B - E */ ctx->subm (F, B, E, ctx); /* G = B + E */ ctx->addm (G, B, E, ctx); /* X_3 = A · F · ((X_1 + Y_1) · (X_2 + Y_2) - C - D) */ ctx->addm (tmp, X1, Y1, ctx); ctx->addm (X3, X2, Y2, ctx); ctx->mulm (X3, X3, tmp, ctx); ctx->subm (X3, X3, C, ctx); ctx->subm (X3, X3, D, ctx); ctx->mulm (X3, X3, F, ctx); ctx->mulm (X3, X3, A, ctx); /* Y_3 = A · G · (D - aC) */ if (ctx->dialect == ECC_DIALECT_ED25519) { ctx->addm (Y3, D, C, ctx); } else { ctx->mulm (Y3, ctx->a, C, ctx); ctx->subm (Y3, D, Y3, ctx); } ctx->mulm (Y3, Y3, G, ctx); ctx->mulm (Y3, Y3, A, ctx); /* Z_3 = F · G */ ctx->mulm (Z3, F, G, ctx); #undef X1 #undef Y1 #undef Z1 #undef X2 #undef Y2 #undef Z2 #undef X3 #undef Y3 #undef Z3 #undef A #undef B #undef C #undef D #undef E #undef F #undef G #undef tmp } /* Compute a step of Montgomery Ladder (only use X and Z in the point). Inputs: P1, P2, and x-coordinate of DIF = P1 - P1. Outputs: PRD = 2 * P1 and SUM = P1 + P2. */ static void montgomery_ladder (mpi_point_t prd, mpi_point_t sum, mpi_point_t p1, mpi_point_t p2, gcry_mpi_t dif_x, mpi_ec_t ctx) { ctx->addm (sum->x, p2->x, p2->z, ctx); ctx->subm (p2->z, p2->x, p2->z, ctx); ctx->addm (prd->x, p1->x, p1->z, ctx); ctx->subm (p1->z, p1->x, p1->z, ctx); ctx->mulm (p2->x, p1->z, sum->x, ctx); ctx->mulm (p2->z, prd->x, p2->z, ctx); ctx->pow2 (p1->x, prd->x, ctx); ctx->pow2 (p1->z, p1->z, ctx); ctx->addm (sum->x, p2->x, p2->z, ctx); ctx->subm (p2->z, p2->x, p2->z, ctx); ctx->mulm (prd->x, p1->x, p1->z, ctx); ctx->subm (p1->z, p1->x, p1->z, ctx); ctx->pow2 (sum->x, sum->x, ctx); ctx->pow2 (sum->z, p2->z, ctx); ctx->mulm (prd->z, p1->z, ctx->a, ctx); /* CTX->A: (a-2)/4 */ ctx->mulm (sum->z, sum->z, dif_x, ctx); ctx->addm (prd->z, p1->x, prd->z, ctx); ctx->mulm (prd->z, prd->z, p1->z, ctx); } /* RESULT = P1 + P2 */ void _gcry_mpi_ec_add_points (mpi_point_t result, mpi_point_t p1, mpi_point_t p2, mpi_ec_t ctx) { switch (ctx->model) { case MPI_EC_WEIERSTRASS: add_points_weierstrass (result, p1, p2, ctx); break; case MPI_EC_MONTGOMERY: add_points_montgomery (result, p1, p2, ctx); break; case MPI_EC_EDWARDS: add_points_edwards (result, p1, p2, ctx); break; } } /* RESULT = P1 - P2 (Weierstrass version).*/ static void sub_points_weierstrass (mpi_point_t result, mpi_point_t p1, mpi_point_t p2, mpi_ec_t ctx) { (void)result; (void)p1; (void)p2; (void)ctx; log_fatal ("%s: %s not yet supported\n", "_gcry_mpi_ec_sub_points", "Weierstrass"); } /* RESULT = P1 - P2 (Montgomery version).*/ static void sub_points_montgomery (mpi_point_t result, mpi_point_t p1, mpi_point_t p2, mpi_ec_t ctx) { (void)result; (void)p1; (void)p2; (void)ctx; log_fatal ("%s: %s not yet supported\n", "_gcry_mpi_ec_sub_points", "Montgomery"); } /* RESULT = P1 - P2 (Twisted Edwards version).*/ static void sub_points_edwards (mpi_point_t result, mpi_point_t p1, mpi_point_t p2, mpi_ec_t ctx) { mpi_point_t p2i = _gcry_mpi_point_new (0); point_set (p2i, p2); ctx->subm (p2i->x, ctx->p, p2i->x, ctx); add_points_edwards (result, p1, p2i, ctx); _gcry_mpi_point_release (p2i); } /* RESULT = P1 - P2 */ void _gcry_mpi_ec_sub_points (mpi_point_t result, mpi_point_t p1, mpi_point_t p2, mpi_ec_t ctx) { switch (ctx->model) { case MPI_EC_WEIERSTRASS: sub_points_weierstrass (result, p1, p2, ctx); break; case MPI_EC_MONTGOMERY: sub_points_montgomery (result, p1, p2, ctx); break; case MPI_EC_EDWARDS: sub_points_edwards (result, p1, p2, ctx); break; } } -/* Scalar point multiplication - the main function for ECC. If takes +/* Scalar point multiplication - the main function for ECC. It takes an integer SCALAR and a POINT as well as the usual context CTX. RESULT will be set to the resulting point. */ void _gcry_mpi_ec_mul_point (mpi_point_t result, gcry_mpi_t scalar, mpi_point_t point, mpi_ec_t ctx) { gcry_mpi_t x1, y1, z1, k, h, yy; unsigned int i, loops; mpi_point_struct p1, p2, p1inv; + /* First try HW accelerated scalar multiplications. Error + is returned if acceleration is not supported or if HW + does not support acceleration of given input. */ + if (mpi_ec_hw_mul_point (result, scalar, point, ctx) >= 0) + { + return; + } + if (ctx->model == MPI_EC_EDWARDS || (ctx->model == MPI_EC_WEIERSTRASS && mpi_is_secure (scalar))) { /* Simple left to right binary method. Algorithm 3.27 from * {author={Hankerson, Darrel and Menezes, Alfred J. and Vanstone, Scott}, * title = {Guide to Elliptic Curve Cryptography}, * year = {2003}, isbn = {038795273X}, * url = {http://www.cacr.math.uwaterloo.ca/ecc/}, * publisher = {Springer-Verlag New York, Inc.}} */ unsigned int nbits; int j; if (mpi_cmp (scalar, ctx->p) >= 0) nbits = mpi_get_nbits (scalar); else nbits = mpi_get_nbits (ctx->p); if (ctx->model == MPI_EC_WEIERSTRASS) { mpi_set_ui (result->x, 1); mpi_set_ui (result->y, 1); mpi_set_ui (result->z, 0); } else { mpi_set_ui (result->x, 0); mpi_set_ui (result->y, 1); mpi_set_ui (result->z, 1); mpi_point_resize (point, ctx); } if (mpi_is_secure (scalar)) { /* If SCALAR is in secure memory we assume that it is the secret key we use constant time operation. */ mpi_point_struct tmppnt; point_init (&tmppnt); mpi_point_resize (result, ctx); mpi_point_resize (&tmppnt, ctx); for (j=nbits-1; j >= 0; j--) { _gcry_mpi_ec_dup_point (result, result, ctx); _gcry_mpi_ec_add_points (&tmppnt, result, point, ctx); point_swap_cond (result, &tmppnt, mpi_test_bit (scalar, j), ctx); } point_free (&tmppnt); } else { if (ctx->model == MPI_EC_EDWARDS) { mpi_point_resize (result, ctx); mpi_point_resize (point, ctx); } for (j=nbits-1; j >= 0; j--) { _gcry_mpi_ec_dup_point (result, result, ctx); if (mpi_test_bit (scalar, j)) _gcry_mpi_ec_add_points (result, result, point, ctx); } } return; } else if (ctx->model == MPI_EC_MONTGOMERY) { unsigned int nbits; int j; mpi_point_struct p1_, p2_; mpi_point_t q1, q2, prd, sum; unsigned long sw; mpi_size_t rsize; int scalar_copied = 0; /* Compute scalar point multiplication with Montgomery Ladder. Note that we don't use Y-coordinate in the points at all. RESULT->Y will be filled by zero. */ nbits = mpi_get_nbits (scalar); point_init (&p1); point_init (&p2); point_init (&p1_); point_init (&p2_); mpi_set_ui (p1.x, 1); mpi_free (p2.x); p2.x = mpi_copy (point->x); mpi_set_ui (p2.z, 1); if (mpi_is_opaque (scalar)) { const unsigned int pbits = ctx->nbits; gcry_mpi_t a; unsigned int n; unsigned char *raw; scalar_copied = 1; raw = _gcry_mpi_get_opaque_copy (scalar, &n); if ((n+7)/8 != (pbits+7)/8) log_fatal ("scalar size (%d) != prime size (%d)\n", (n+7)/8, (pbits+7)/8); reverse_buffer (raw, (n+7)/8); if ((pbits % 8)) raw[0] &= (1 << (pbits % 8)) - 1; raw[0] |= (1 << ((pbits + 7) % 8)); raw[(pbits+7)/8 - 1] &= (256 - ctx->h); a = mpi_is_secure (scalar) ? mpi_snew (pbits): mpi_new (pbits); _gcry_mpi_set_buffer (a, raw, (n+7)/8, 0); xfree (raw); scalar = a; } mpi_point_resize (&p1, ctx); mpi_point_resize (&p2, ctx); mpi_point_resize (&p1_, ctx); mpi_point_resize (&p2_, ctx); mpi_resize (point->x, ctx->p->nlimbs); point->x->nlimbs = ctx->p->nlimbs; q1 = &p1; q2 = &p2; prd = &p1_; sum = &p2_; for (j=nbits-1; j >= 0; j--) { mpi_point_t t; sw = mpi_test_bit (scalar, j); point_swap_cond (q1, q2, sw, ctx); montgomery_ladder (prd, sum, q1, q2, point->x, ctx); point_swap_cond (prd, sum, sw, ctx); t = q1; q1 = prd; prd = t; t = q2; q2 = sum; sum = t; } mpi_clear (result->y); sw = (nbits & 1); point_swap_cond (&p1, &p1_, sw, ctx); rsize = p1.z->nlimbs; MPN_NORMALIZE (p1.z->d, rsize); if (rsize == 0) { mpi_set_ui (result->x, 1); mpi_set_ui (result->z, 0); } else { z1 = mpi_new (0); ec_invm (z1, p1.z, ctx); ec_mulm (result->x, p1.x, z1, ctx); mpi_set_ui (result->z, 1); mpi_free (z1); } point_free (&p1); point_free (&p2); point_free (&p1_); point_free (&p2_); if (scalar_copied) _gcry_mpi_release (scalar); return; } x1 = mpi_alloc_like (ctx->p); y1 = mpi_alloc_like (ctx->p); h = mpi_alloc_like (ctx->p); k = mpi_copy (scalar); yy = mpi_copy (point->y); if ( mpi_has_sign (k) ) { k->sign = 0; ec_invm (yy, yy, ctx); } if (!mpi_cmp_ui (point->z, 1)) { mpi_set (x1, point->x); mpi_set (y1, yy); } else { gcry_mpi_t z2, z3; z2 = mpi_alloc_like (ctx->p); z3 = mpi_alloc_like (ctx->p); ec_mulm (z2, point->z, point->z, ctx); ec_mulm (z3, point->z, z2, ctx); ec_invm (z2, z2, ctx); ec_mulm (x1, point->x, z2, ctx); ec_invm (z3, z3, ctx); ec_mulm (y1, yy, z3, ctx); mpi_free (z2); mpi_free (z3); } z1 = mpi_copy (mpi_const (MPI_C_ONE)); mpi_mul (h, k, mpi_const (MPI_C_THREE)); /* h = 3k */ loops = mpi_get_nbits (h); if (loops < 2) { /* If SCALAR is zero, the above mpi_mul sets H to zero and thus LOOPs will be zero. To avoid an underflow of I in the main loop we set LOOP to 2 and the result to (0,0,0). */ loops = 2; mpi_clear (result->x); mpi_clear (result->y); mpi_clear (result->z); } else { mpi_set (result->x, point->x); mpi_set (result->y, yy); mpi_set (result->z, point->z); } mpi_free (yy); yy = NULL; p1.x = x1; x1 = NULL; p1.y = y1; y1 = NULL; p1.z = z1; z1 = NULL; point_init (&p2); point_init (&p1inv); /* Invert point: y = p - y mod p */ point_set (&p1inv, &p1); ec_subm (p1inv.y, ctx->p, p1inv.y, ctx); for (i=loops-2; i > 0; i--) { _gcry_mpi_ec_dup_point (result, result, ctx); if (mpi_test_bit (h, i) == 1 && mpi_test_bit (k, i) == 0) { point_set (&p2, result); _gcry_mpi_ec_add_points (result, &p2, &p1, ctx); } if (mpi_test_bit (h, i) == 0 && mpi_test_bit (k, i) == 1) { point_set (&p2, result); _gcry_mpi_ec_add_points (result, &p2, &p1inv, ctx); } } point_free (&p1); point_free (&p2); point_free (&p1inv); mpi_free (h); mpi_free (k); } /* Return true if POINT is on the curve described by CTX. */ int _gcry_mpi_ec_curve_point (gcry_mpi_point_t point, mpi_ec_t ctx) { int res = 0; gcry_mpi_t x, y, w; x = mpi_new (0); y = mpi_new (0); w = mpi_new (0); /* Check that the point is in range. This needs to be done here and * not after conversion to affine coordinates. */ if (mpi_cmpabs (point->x, ctx->p) >= 0) goto leave; if (mpi_cmpabs (point->y, ctx->p) >= 0) goto leave; if (mpi_cmpabs (point->z, ctx->p) >= 0) goto leave; switch (ctx->model) { case MPI_EC_WEIERSTRASS: { gcry_mpi_t xxx; if (_gcry_mpi_ec_get_affine (x, y, point, ctx)) goto leave; xxx = mpi_new (0); /* y^2 == x^3 + a·x + b */ ec_pow2 (y, y, ctx); ec_pow3 (xxx, x, ctx); ec_mulm (w, ctx->a, x, ctx); ec_addm (w, w, ctx->b, ctx); ec_addm (w, w, xxx, ctx); if (!mpi_cmp (y, w)) res = 1; _gcry_mpi_release (xxx); } break; case MPI_EC_MONTGOMERY: { #define xx y /* With Montgomery curve, only X-coordinate is valid. */ if (_gcry_mpi_ec_get_affine (x, NULL, point, ctx)) goto leave; /* The equation is: b * y^2 == x^3 + a · x^2 + x */ /* We check if right hand is quadratic residue or not by Euler's criterion. */ /* CTX->A has (a-2)/4 and CTX->B has b^-1 */ ec_mulm (w, ctx->a, mpi_const (MPI_C_FOUR), ctx); ec_addm (w, w, mpi_const (MPI_C_TWO), ctx); ec_mulm (w, w, x, ctx); ec_pow2 (xx, x, ctx); ec_addm (w, w, xx, ctx); ec_addm (w, w, mpi_const (MPI_C_ONE), ctx); ec_mulm (w, w, x, ctx); ec_mulm (w, w, ctx->b, ctx); #undef xx /* Compute Euler's criterion: w^(p-1)/2 */ #define p_minus1 y ec_subm (p_minus1, ctx->p, mpi_const (MPI_C_ONE), ctx); mpi_rshift (p_minus1, p_minus1, 1); ec_powm (w, w, p_minus1, ctx); res = !mpi_cmp_ui (w, 1); #undef p_minus1 } break; case MPI_EC_EDWARDS: { if (_gcry_mpi_ec_get_affine (x, y, point, ctx)) goto leave; mpi_resize (w, ctx->p->nlimbs); w->nlimbs = ctx->p->nlimbs; /* a · x^2 + y^2 - 1 - b · x^2 · y^2 == 0 */ ctx->pow2 (x, x, ctx); ctx->pow2 (y, y, ctx); if (ctx->dialect == ECC_DIALECT_ED25519) ctx->subm (w, ctx->p, x, ctx); else ctx->mulm (w, ctx->a, x, ctx); ctx->addm (w, w, y, ctx); ctx->mulm (x, x, y, ctx); ctx->mulm (x, x, ctx->b, ctx); ctx->subm (w, w, x, ctx); if (!mpi_cmp_ui (w, 1)) res = 1; } break; } leave: _gcry_mpi_release (w); _gcry_mpi_release (x); _gcry_mpi_release (y); return res; } int _gcry_mpi_ec_bad_point (gcry_mpi_point_t point, mpi_ec_t ctx) { int i; gcry_mpi_t x_bad; for (i = 0; (x_bad = ctx->t.scratch[i]); i++) if (!mpi_cmp (point->x, x_bad)) return 1; return 0; } diff --git a/src/g10lib.h b/src/g10lib.h index b0b73852..400cb13e 100644 --- a/src/g10lib.h +++ b/src/g10lib.h @@ -1,504 +1,505 @@ /* g10lib.h - Internal definitions for libgcrypt * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005 * 2007, 2011 Free Software Foundation, Inc. * * This file is part of Libgcrypt. * * Libgcrypt is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser general Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * Libgcrypt is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . */ /* This header is to be used inside of libgcrypt in place of gcrypt.h. This way we can better distinguish between internal and external usage of gcrypt.h. */ #ifndef G10LIB_H #define G10LIB_H 1 #ifdef _GCRYPT_H #error gcrypt.h already included #endif #ifndef _GCRYPT_IN_LIBGCRYPT #error something is wrong with config.h #endif #include #include #include "visibility.h" #include "types.h" /* Attribute handling macros. */ #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 ) #define JNLIB_GCC_M_FUNCTION 1 #define JNLIB_GCC_A_NR __attribute__ ((noreturn)) #define JNLIB_GCC_A_PRINTF( f, a ) __attribute__ ((format (printf,f,a))) #define JNLIB_GCC_A_NR_PRINTF( f, a ) \ __attribute__ ((noreturn, format (printf,f,a))) #define GCC_ATTR_NORETURN __attribute__ ((__noreturn__)) #else #define JNLIB_GCC_A_NR #define JNLIB_GCC_A_PRINTF( f, a ) #define JNLIB_GCC_A_NR_PRINTF( f, a ) #define GCC_ATTR_NORETURN #endif #if __GNUC__ >= 3 /* According to glibc this attribute is available since 2.8 however we better play safe and use it only with gcc 3 or newer. */ #define GCC_ATTR_FORMAT_ARG(a) __attribute__ ((format_arg (a))) #else #define GCC_ATTR_FORMAT_ARG(a) #endif /* I am not sure since when the unused attribute is really supported. In any case it it only needed for gcc versions which print a warning. Thus let us require gcc >= 3.5. */ #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 5 ) #define GCC_ATTR_UNUSED __attribute__ ((unused)) #else #define GCC_ATTR_UNUSED #endif #if __GNUC__ > 3 #define NOINLINE_FUNC __attribute__((noinline)) #else #define NOINLINE_FUNC #endif #if __GNUC__ >= 3 #define LIKELY(expr) __builtin_expect( !!(expr), 1 ) #define UNLIKELY(expr) __builtin_expect( !!(expr), 0 ) #define CONSTANT_P(expr) __builtin_constant_p( expr ) #else #define LIKELY(expr) (!!(expr)) #define UNLIKELY(expr) (!!(expr)) #define CONSTANT_P(expr) (0) #endif /* Gettext macros. */ #define _(a) _gcry_gettext(a) #define N_(a) (a) /* Some handy macros */ #ifndef STR #define STR(v) #v #endif #define STR2(v) STR(v) #define DIM(v) (sizeof(v)/sizeof((v)[0])) #define DIMof(type,member) DIM(((type *)0)->member) #define my_isascii(c) (!((c) & 0x80)) /*-- src/global.c -*/ extern int _gcry_global_any_init_done; int _gcry_global_is_operational (void); gcry_err_code_t _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr); void _gcry_check_heap (const void *a); void _gcry_pre_syscall (void); void _gcry_post_syscall (void); int _gcry_get_debug_flag (unsigned int mask); char *_gcry_get_config (int mode, const char *what); /* Malloc functions and common wrapper macros. */ void *_gcry_malloc (size_t n) _GCRY_GCC_ATTR_MALLOC; void *_gcry_calloc (size_t n, size_t m) _GCRY_GCC_ATTR_MALLOC; void *_gcry_malloc_secure (size_t n) _GCRY_GCC_ATTR_MALLOC; void *_gcry_calloc_secure (size_t n, size_t m) _GCRY_GCC_ATTR_MALLOC; void *_gcry_realloc (void *a, size_t n); char *_gcry_strdup (const char *string) _GCRY_GCC_ATTR_MALLOC; void *_gcry_xmalloc (size_t n) _GCRY_GCC_ATTR_MALLOC; void *_gcry_xcalloc (size_t n, size_t m) _GCRY_GCC_ATTR_MALLOC; void *_gcry_xmalloc_secure (size_t n) _GCRY_GCC_ATTR_MALLOC; void *_gcry_xcalloc_secure (size_t n, size_t m) _GCRY_GCC_ATTR_MALLOC; void *_gcry_xrealloc (void *a, size_t n); char *_gcry_xstrdup (const char * a) _GCRY_GCC_ATTR_MALLOC; void _gcry_free (void *a); int _gcry_is_secure (const void *a) _GCRY_GCC_ATTR_PURE; #define xtrymalloc(a) _gcry_malloc ((a)) #define xtrycalloc(a,b) _gcry_calloc ((a),(b)) #define xtrymalloc_secure(a) _gcry_malloc_secure ((a)) #define xtrycalloc_secure(a,b) _gcry_calloc_secure ((a),(b)) #define xtryrealloc(a,b) _gcry_realloc ((a),(b)) #define xtrystrdup(a) _gcry_strdup ((a)) #define xmalloc(a) _gcry_xmalloc ((a)) #define xcalloc(a,b) _gcry_xcalloc ((a),(b)) #define xmalloc_secure(a) _gcry_xmalloc_secure ((a)) #define xcalloc_secure(a,b) _gcry_xcalloc_secure ((a),(b)) #define xrealloc(a,b) _gcry_xrealloc ((a),(b)) #define xstrdup(a) _gcry_xstrdup ((a)) #define xfree(a) _gcry_free ((a)) /*-- src/misc.c --*/ #if defined(JNLIB_GCC_M_FUNCTION) || __STDC_VERSION__ >= 199901L void _gcry_bug (const char *file, int line, const char *func) GCC_ATTR_NORETURN; void _gcry_assert_failed (const char *expr, const char *file, int line, const char *func) GCC_ATTR_NORETURN; #else void _gcry_bug (const char *file, int line); void _gcry_assert_failed (const char *expr, const char *file, int line); #endif void _gcry_divide_by_zero (void) JNLIB_GCC_A_NR; const char *_gcry_gettext (const char *key) GCC_ATTR_FORMAT_ARG(1); void _gcry_fatal_error(int rc, const char *text ) JNLIB_GCC_A_NR; void _gcry_logv (int level, const char *fmt, va_list arg_ptr) JNLIB_GCC_A_PRINTF(2,0); void _gcry_log( int level, const char *fmt, ... ) JNLIB_GCC_A_PRINTF(2,3); void _gcry_log_bug( const char *fmt, ... ) JNLIB_GCC_A_NR_PRINTF(1,2); void _gcry_log_fatal( const char *fmt, ... ) JNLIB_GCC_A_NR_PRINTF(1,2); void _gcry_log_error( const char *fmt, ... ) JNLIB_GCC_A_PRINTF(1,2); void _gcry_log_info( const char *fmt, ... ) JNLIB_GCC_A_PRINTF(1,2); void _gcry_log_debug( const char *fmt, ... ) JNLIB_GCC_A_PRINTF(1,2); void _gcry_log_printf ( const char *fmt, ... ) JNLIB_GCC_A_PRINTF(1,2); void _gcry_log_printhex (const char *text, const void *buffer, size_t length); void _gcry_log_printmpi (const char *text, gcry_mpi_t mpi); void _gcry_log_printsxp (const char *text, gcry_sexp_t sexp); void _gcry_set_log_verbosity( int level ); int _gcry_log_verbosity( int level ); #ifdef JNLIB_GCC_M_FUNCTION #define BUG() _gcry_bug( __FILE__ , __LINE__, __FUNCTION__ ) #define gcry_assert(expr) (LIKELY(expr)? (void)0 \ : _gcry_assert_failed (STR(expr), __FILE__, __LINE__, __FUNCTION__)) #elif __STDC_VERSION__ >= 199901L #define BUG() _gcry_bug( __FILE__ , __LINE__, __func__ ) #define gcry_assert(expr) (LIKELY(expr)? (void)0 \ : _gcry_assert_failed (STR(expr), __FILE__, __LINE__, __func__)) #else #define BUG() _gcry_bug( __FILE__ , __LINE__ ) #define gcry_assert(expr) (LIKELY(expr)? (void)0 \ : _gcry_assert_failed (STR(expr), __FILE__, __LINE__)) #endif #define log_bug _gcry_log_bug #define log_fatal _gcry_log_fatal #define log_error _gcry_log_error #define log_info _gcry_log_info #define log_debug _gcry_log_debug #define log_printf _gcry_log_printf #define log_printhex _gcry_log_printhex #define log_printmpi _gcry_log_printmpi #define log_printsxp _gcry_log_printsxp /* Compatibility macro. */ #define log_mpidump _gcry_log_printmpi /* Tokeninze STRING and return a malloced array. */ char **_gcry_strtokenize (const char *string, const char *delim); /*-- src/hwfeatures.c --*/ #if defined(HAVE_CPU_ARCH_X86) #define HWF_PADLOCK_RNG (1 << 0) #define HWF_PADLOCK_AES (1 << 1) #define HWF_PADLOCK_SHA (1 << 2) #define HWF_PADLOCK_MMUL (1 << 3) #define HWF_INTEL_CPU (1 << 4) #define HWF_INTEL_FAST_SHLD (1 << 5) #define HWF_INTEL_BMI2 (1 << 6) #define HWF_INTEL_SSSE3 (1 << 7) #define HWF_INTEL_SSE4_1 (1 << 8) #define HWF_INTEL_PCLMUL (1 << 9) #define HWF_INTEL_AESNI (1 << 10) #define HWF_INTEL_RDRAND (1 << 11) #define HWF_INTEL_AVX (1 << 12) #define HWF_INTEL_AVX2 (1 << 13) #define HWF_INTEL_FAST_VPGATHER (1 << 14) #define HWF_INTEL_RDTSC (1 << 15) #define HWF_INTEL_SHAEXT (1 << 16) #define HWF_INTEL_VAES_VPCLMUL (1 << 17) #elif defined(HAVE_CPU_ARCH_ARM) #define HWF_ARM_NEON (1 << 0) #define HWF_ARM_AES (1 << 1) #define HWF_ARM_SHA1 (1 << 2) #define HWF_ARM_SHA2 (1 << 3) #define HWF_ARM_PMULL (1 << 4) #elif defined(HAVE_CPU_ARCH_PPC) #define HWF_PPC_VCRYPTO (1 << 0) #define HWF_PPC_ARCH_3_00 (1 << 1) #define HWF_PPC_ARCH_2_07 (1 << 2) #elif defined(HAVE_CPU_ARCH_S390X) #define HWF_S390X_MSA (1 << 0) #define HWF_S390X_MSA_4 (1 << 1) #define HWF_S390X_MSA_8 (1 << 2) -#define HWF_S390X_VX (1 << 3) +#define HWF_S390X_MSA_9 (1 << 3) +#define HWF_S390X_VX (1 << 4) #endif gpg_err_code_t _gcry_disable_hw_feature (const char *name); void _gcry_detect_hw_features (void); unsigned int _gcry_get_hw_features (void); const char *_gcry_enum_hw_features (int idx, unsigned int *r_feature); /*-- mpi/mpiutil.c --*/ const char *_gcry_mpi_get_hw_config (void); /*-- cipher/pubkey.c --*/ /* FIXME: shouldn't this go into mpi.h? */ #ifndef mpi_powm #define mpi_powm(w,b,e,m) gcry_mpi_powm( (w), (b), (e), (m) ) #endif /*-- primegen.c --*/ gcry_err_code_t _gcry_primegen_init (void); gcry_mpi_t _gcry_generate_secret_prime (unsigned int nbits, gcry_random_level_t random_level, int (*extra_check)(void*, gcry_mpi_t), void *extra_check_arg); gcry_mpi_t _gcry_generate_public_prime (unsigned int nbits, gcry_random_level_t random_level, int (*extra_check)(void*, gcry_mpi_t), void *extra_check_arg); gcry_err_code_t _gcry_generate_elg_prime (int mode, unsigned int pbits, unsigned int qbits, gcry_mpi_t g, gcry_mpi_t *r_prime, gcry_mpi_t **factors); gcry_mpi_t _gcry_derive_x931_prime (const gcry_mpi_t xp, const gcry_mpi_t xp1, const gcry_mpi_t xp2, const gcry_mpi_t e, gcry_mpi_t *r_p1, gcry_mpi_t *r_p2); gpg_err_code_t _gcry_generate_fips186_2_prime (unsigned int pbits, unsigned int qbits, const void *seed, size_t seedlen, gcry_mpi_t *r_q, gcry_mpi_t *r_p, int *r_counter, void **r_seed, size_t *r_seedlen); gpg_err_code_t _gcry_generate_fips186_3_prime (unsigned int pbits, unsigned int qbits, const void *seed, size_t seedlen, gcry_mpi_t *r_q, gcry_mpi_t *r_p, int *r_counter, void **r_seed, size_t *r_seedlen, int *r_hashalgo); gpg_err_code_t _gcry_fips186_4_prime_check (const gcry_mpi_t x, unsigned int bits); /* Replacements of missing functions (missing-string.c). */ #ifndef HAVE_STPCPY char *stpcpy (char *a, const char *b); #endif #ifndef HAVE_STRCASECMP int strcasecmp (const char *a, const char *b) _GCRY_GCC_ATTR_PURE; #endif #include "../compat/libcompat.h" /* Macros used to rename missing functions. */ #ifndef HAVE_STRTOUL #define strtoul(a,b,c) ((unsigned long)strtol((a),(b),(c))) #endif #ifndef HAVE_MEMMOVE #define memmove(d, s, n) bcopy((s), (d), (n)) #endif #ifndef HAVE_STRICMP #define stricmp(a,b) strcasecmp( (a), (b) ) #endif #ifndef HAVE_ATEXIT #define atexit(a) (on_exit((a),0)) #endif #ifndef HAVE_RAISE #define raise(a) kill(getpid(), (a)) #endif /* Stack burning. */ #ifdef HAVE_GCC_ASM_VOLATILE_MEMORY #define __gcry_burn_stack_dummy() asm volatile ("":::"memory") #else void __gcry_burn_stack_dummy (void); #endif void __gcry_burn_stack (unsigned int bytes); #define _gcry_burn_stack(bytes) \ do { __gcry_burn_stack (bytes); \ __gcry_burn_stack_dummy (); } while(0) /* To avoid that a compiler optimizes certain memset calls away, these macros may be used instead. For small constant length buffers, memory wiping is inlined. For non-constant or large length buffers, memory is wiped with memset through _gcry_fast_wipememory. */ #define wipememory2(_ptr,_set,_len) do { \ if (!CONSTANT_P(_len) || _len > 64) { \ if (CONSTANT_P(_set) && (_set) == 0) \ _gcry_fast_wipememory((void *)_ptr, _len); \ else \ _gcry_fast_wipememory2((void *)_ptr, _set, _len); \ } else {\ volatile char *_vptr = (volatile char *)(_ptr); \ size_t _vlen = (_len); \ const unsigned char _vset = (_set); \ fast_wipememory2(_vptr, _vset, _vlen); \ while(_vlen) { *_vptr = (_vset); _vptr++; _vlen--; } \ } \ } while(0) #define wipememory(_ptr,_len) wipememory2(_ptr,0,_len) void _gcry_fast_wipememory(void *ptr, size_t len); void _gcry_fast_wipememory2(void *ptr, int set, size_t len); #if defined(HAVE_GCC_ATTRIBUTE_PACKED) && \ defined(HAVE_GCC_ATTRIBUTE_ALIGNED) && \ defined(HAVE_GCC_ATTRIBUTE_MAY_ALIAS) typedef struct fast_wipememory_s { u64 a; } __attribute__((packed, aligned(1), may_alias)) fast_wipememory_t; /* fast_wipememory may leave tail bytes unhandled, in which case tail bytes are handled by wipememory. */ # define fast_wipememory2(_vptr,_vset,_vlen) do { \ fast_wipememory_t _vset_long; \ if (_vlen < sizeof(fast_wipememory_t)) \ break; \ _vset_long.a = (_vset); \ _vset_long.a *= U64_C(0x0101010101010101); \ do { \ volatile fast_wipememory_t *_vptr_long = \ (volatile void *)_vptr; \ _vptr_long->a = _vset_long.a; \ _vlen -= sizeof(fast_wipememory_t); \ _vptr += sizeof(fast_wipememory_t); \ } while (_vlen >= sizeof(fast_wipememory_t)); \ } while (0) #else # define fast_wipememory2(_vptr,_vset,_vlen) #endif /* Digit predicates. */ #define digitp(p) (*(p) >= '0' && *(p) <= '9') #define octdigitp(p) (*(p) >= '0' && *(p) <= '7') #define alphap(a) ( (*(a) >= 'A' && *(a) <= 'Z') \ || (*(a) >= 'a' && *(a) <= 'z')) #define hexdigitp(a) (digitp (a) \ || (*(a) >= 'A' && *(a) <= 'F') \ || (*(a) >= 'a' && *(a) <= 'f')) /* Init functions. */ gcry_err_code_t _gcry_cipher_init (void); gcry_err_code_t _gcry_md_init (void); gcry_err_code_t _gcry_mac_init (void); gcry_err_code_t _gcry_pk_init (void); gcry_err_code_t _gcry_secmem_module_init (void); gcry_err_code_t _gcry_mpi_init (void); /* Memory management. */ #define GCRY_ALLOC_FLAG_SECURE (1 << 0) #define GCRY_ALLOC_FLAG_XHINT (1 << 1) /* Called from xmalloc. */ /*-- sexp.c --*/ gcry_err_code_t _gcry_sexp_vbuild (gcry_sexp_t *retsexp, size_t *erroff, const char *format, va_list arg_ptr); char *_gcry_sexp_nth_string (const gcry_sexp_t list, int number); gpg_err_code_t _gcry_sexp_vextract_param (gcry_sexp_t sexp, const char *path, const char *list, va_list arg_ptr); /*-- fips.c --*/ extern int _gcry_no_fips_mode_required; void _gcry_initialize_fips_mode (int force); /* This macro returns true if fips mode is enabled. This is independent of the fips required finite state machine and only used to enable fips specific code. No locking is required because we have the requirement that this variable is only initialized once with no other threads existing. */ #define fips_mode() (!_gcry_no_fips_mode_required) int _gcry_enforced_fips_mode (void); void _gcry_set_enforced_fips_mode (void); void _gcry_inactivate_fips_mode (const char *text); int _gcry_is_fips_mode_inactive (void); void _gcry_fips_signal_error (const char *srcfile, int srcline, const char *srcfunc, int is_fatal, const char *description); #ifdef JNLIB_GCC_M_FUNCTION # define fips_signal_error(a) \ _gcry_fips_signal_error (__FILE__, __LINE__, __FUNCTION__, 0, (a)) # define fips_signal_fatal_error(a) \ _gcry_fips_signal_error (__FILE__, __LINE__, __FUNCTION__, 1, (a)) #else # define fips_signal_error(a) \ _gcry_fips_signal_error (__FILE__, __LINE__, NULL, 0, (a)) # define fips_signal_fatal_error(a) \ _gcry_fips_signal_error (__FILE__, __LINE__, NULL, 1, (a)) #endif int _gcry_fips_is_operational (void); /* Return true if the library is in the operational state. */ #define fips_is_operational() \ (!_gcry_global_any_init_done ? \ _gcry_global_is_operational() : \ (!fips_mode () || _gcry_global_is_operational ())) #define fips_not_operational() (GPG_ERR_NOT_OPERATIONAL) int _gcry_fips_test_operational (void); int _gcry_fips_test_error_or_operational (void); gpg_err_code_t _gcry_fips_run_selftests (int extended); void _gcry_fips_noreturn (void); #define fips_noreturn() (_gcry_fips_noreturn ()) #endif /* G10LIB_H */ diff --git a/src/hwf-s390x.c b/src/hwf-s390x.c index 25121b91..74590fc3 100644 --- a/src/hwf-s390x.c +++ b/src/hwf-s390x.c @@ -1,230 +1,231 @@ /* hwf-s390x.c - Detect hardware features - s390x/zSeries part * Copyright (C) 2020 Jussi Kivilinna * * This file is part of Libgcrypt. * * Libgcrypt is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * Libgcrypt is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . */ #include #include #include #include #include #include #include #if defined(HAVE_SYS_AUXV_H) && (defined(HAVE_GETAUXVAL) || \ defined(HAVE_ELF_AUX_INFO)) #include #endif #include "g10lib.h" #include "hwf-common.h" #if !defined (__s390x__) # error Module build for wrong CPU. #endif #undef HAVE_STFLE #ifdef HAVE_GCC_INLINE_ASM_S390X # define HAVE_STFLE 1 #endif #ifndef AT_HWCAP # define AT_HWCAP 16 #endif #ifndef HWCAP_S390_STFLE # define HWCAP_S390_STFLE 4 #endif #ifndef HWCAP_S390_VXRS # define HWCAP_S390_VXRS 2048 #endif struct feature_map_s { unsigned int facilities_bit; unsigned int hwcap_flag; unsigned int hwf_flag; }; static const struct feature_map_s s390x_features[] = { { 17, 0, HWF_S390X_MSA }, { 77, 0, HWF_S390X_MSA_4 }, { 146, 0, HWF_S390X_MSA_8 }, + { 155, 0, HWF_S390X_MSA_9 }, #ifdef HAVE_GCC_INLINE_ASM_S390X_VX { 129, HWCAP_S390_VXRS, HWF_S390X_VX }, #endif }; #if defined(HAVE_SYS_AUXV_H) && defined(HAVE_ELF_AUX_INFO) && \ !defined(HAVE_GETAUXVAL) && defined(AT_HWCAP) #define HAVE_GETAUXVAL static unsigned long getauxval(unsigned long type) { unsigned long auxval = 0; int err; /* FreeBSD provides 'elf_aux_info' function that does the same as * 'getauxval' on Linux. */ err = elf_aux_info (type, &auxval, sizeof(auxval)); if (err) { errno = err; auxval = 0; } return auxval; } #endif #undef HAS_SYS_AT_HWCAP #if defined(__linux__) || \ (defined(HAVE_SYS_AUXV_H) && defined(HAVE_GETAUXVAL)) #define HAS_SYS_AT_HWCAP 1 struct facilities_s { u64 bits[3]; }; static int get_hwcap(unsigned int *hwcap) { struct { unsigned long a_type; unsigned long a_val; } auxv; FILE *f; int err = -1; static int hwcap_initialized = 0; static unsigned int stored_hwcap = 0; if (hwcap_initialized) { *hwcap = stored_hwcap; return 0; } #if defined(HAVE_SYS_AUXV_H) && defined(HAVE_GETAUXVAL) errno = 0; auxv.a_val = getauxval (AT_HWCAP); if (errno == 0) { stored_hwcap |= auxv.a_val; hwcap_initialized = 1; } if (hwcap_initialized && stored_hwcap) { *hwcap = stored_hwcap; return 0; } #endif f = fopen("/proc/self/auxv", "r"); if (!f) { *hwcap = stored_hwcap; return -1; } while (fread(&auxv, sizeof(auxv), 1, f) > 0) { if (auxv.a_type == AT_HWCAP) { stored_hwcap |= auxv.a_val; hwcap_initialized = 1; } } if (hwcap_initialized) err = 0; fclose(f); *hwcap = stored_hwcap; return err; } #endif #ifdef HAVE_STFLE static void get_stfle(struct facilities_s *out) { static int stfle_initialized = 0; static struct facilities_s stored_facilities; if (!stfle_initialized) { register unsigned long reg0 asm("0") = DIM(stored_facilities.bits) - 1; asm ("stfle %1\n\t" : "+d" (reg0), "=Q" (stored_facilities.bits[0]) : : "cc", "memory"); stfle_initialized = 1; } *out = stored_facilities; } #endif static unsigned int detect_s390x_features(void) { struct facilities_s facilities = { { 0, } }; unsigned int hwcap = 0; unsigned int features = 0; unsigned int i; #if defined (HAS_SYS_AT_HWCAP) if (get_hwcap(&hwcap) < 0) return features; #endif if ((hwcap & HWCAP_S390_STFLE) == 0) return features; #ifdef HAVE_STFLE get_stfle(&facilities); #endif for (i = 0; i < DIM(s390x_features); i++) { if (s390x_features[i].hwcap_flag == 0 || (s390x_features[i].hwcap_flag & hwcap)) { unsigned int idx = s390x_features[i].facilities_bit; unsigned int u64_idx = idx / 64; unsigned int u64_bit = 63 - (idx % 64); if (facilities.bits[u64_idx] & (U64_C(1) << u64_bit)) features |= s390x_features[i].hwf_flag; } } return features; } unsigned int _gcry_hwf_detect_s390x (void) { unsigned int ret = 0; ret |= detect_s390x_features (); return ret; } diff --git a/src/hwfeatures.c b/src/hwfeatures.c index 534c271d..89f5943d 100644 --- a/src/hwfeatures.c +++ b/src/hwfeatures.c @@ -1,239 +1,240 @@ /* hwfeatures.c - Detect hardware features. * Copyright (C) 2007, 2011 Free Software Foundation, Inc. * Copyright (C) 2012 g10 Code GmbH * * This file is part of Libgcrypt. * * Libgcrypt is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * Libgcrypt is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . */ #include #include #include #include #include #include #include #ifdef HAVE_SYSLOG # include #endif /*HAVE_SYSLOG*/ #include "g10lib.h" #include "hwf-common.h" /* The name of a file used to globally disable selected features. */ #define HWF_DENY_FILE "/etc/gcrypt/hwf.deny" /* A table to map hardware features to a string. * Note: Remember to add new HW features to 'doc/gcrypt.texi'. */ static struct { unsigned int flag; const char *desc; } hwflist[] = { #if defined(HAVE_CPU_ARCH_X86) { HWF_PADLOCK_RNG, "padlock-rng" }, { HWF_PADLOCK_AES, "padlock-aes" }, { HWF_PADLOCK_SHA, "padlock-sha" }, { HWF_PADLOCK_MMUL, "padlock-mmul"}, { HWF_INTEL_CPU, "intel-cpu" }, { HWF_INTEL_FAST_SHLD, "intel-fast-shld" }, { HWF_INTEL_BMI2, "intel-bmi2" }, { HWF_INTEL_SSSE3, "intel-ssse3" }, { HWF_INTEL_SSE4_1, "intel-sse4.1" }, { HWF_INTEL_PCLMUL, "intel-pclmul" }, { HWF_INTEL_AESNI, "intel-aesni" }, { HWF_INTEL_RDRAND, "intel-rdrand" }, { HWF_INTEL_AVX, "intel-avx" }, { HWF_INTEL_AVX2, "intel-avx2" }, { HWF_INTEL_FAST_VPGATHER, "intel-fast-vpgather" }, { HWF_INTEL_RDTSC, "intel-rdtsc" }, { HWF_INTEL_SHAEXT, "intel-shaext" }, { HWF_INTEL_VAES_VPCLMUL, "intel-vaes-vpclmul" }, #elif defined(HAVE_CPU_ARCH_ARM) { HWF_ARM_NEON, "arm-neon" }, { HWF_ARM_AES, "arm-aes" }, { HWF_ARM_SHA1, "arm-sha1" }, { HWF_ARM_SHA2, "arm-sha2" }, { HWF_ARM_PMULL, "arm-pmull" }, #elif defined(HAVE_CPU_ARCH_PPC) { HWF_PPC_VCRYPTO, "ppc-vcrypto" }, { HWF_PPC_ARCH_3_00, "ppc-arch_3_00" }, { HWF_PPC_ARCH_2_07, "ppc-arch_2_07" }, #elif defined(HAVE_CPU_ARCH_S390X) { HWF_S390X_MSA, "s390x-msa" }, { HWF_S390X_MSA_4, "s390x-msa-4" }, { HWF_S390X_MSA_8, "s390x-msa-8" }, + { HWF_S390X_MSA_9, "s390x-msa-9" }, { HWF_S390X_VX, "s390x-vx" }, #endif }; /* A bit vector with the hardware features which shall not be used. This variable must be set prior to any initialization. */ static unsigned int disabled_hw_features; /* A bit vector describing the hardware features currently available. */ static unsigned int hw_features; /* Disable a feature by name. This function must be called *before* _gcry_detect_hw_features is called. */ gpg_err_code_t _gcry_disable_hw_feature (const char *name) { int i; size_t n1, n2; while (name && *name) { n1 = strcspn (name, ":,"); if (!n1) ; else if (n1 == 3 && !strncmp (name, "all", 3)) disabled_hw_features = ~0; else { for (i=0; i < DIM (hwflist); i++) { n2 = strlen (hwflist[i].desc); if (n1 == n2 && !strncmp (hwflist[i].desc, name, n2)) { disabled_hw_features |= hwflist[i].flag; break; } } if (!(i < DIM (hwflist))) return GPG_ERR_INV_NAME; } name += n1; if (*name) name++; /* Skip delimiter ':' or ','. */ } return 0; } /* Return a bit vector describing the available hardware features. The HWF_ constants are used to test for them. */ unsigned int _gcry_get_hw_features (void) { return hw_features; } /* Enumerate all features. The caller is expected to start with an IDX of 0 and then increment IDX until NULL is returned. */ const char * _gcry_enum_hw_features (int idx, unsigned int *r_feature) { if (idx < 0 || idx >= DIM (hwflist)) return NULL; if (r_feature) *r_feature = hwflist[idx].flag; return hwflist[idx].desc; } /* Read a file with features which shall not be used. The file is a simple text file where empty lines and lines with the first non white-space character being '#' are ignored. */ static void parse_hwf_deny_file (void) { const char *fname = HWF_DENY_FILE; FILE *fp; char buffer[256]; char *p, *pend; int lnr = 0; fp = fopen (fname, "r"); if (!fp) return; for (;;) { if (!fgets (buffer, sizeof buffer, fp)) { if (!feof (fp)) { #ifdef HAVE_SYSLOG syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: error reading '%s', line %d", fname, lnr); #endif /*HAVE_SYSLOG*/ } fclose (fp); return; } lnr++; for (p=buffer; my_isascii (*p) && isspace (*p); p++) ; pend = strchr (p, '\n'); if (pend) *pend = 0; pend = p + (*p? (strlen (p)-1):0); for ( ;pend > p; pend--) if (my_isascii (*pend) && isspace (*pend)) *pend = 0; if (!*p || *p == '#') continue; if (_gcry_disable_hw_feature (p) == GPG_ERR_INV_NAME) { #ifdef HAVE_SYSLOG syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: unknown feature in '%s', line %d", fname, lnr); #endif /*HAVE_SYSLOG*/ } } } /* Detect the available hardware features. This function is called once right at startup and we assume that no other threads are running. */ void _gcry_detect_hw_features (void) { hw_features = 0; if (fips_mode ()) return; /* Hardware support is not to be evaluated. */ parse_hwf_deny_file (); #if defined (HAVE_CPU_ARCH_X86) { hw_features = _gcry_hwf_detect_x86 (); } #elif defined (HAVE_CPU_ARCH_ARM) { hw_features = _gcry_hwf_detect_arm (); } #elif defined (HAVE_CPU_ARCH_PPC) { hw_features = _gcry_hwf_detect_ppc (); } #elif defined (HAVE_CPU_ARCH_S390X) { hw_features = _gcry_hwf_detect_s390x (); } #endif hw_features &= ~disabled_hw_features; }