diff --git a/mpi/mpih-const-time.c b/mpi/mpih-const-time.c index 96899505..8b78aabc 100644 --- a/mpi/mpih-const-time.c +++ b/mpi/mpih-const-time.c @@ -1,197 +1,204 @@ /* mpih-const-time.c - Constant-time MPI helper functions * Copyright (C) 2020 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 "mpi-internal.h" #include "g10lib.h" #define A_LIMB_1 ((mpi_limb_t)1) +/* These variables are used to generate masks from conditional operation + * flag parameters. Use of volatile prevents compiler optimizations from + * converting AND-masking to conditional branches. */ +static volatile mpi_limb_t vzero = 0; +static volatile mpi_limb_t vone = 1; + /* * W = U when OP_ENABLED=1 * otherwise, W keeps old value */ void _gcry_mpih_set_cond (mpi_ptr_t wp, mpi_ptr_t up, mpi_size_t usize, unsigned long op_enable) { mpi_size_t i; mpi_limb_t mask = ((mpi_limb_t)0) - op_enable; mpi_limb_t x; for (i = 0; i < usize; i++) { x = mask & (wp[i] ^ up[i]); wp[i] = wp[i] ^ x; } } /* * W = U + V when OP_ENABLED=1 * otherwise, W = U */ mpi_limb_t _gcry_mpih_add_n_cond (mpi_ptr_t wp, mpi_ptr_t up, mpi_ptr_t vp, mpi_size_t usize, unsigned long op_enable) { mpi_size_t i; mpi_limb_t cy; mpi_limb_t mask = ((mpi_limb_t)0) - op_enable; cy = 0; for (i = 0; i < usize; i++) { mpi_limb_t x = up[i] + (vp[i] & mask); mpi_limb_t cy1 = x < up[i]; mpi_limb_t cy2; x = x + cy; cy2 = x < cy; cy = cy1 | cy2; wp[i] = x; } return cy; } /* * W = U - V when OP_ENABLED=1 * otherwise, W = U */ mpi_limb_t _gcry_mpih_sub_n_cond (mpi_ptr_t wp, mpi_ptr_t up, mpi_ptr_t vp, mpi_size_t usize, unsigned long op_enable) { mpi_size_t i; mpi_limb_t cy; mpi_limb_t mask = ((mpi_limb_t)0) - op_enable; cy = 0; for (i = 0; i < usize; i++) { mpi_limb_t x = up[i] - (vp[i] & mask); mpi_limb_t cy1 = x > up[i]; mpi_limb_t cy2; cy2 = x < cy; x = x - cy; cy = cy1 | cy2; wp[i] = x; } return cy; } /* * Swap value of U and V when OP_ENABLED=1 * otherwise, no change */ void _gcry_mpih_swap_cond (mpi_ptr_t up, mpi_ptr_t vp, mpi_size_t usize, unsigned long op_enable) { mpi_size_t i; - mpi_limb_t mask = ((mpi_limb_t)0) - op_enable; + mpi_limb_t mask1 = vzero - op_enable; + mpi_limb_t mask2 = op_enable - vone; for (i = 0; i < usize; i++) { - mpi_limb_t x = mask & (up[i] ^ vp[i]); - - up[i] = up[i] ^ x; - vp[i] = vp[i] ^ x; + mpi_limb_t u = up[i]; + mpi_limb_t v = vp[i]; + up[i] = (u & mask2) | (v & mask1); + vp[i] = (u & mask1) | (v & mask2); } } /* * W = -U when OP_ENABLED=1 * otherwise, W = U */ void _gcry_mpih_abs_cond (mpi_ptr_t wp, mpi_ptr_t up, mpi_size_t usize, unsigned long op_enable) { mpi_size_t i; mpi_limb_t mask = ((mpi_limb_t)0) - op_enable; mpi_limb_t cy = op_enable; for (i = 0; i < usize; i++) { mpi_limb_t x = ~up[i] + cy; cy = (x < ~up[i]); wp[i] = up[i] ^ (mask & (x ^ up[i])); } } /* * Allocating memory for W, * compute W = V % U, then return W */ mpi_ptr_t _gcry_mpih_mod (mpi_ptr_t vp, mpi_size_t vsize, mpi_ptr_t up, mpi_size_t usize) { int secure; mpi_ptr_t rp; mpi_size_t i; secure = _gcry_is_secure (vp); rp = mpi_alloc_limb_space (usize, secure); MPN_ZERO (rp, usize); for (i = 0; i < vsize * BITS_PER_MPI_LIMB; i++) { unsigned int j = vsize * BITS_PER_MPI_LIMB - 1 - i; unsigned int limbno = j / BITS_PER_MPI_LIMB; unsigned int bitno = j % BITS_PER_MPI_LIMB; mpi_limb_t limb = vp[limbno]; unsigned int the_bit = ((limb & (A_LIMB_1 << bitno)) ? 1 : 0); mpi_limb_t underflow; mpi_limb_t overflow; overflow = _gcry_mpih_lshift (rp, rp, usize, 1); rp[0] |= the_bit; underflow = _gcry_mpih_sub_n (rp, rp, up, usize); mpih_add_n_cond (rp, rp, up, usize, overflow ^ underflow); } return rp; } int _gcry_mpih_cmp_ui (mpi_ptr_t up, mpi_size_t usize, unsigned long v) { int is_all_zero = 1; mpi_size_t i; for (i = 1; i < usize; i++) is_all_zero &= (up[i] == 0); if (is_all_zero) return up[0] - v; return 1; } diff --git a/mpi/mpiutil.c b/mpi/mpiutil.c index 86b8361e..a1ac1c43 100644 --- a/mpi/mpiutil.c +++ b/mpi/mpiutil.c @@ -1,780 +1,792 @@ /* mpiutil.ac - Utility functions for MPI * Copyright (C) 1998, 2000, 2001, 2002, 2003, * 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 "g10lib.h" #include "mpi-internal.h" #include "mod-source-info.h" #if SIZEOF_UNSIGNED_INT == 2 # define MY_UINT_MAX 0xffff /* (visual check: 0123 ) */ #elif SIZEOF_UNSIGNED_INT == 4 # define MY_UINT_MAX 0xffffffff /* (visual check: 01234567 ) */ #elif SIZEOF_UNSIGNED_INT == 8 # define MY_UINT_MAX 0xffffffffffffffff /* (visual check: 0123456789abcdef ) */ #else # error Need MY_UINT_MAX for this limb size #endif /* Constants allocated right away at startup. */ static gcry_mpi_t constants[MPI_NUMBER_OF_CONSTANTS]; +/* These variables are used to generate masks from conditional operation + * flag parameters. Use of volatile prevents compiler optimizations from + * converting AND-masking to conditional branches. */ +static volatile mpi_limb_t vzero = 0; +static volatile mpi_limb_t vone = 1; const char * _gcry_mpi_get_hw_config (void) { return mod_source_info + 1; } /* Initialize the MPI subsystem. This is called early and allows to do some initialization without taking care of threading issues. */ gcry_err_code_t _gcry_mpi_init (void) { int idx; unsigned long value; for (idx=0; idx < MPI_NUMBER_OF_CONSTANTS; idx++) { switch (idx) { case MPI_C_ZERO: value = 0; break; case MPI_C_ONE: value = 1; break; case MPI_C_TWO: value = 2; break; case MPI_C_THREE: value = 3; break; case MPI_C_FOUR: value = 4; break; case MPI_C_EIGHT: value = 8; break; default: log_bug ("invalid mpi_const selector %d\n", idx); } constants[idx] = mpi_alloc_set_ui (value); constants[idx]->flags = (16|32); } return 0; } /**************** * Note: It was a bad idea to use the number of limbs to allocate * because on a alpha the limbs are large but we normally need * integers of n bits - So we should change this to bits (or bytes). * * But mpi_alloc is used in a lot of places :-(. New code * should use mpi_new. */ gcry_mpi_t _gcry_mpi_alloc( unsigned nlimbs ) { gcry_mpi_t a; a = xmalloc( sizeof *a ); a->d = nlimbs? mpi_alloc_limb_space( nlimbs, 0 ) : NULL; a->alloced = nlimbs; a->nlimbs = 0; a->sign = 0; a->flags = 0; return a; } void _gcry_mpi_m_check( gcry_mpi_t a ) { _gcry_check_heap(a); _gcry_check_heap(a->d); } gcry_mpi_t _gcry_mpi_alloc_secure( unsigned nlimbs ) { gcry_mpi_t a; a = xmalloc( sizeof *a ); a->d = nlimbs? mpi_alloc_limb_space( nlimbs, 1 ) : NULL; a->alloced = nlimbs; a->flags = 1; a->nlimbs = 0; a->sign = 0; return a; } mpi_ptr_t _gcry_mpi_alloc_limb_space( unsigned int nlimbs, int secure ) { mpi_ptr_t p; size_t len; len = (nlimbs ? nlimbs : 1) * sizeof (mpi_limb_t); p = secure ? xmalloc_secure (len) : xmalloc (len); if (! nlimbs) *p = 0; return p; } void _gcry_mpi_free_limb_space( mpi_ptr_t a, unsigned int nlimbs) { if (a) { size_t len = nlimbs * sizeof(mpi_limb_t); /* If we have information on the number of allocated limbs, we better wipe that space out. This is a failsafe feature if secure memory has been disabled or was not properly implemented in user provided allocation functions. */ if (len) wipememory (a, len); xfree(a); } } void _gcry_mpi_assign_limb_space( gcry_mpi_t a, mpi_ptr_t ap, unsigned int nlimbs ) { _gcry_mpi_free_limb_space (a->d, a->alloced); a->d = ap; a->alloced = nlimbs; } /**************** * Resize the array of A to NLIMBS. The additional space is cleared * (set to 0). */ void _gcry_mpi_resize (gcry_mpi_t a, unsigned nlimbs) { size_t i; if (nlimbs <= a->alloced) { /* We only need to clear the new space (this is a nop if the limb space is already of the correct size. */ for (i=a->nlimbs; i < a->alloced; i++) a->d[i] = 0; return; } /* Actually resize the limb space. */ if (a->d) { a->d = xrealloc (a->d, nlimbs * sizeof (mpi_limb_t)); for (i=a->alloced; i < nlimbs; i++) a->d[i] = 0; } else { if (a->flags & 1) /* Secure memory is wanted. */ a->d = xcalloc_secure (nlimbs , sizeof (mpi_limb_t)); else /* Standard memory. */ a->d = xcalloc (nlimbs , sizeof (mpi_limb_t)); } a->alloced = nlimbs; } void _gcry_mpi_clear( gcry_mpi_t a ) { if (mpi_is_immutable (a)) { mpi_immutable_failed (); return; } a->nlimbs = 0; a->flags = 0; } void _gcry_mpi_free( gcry_mpi_t a ) { if (!a ) return; if ((a->flags & 32)) { #if GPGRT_VERSION_NUMBER >= 0x011600 /* 1.22 */ gpgrt_annotate_leaked_object(a); #endif return; /* Never release a constant. */ } if ((a->flags & 4)) xfree( a->d ); else { _gcry_mpi_free_limb_space(a->d, a->alloced); } /* Check that the flags makes sense. We better allow for bit 1 (value 2) for backward ABI compatibility. */ if ((a->flags & ~(1|2|4|16 |GCRYMPI_FLAG_USER1 |GCRYMPI_FLAG_USER2 |GCRYMPI_FLAG_USER3 |GCRYMPI_FLAG_USER4))) log_bug("invalid flag value in mpi_free\n"); xfree (a); } void _gcry_mpi_immutable_failed (void) { log_info ("Warning: trying to change an immutable MPI\n"); } static void mpi_set_secure( gcry_mpi_t a ) { mpi_ptr_t ap, bp; if ( (a->flags & 1) ) return; a->flags |= 1; ap = a->d; if (!a->nlimbs) { gcry_assert (!ap); return; } bp = mpi_alloc_limb_space (a->alloced, 1); MPN_COPY( bp, ap, a->nlimbs ); a->d = bp; _gcry_mpi_free_limb_space (ap, a->alloced); } gcry_mpi_t _gcry_mpi_set_opaque (gcry_mpi_t a, void *p, unsigned int nbits) { if (!a) a = mpi_alloc(0); if (mpi_is_immutable (a)) { mpi_immutable_failed (); return a; } if( a->flags & 4 ) xfree (a->d); else _gcry_mpi_free_limb_space (a->d, a->alloced); a->d = p; a->alloced = 0; a->nlimbs = 0; a->sign = nbits; a->flags = 4 | (a->flags & (GCRYMPI_FLAG_USER1|GCRYMPI_FLAG_USER2 |GCRYMPI_FLAG_USER3|GCRYMPI_FLAG_USER4)); if (_gcry_is_secure (a->d)) a->flags |= 1; return a; } gcry_mpi_t _gcry_mpi_set_opaque_copy (gcry_mpi_t a, const void *p, unsigned int nbits) { void *d; unsigned int n; n = (nbits+7)/8; d = _gcry_is_secure (p)? xtrymalloc_secure (n) : xtrymalloc (n); if (!d) return NULL; memcpy (d, p, n); return mpi_set_opaque (a, d, nbits); } void * _gcry_mpi_get_opaque (gcry_mpi_t a, unsigned int *nbits) { if( !(a->flags & 4) ) log_bug("mpi_get_opaque on normal mpi\n"); if( nbits ) *nbits = a->sign; return a->d; } void * _gcry_mpi_get_opaque_copy (gcry_mpi_t a, unsigned int *nbits) { const void *s; void *d; unsigned int n; s = mpi_get_opaque (a, nbits); if (!s && nbits) return NULL; n = (*nbits+7)/8; d = _gcry_is_secure (s)? xtrymalloc_secure (n) : xtrymalloc (n); if (d) memcpy (d, s, n); return d; } /**************** * Note: This copy function should not interpret the MPI * but copy it transparently. */ gcry_mpi_t _gcry_mpi_copy (gcry_mpi_t a) { int i; gcry_mpi_t b; if( a && (a->flags & 4) ) { void *p = _gcry_is_secure(a->d)? xmalloc_secure ((a->sign+7)/8) : xmalloc ((a->sign+7)/8); if (a->d) memcpy( p, a->d, (a->sign+7)/8 ); b = mpi_set_opaque( NULL, p, a->sign ); b->flags = a->flags; b->flags &= ~(16|32); /* Reset the immutable and constant flags. */ } else if( a ) { b = mpi_is_secure(a)? mpi_alloc_secure( a->nlimbs ) : mpi_alloc( a->nlimbs ); b->nlimbs = a->nlimbs; b->sign = a->sign; b->flags = a->flags; b->flags &= ~(16|32); /* Reset the immutable and constant flags. */ for(i=0; i < b->nlimbs; i++ ) b->d[i] = a->d[i]; } else b = NULL; return b; } /* Return true if A is negative. */ int _gcry_mpi_is_neg (gcry_mpi_t a) { if (a->sign && _gcry_mpi_cmp_ui (a, 0)) return 1; else return 0; } /* W = - U */ void _gcry_mpi_neg (gcry_mpi_t w, gcry_mpi_t u) { if (w != u) mpi_set (w, u); else if (mpi_is_immutable (w)) { mpi_immutable_failed (); return; } w->sign = !u->sign; } /* W = [W] */ void _gcry_mpi_abs (gcry_mpi_t w) { if (mpi_is_immutable (w)) { mpi_immutable_failed (); return; } w->sign = 0; } /**************** * This function allocates an MPI which is optimized to hold * a value as large as the one given in the argument and allocates it * with the same flags as A. */ gcry_mpi_t _gcry_mpi_alloc_like( gcry_mpi_t a ) { gcry_mpi_t b; if( a && (a->flags & 4) ) { int n = (a->sign+7)/8; void *p = _gcry_is_secure(a->d)? xtrymalloc_secure (n) : xtrymalloc (n); memcpy( p, a->d, n ); b = mpi_set_opaque( NULL, p, a->sign ); } else if( a ) { b = mpi_is_secure(a)? mpi_alloc_secure( a->nlimbs ) : mpi_alloc( a->nlimbs ); b->nlimbs = 0; b->sign = 0; b->flags = a->flags; } else b = NULL; return b; } /* Set U into W and release U. If W is NULL only U will be released. */ void _gcry_mpi_snatch (gcry_mpi_t w, gcry_mpi_t u) { if (w) { if (mpi_is_immutable (w)) { mpi_immutable_failed (); return; } _gcry_mpi_assign_limb_space (w, u->d, u->alloced); w->nlimbs = u->nlimbs; w->sign = u->sign; w->flags = u->flags; u->alloced = 0; u->nlimbs = 0; u->d = NULL; } _gcry_mpi_free (u); } gcry_mpi_t _gcry_mpi_set (gcry_mpi_t w, gcry_mpi_t u) { mpi_ptr_t wp, up; mpi_size_t usize = u->nlimbs; int usign = u->sign; if (!w) w = _gcry_mpi_alloc( mpi_get_nlimbs(u) ); if (mpi_is_immutable (w)) { mpi_immutable_failed (); return w; } RESIZE_IF_NEEDED(w, usize); wp = w->d; up = u->d; MPN_COPY( wp, up, usize ); w->nlimbs = usize; w->flags = u->flags; w->flags &= ~(16|32); /* Reset the immutable and constant flags. */ w->sign = usign; return w; } /**************** * Set the value of W by the one of U, when SET is 1. * Leave the value when SET is 0. * This implementation should be constant-time regardless of SET. */ gcry_mpi_t _gcry_mpi_set_cond (gcry_mpi_t w, const gcry_mpi_t u, unsigned long set) { mpi_size_t i; mpi_size_t nlimbs = u->alloced; mpi_limb_t mask = ((mpi_limb_t)0) - set; mpi_limb_t x; if (w->alloced != u->alloced) log_bug ("mpi_set_cond: different sizes\n"); for (i = 0; i < nlimbs; i++) { x = mask & (w->d[i] ^ u->d[i]); w->d[i] = w->d[i] ^ x; } x = mask & (w->nlimbs ^ u->nlimbs); w->nlimbs = w->nlimbs ^ x; x = mask & (w->sign ^ u->sign); w->sign = w->sign ^ x; return w; } gcry_mpi_t _gcry_mpi_set_ui (gcry_mpi_t w, unsigned long u) { if (!w) w = _gcry_mpi_alloc (1); /* FIXME: If U is 0 we have no need to resize and thus possible allocating the the limbs. */ if (mpi_is_immutable (w)) { mpi_immutable_failed (); return w; } RESIZE_IF_NEEDED(w, 1); w->d[0] = u; w->nlimbs = u? 1:0; w->sign = 0; w->flags = 0; return w; } /* If U is non-negative and small enough store it as an unsigned int * at W. If the value does not fit into an unsigned int or is * negative return GPG_ERR_ERANGE. Note that we return an unsigned * int so that the value can be used with the bit test functions; in * contrast the other _ui functions take an unsigned long so that on * some platforms they may accept a larger value. On error the value * at W is not changed. */ gcry_err_code_t _gcry_mpi_get_ui (unsigned int *w, gcry_mpi_t u) { mpi_limb_t x; if (u->nlimbs > 1 || u->sign) return GPG_ERR_ERANGE; x = (u->nlimbs == 1) ? u->d[0] : 0; if (sizeof (x) > sizeof (unsigned int) && x > MY_UINT_MAX) return GPG_ERR_ERANGE; *w = x; return 0; } gcry_mpi_t _gcry_mpi_alloc_set_ui( unsigned long u) { gcry_mpi_t w = mpi_alloc(1); w->d[0] = u; w->nlimbs = u? 1:0; w->sign = 0; return w; } void _gcry_mpi_swap (gcry_mpi_t a, gcry_mpi_t b) { struct gcry_mpi tmp; tmp = *a; *a = *b; *b = tmp; } /**************** * Swap the value of A and B, when SWAP is 1. * Leave the value when SWAP is 0. * This implementation should be constant-time regardless of SWAP. */ void _gcry_mpi_swap_cond (gcry_mpi_t a, gcry_mpi_t b, unsigned long swap) { mpi_size_t i; mpi_size_t nlimbs; - mpi_limb_t mask = ((mpi_limb_t)0) - swap; - mpi_limb_t x; + mpi_limb_t mask1 = vzero - swap; + mpi_limb_t mask2 = swap - vone; + mpi_limb_t *ua = a->d; + mpi_limb_t *ub = b->d; + mpi_limb_t xa; + mpi_limb_t xb; if (a->alloced > b->alloced) nlimbs = b->alloced; else nlimbs = a->alloced; if (a->nlimbs > nlimbs || b->nlimbs > nlimbs) log_bug ("mpi_swap_cond: different sizes\n"); for (i = 0; i < nlimbs; i++) { - x = mask & (a->d[i] ^ b->d[i]); - a->d[i] = a->d[i] ^ x; - b->d[i] = b->d[i] ^ x; + xa = ua[i]; + xb = ub[i]; + ua[i] = (xa & mask2) | (xb & mask1); + ub[i] = (xa & mask1) | (xb & mask2); } - x = mask & (a->nlimbs ^ b->nlimbs); - a->nlimbs = a->nlimbs ^ x; - b->nlimbs = b->nlimbs ^ x; + xa = a->nlimbs; + xb = b->nlimbs; + a->nlimbs = (xa & mask2) | (xb & mask1); + b->nlimbs = (xa & mask1) | (xb & mask2); - x = mask & (a->sign ^ b->sign); - a->sign = a->sign ^ x; - b->sign = b->sign ^ x; + xa = a->sign; + xb = b->sign; + a->sign = (xa & mask2) | (xb & mask1); + b->sign = (xa & mask1) | (xb & mask2); } /**************** * Set bit N of A, when SET is 1. * This implementation should be constant-time regardless of SET. */ void _gcry_mpi_set_bit_cond (gcry_mpi_t a, unsigned int n, unsigned long set) { unsigned int limbno, bitno; mpi_limb_t set_the_bit = !!set; limbno = n / BITS_PER_MPI_LIMB; bitno = n % BITS_PER_MPI_LIMB; a->d[limbno] |= (set_the_bit<flags |= (16|32); break; case GCRYMPI_FLAG_IMMUTABLE: a->flags |= 16; break; case GCRYMPI_FLAG_USER1: case GCRYMPI_FLAG_USER2: case GCRYMPI_FLAG_USER3: case GCRYMPI_FLAG_USER4: a->flags |= flag; break; case GCRYMPI_FLAG_OPAQUE: default: log_bug("invalid flag value\n"); } } void _gcry_mpi_clear_flag (gcry_mpi_t a, enum gcry_mpi_flag flag) { (void)a; /* Not yet used. */ switch (flag) { case GCRYMPI_FLAG_IMMUTABLE: if (!(a->flags & 32)) a->flags &= ~16; break; case GCRYMPI_FLAG_USER1: case GCRYMPI_FLAG_USER2: case GCRYMPI_FLAG_USER3: case GCRYMPI_FLAG_USER4: a->flags &= ~flag; break; case GCRYMPI_FLAG_CONST: case GCRYMPI_FLAG_SECURE: case GCRYMPI_FLAG_OPAQUE: default: log_bug("invalid flag value\n"); } } int _gcry_mpi_get_flag (gcry_mpi_t a, enum gcry_mpi_flag flag) { switch (flag) { case GCRYMPI_FLAG_SECURE: return !!(a->flags & 1); case GCRYMPI_FLAG_OPAQUE: return !!(a->flags & 4); case GCRYMPI_FLAG_IMMUTABLE: return !!(a->flags & 16); case GCRYMPI_FLAG_CONST: return !!(a->flags & 32); case GCRYMPI_FLAG_USER1: case GCRYMPI_FLAG_USER2: case GCRYMPI_FLAG_USER3: case GCRYMPI_FLAG_USER4: return !!(a->flags & flag); default: log_bug("invalid flag value\n"); } /*NOTREACHED*/ return 0; } /* Return a constant MPI descripbed by NO which is one of the MPI_C_xxx macros. There is no need to copy this returned value; it may be used directly. */ gcry_mpi_t _gcry_mpi_const (enum gcry_mpi_constants no) { if ((int)no < 0 || no > MPI_NUMBER_OF_CONSTANTS) log_bug("invalid mpi_const selector %d\n", no); if (!constants[no]) log_bug("MPI subsystem not initialized\n"); return constants[no]; }