-
+ 1C5BD39C13569D58A5CFD542D96DF998B63EFD14EDFCDB9488975B69DD7796B21EF656577E9DA950CECE9D9122B7030395F0714CBBA2983B3DAFC860B34C1B85
eucrypt/mpi/mpih-mul.c
(0 . 0)(1 . 519)
5737 /* mpihelp-mul.c - MPI helper functions
5738 * Modified by No Such Labs. (C) 2015. See README.
5739 *
5740 * This file was originally part of Gnu Privacy Guard (GPG), ver. 1.4.10,
5741 * SHA256(gnupg-1.4.10.tar.gz):
5742 * 0bfd74660a2f6cedcf7d8256db4a63c996ffebbcdc2cf54397bfb72878c5a85a
5743 * (C) 1994-2005 Free Software Foundation, Inc.
5744 *
5745 * This program is free software: you can redistribute it and/or modify
5746 * it under the terms of the GNU General Public License as published by
5747 * the Free Software Foundation, either version 3 of the License, or
5748 * (at your option) any later version.
5749 *
5750 * This program is distributed in the hope that it will be useful,
5751 * but WITHOUT ANY WARRANTY; without even the implied warranty of
5752 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
5753 * GNU General Public License for more details.
5754 *
5755 * You should have received a copy of the GNU General Public License
5756 * along with this program. If not, see <http://www.gnu.org/licenses/>.
5757 */
5758
5759 #include <stdio.h>
5760 #include <stdlib.h>
5761 #include <string.h>
5762
5763 #include "knobs.h"
5764 #include "mpi-internal.h"
5765 #include "longlong.h"
5766
5767
5768 #define MPN_MUL_N_RECURSE(prodp, up, vp, size, tspace) \
5769 do { \
5770 if( (size) < KARATSUBA_THRESHOLD ) \
5771 mul_n_basecase (prodp, up, vp, size); \
5772 else \
5773 mul_n (prodp, up, vp, size, tspace); \
5774 } while (0);
5775
5776 #define MPN_SQR_N_RECURSE(prodp, up, size, tspace) \
5777 do { \
5778 if ((size) < KARATSUBA_THRESHOLD) \
5779 mpih_sqr_n_basecase (prodp, up, size); \
5780 else \
5781 mpih_sqr_n (prodp, up, size, tspace); \
5782 } while (0);
5783
5784
5785 /* Multiply the natural numbers u (pointed to by UP) and v (pointed to by VP),
5786 * both with SIZE limbs, and store the result at PRODP. 2 * SIZE limbs are
5787 * always stored. Return the most significant limb.
5788 *
5789 * Argument constraints:
5790 * 1. PRODP != UP and PRODP != VP, i.e. the destination
5791 * must be distinct from the multiplier and the multiplicand.
5792 *
5793 *
5794 * Handle simple cases with traditional multiplication.
5795 *
5796 * This is the most critical code of multiplication. All multiplies rely
5797 * on this, both small and huge. Small ones arrive here immediately. Huge
5798 * ones arrive here as this is the base case for Karatsuba's recursive
5799 * algorithm below.
5800 */
5801
5802 static mpi_limb_t
5803 mul_n_basecase( mpi_ptr_t prodp, mpi_ptr_t up,
5804 mpi_ptr_t vp, mpi_size_t size)
5805 {
5806 mpi_size_t i;
5807 mpi_limb_t cy;
5808 mpi_limb_t v_limb;
5809
5810 /* Multiply by the first limb in V separately, as the result can be
5811 * stored (not added) to PROD. We also avoid a loop for zeroing. */
5812 v_limb = vp[0];
5813 if( v_limb <= 1 ) {
5814 if( v_limb == 1 )
5815 MPN_COPY( prodp, up, size );
5816 else
5817 MPN_ZERO( prodp, size );
5818 cy = 0;
5819 }
5820 else
5821 cy = mpihelp_mul_1( prodp, up, size, v_limb );
5822
5823 prodp[size] = cy;
5824 prodp++;
5825
5826 /* For each iteration in the outer loop, multiply one limb from
5827 * U with one limb from V, and add it to PROD. */
5828 for( i = 1; i < size; i++ ) {
5829 v_limb = vp[i];
5830 if( v_limb <= 1 ) {
5831 cy = 0;
5832 if( v_limb == 1 )
5833 cy = mpihelp_add_n(prodp, prodp, up, size);
5834 }
5835 else
5836 cy = mpihelp_addmul_1(prodp, up, size, v_limb);
5837
5838 prodp[size] = cy;
5839 prodp++;
5840 }
5841
5842 return cy;
5843 }
5844
5845
5846 static void
5847 mul_n( mpi_ptr_t prodp, mpi_ptr_t up, mpi_ptr_t vp,
5848 mpi_size_t size, mpi_ptr_t tspace )
5849 {
5850 if( size & 1 ) {
5851 /* The size is odd, and the code below doesn't handle that.
5852 * Multiply the least significant (size - 1) limbs with a recursive
5853 * call, and handle the most significant limb of S1 and S2
5854 * separately.
5855 * A slightly faster way to do this would be to make the Karatsuba
5856 * code below behave as if the size were even, and let it check for
5857 * odd size in the end. I.e., in essence move this code to the end.
5858 * Doing so would save us a recursive call, and potentially make the
5859 * stack grow a lot less.
5860 */
5861 mpi_size_t esize = size - 1; /* even size */
5862 mpi_limb_t cy_limb;
5863
5864 MPN_MUL_N_RECURSE( prodp, up, vp, esize, tspace );
5865 cy_limb = mpihelp_addmul_1( prodp + esize, up, esize, vp[esize] );
5866 prodp[esize + esize] = cy_limb;
5867 cy_limb = mpihelp_addmul_1( prodp + esize, vp, size, up[esize] );
5868 prodp[esize + size] = cy_limb;
5869 }
5870 else {
5871 /* Anatolij Alekseevich Karatsuba's divide-and-conquer algorithm.
5872 *
5873 * Split U in two pieces, U1 and U0, such that
5874 * U = U0 + U1*(B**n),
5875 * and V in V1 and V0, such that
5876 * V = V0 + V1*(B**n).
5877 *
5878 * UV is then computed recursively using the identity
5879 *
5880 * 2n n n n
5881 * UV = (B + B )U V + B (U -U )(V -V ) + (B + 1)U V
5882 * 1 1 1 0 0 1 0 0
5883 *
5884 * Where B = 2**BITS_PER_MP_LIMB.
5885 */
5886 mpi_size_t hsize = size >> 1;
5887 mpi_limb_t cy;
5888 int negflg;
5889
5890 /* Product H. ________________ ________________
5891 * |_____U1 x V1____||____U0 x V0_____|
5892 * Put result in upper part of PROD and pass low part of TSPACE
5893 * as new TSPACE.
5894 */
5895 MPN_MUL_N_RECURSE(prodp + size, up + hsize, vp + hsize, hsize, tspace);
5896
5897 /* Product M. ________________
5898 * |_(U1-U0)(V0-V1)_|
5899 */
5900 if( mpihelp_cmp(up + hsize, up, hsize) >= 0 ) {
5901 mpihelp_sub_n(prodp, up + hsize, up, hsize);
5902 negflg = 0;
5903 }
5904 else {
5905 mpihelp_sub_n(prodp, up, up + hsize, hsize);
5906 negflg = 1;
5907 }
5908 if( mpihelp_cmp(vp + hsize, vp, hsize) >= 0 ) {
5909 mpihelp_sub_n(prodp + hsize, vp + hsize, vp, hsize);
5910 negflg ^= 1;
5911 }
5912 else {
5913 mpihelp_sub_n(prodp + hsize, vp, vp + hsize, hsize);
5914 /* No change of NEGFLG. */
5915 }
5916 /* Read temporary operands from low part of PROD.
5917 * Put result in low part of TSPACE using upper part of TSPACE
5918 * as new TSPACE.
5919 */
5920 MPN_MUL_N_RECURSE(tspace, prodp, prodp + hsize, hsize, tspace + size);
5921
5922 /* Add/copy product H. */
5923 MPN_COPY (prodp + hsize, prodp + size, hsize);
5924 cy = mpihelp_add_n( prodp + size, prodp + size,
5925 prodp + size + hsize, hsize);
5926
5927 /* Add product M (if NEGFLG M is a negative number) */
5928 if(negflg)
5929 cy -= mpihelp_sub_n(prodp + hsize, prodp + hsize, tspace, size);
5930 else
5931 cy += mpihelp_add_n(prodp + hsize, prodp + hsize, tspace, size);
5932
5933 /* Product L. ________________ ________________
5934 * |________________||____U0 x V0_____|
5935 * Read temporary operands from low part of PROD.
5936 * Put result in low part of TSPACE using upper part of TSPACE
5937 * as new TSPACE.
5938 */
5939 MPN_MUL_N_RECURSE(tspace, up, vp, hsize, tspace + size);
5940
5941 /* Add/copy Product L (twice) */
5942
5943 cy += mpihelp_add_n(prodp + hsize, prodp + hsize, tspace, size);
5944 if( cy )
5945 mpihelp_add_1(prodp + hsize + size, prodp + hsize + size, hsize, cy);
5946
5947 MPN_COPY(prodp, tspace, hsize);
5948 cy = mpihelp_add_n(prodp + hsize, prodp + hsize, tspace + hsize, hsize);
5949 if( cy )
5950 mpihelp_add_1(prodp + size, prodp + size, size, 1);
5951 }
5952 }
5953
5954
5955 void
5956 mpih_sqr_n_basecase( mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t size )
5957 {
5958 mpi_size_t i;
5959 mpi_limb_t cy_limb;
5960 mpi_limb_t v_limb;
5961
5962 /* Multiply by the first limb in V separately, as the result can be
5963 * stored (not added) to PROD. We also avoid a loop for zeroing. */
5964 v_limb = up[0];
5965 if( v_limb <= 1 ) {
5966 if( v_limb == 1 )
5967 MPN_COPY( prodp, up, size );
5968 else
5969 MPN_ZERO(prodp, size);
5970 cy_limb = 0;
5971 }
5972 else
5973 cy_limb = mpihelp_mul_1( prodp, up, size, v_limb );
5974
5975 prodp[size] = cy_limb;
5976 prodp++;
5977
5978 /* For each iteration in the outer loop, multiply one limb from
5979 * U with one limb from V, and add it to PROD. */
5980 for( i=1; i < size; i++) {
5981 v_limb = up[i];
5982 if( v_limb <= 1 ) {
5983 cy_limb = 0;
5984 if( v_limb == 1 )
5985 cy_limb = mpihelp_add_n(prodp, prodp, up, size);
5986 }
5987 else
5988 cy_limb = mpihelp_addmul_1(prodp, up, size, v_limb);
5989
5990 prodp[size] = cy_limb;
5991 prodp++;
5992 }
5993 }
5994
5995
5996 void
5997 mpih_sqr_n( mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t size, mpi_ptr_t tspace)
5998 {
5999 if( size & 1 ) {
6000 /* The size is odd, and the code below doesn't handle that.
6001 * Multiply the least significant (size - 1) limbs with a recursive
6002 * call, and handle the most significant limb of S1 and S2
6003 * separately.
6004 * A slightly faster way to do this would be to make the Karatsuba
6005 * code below behave as if the size were even, and let it check for
6006 * odd size in the end. I.e., in essence move this code to the end.
6007 * Doing so would save us a recursive call, and potentially make the
6008 * stack grow a lot less.
6009 */
6010 mpi_size_t esize = size - 1; /* even size */
6011 mpi_limb_t cy_limb;
6012
6013 MPN_SQR_N_RECURSE( prodp, up, esize, tspace );
6014 cy_limb = mpihelp_addmul_1( prodp + esize, up, esize, up[esize] );
6015 prodp[esize + esize] = cy_limb;
6016 cy_limb = mpihelp_addmul_1( prodp + esize, up, size, up[esize] );
6017
6018 prodp[esize + size] = cy_limb;
6019 }
6020 else {
6021 mpi_size_t hsize = size >> 1;
6022 mpi_limb_t cy;
6023
6024 /* Product H. ________________ ________________
6025 * |_____U1 x U1____||____U0 x U0_____|
6026 * Put result in upper part of PROD and pass low part of TSPACE
6027 * as new TSPACE.
6028 */
6029 MPN_SQR_N_RECURSE(prodp + size, up + hsize, hsize, tspace);
6030
6031 /* Product M. ________________
6032 * |_(U1-U0)(U0-U1)_|
6033 */
6034 if( mpihelp_cmp( up + hsize, up, hsize) >= 0 )
6035 mpihelp_sub_n( prodp, up + hsize, up, hsize);
6036 else
6037 mpihelp_sub_n (prodp, up, up + hsize, hsize);
6038
6039 /* Read temporary operands from low part of PROD.
6040 * Put result in low part of TSPACE using upper part of TSPACE
6041 * as new TSPACE. */
6042 MPN_SQR_N_RECURSE(tspace, prodp, hsize, tspace + size);
6043
6044 /* Add/copy product H */
6045 MPN_COPY(prodp + hsize, prodp + size, hsize);
6046 cy = mpihelp_add_n(prodp + size, prodp + size,
6047 prodp + size + hsize, hsize);
6048
6049 /* Add product M (if NEGFLG M is a negative number). */
6050 cy -= mpihelp_sub_n (prodp + hsize, prodp + hsize, tspace, size);
6051
6052 /* Product L. ________________ ________________
6053 * |________________||____U0 x U0_____|
6054 * Read temporary operands from low part of PROD.
6055 * Put result in low part of TSPACE using upper part of TSPACE
6056 * as new TSPACE. */
6057 MPN_SQR_N_RECURSE (tspace, up, hsize, tspace + size);
6058
6059 /* Add/copy Product L (twice). */
6060 cy += mpihelp_add_n (prodp + hsize, prodp + hsize, tspace, size);
6061 if( cy )
6062 mpihelp_add_1(prodp + hsize + size, prodp + hsize + size,
6063 hsize, cy);
6064
6065 MPN_COPY(prodp, tspace, hsize);
6066 cy = mpihelp_add_n (prodp + hsize, prodp + hsize, tspace + hsize, hsize);
6067 if( cy )
6068 mpihelp_add_1 (prodp + size, prodp + size, size, 1);
6069 }
6070 }
6071
6072
6073 /* This should be made into an inline function in gmp.h. */
6074 void
6075 mpihelp_mul_n( mpi_ptr_t prodp, mpi_ptr_t up, mpi_ptr_t vp, mpi_size_t size)
6076 {
6077 int secure;
6078
6079 if( up == vp ) {
6080 if( size < KARATSUBA_THRESHOLD )
6081 mpih_sqr_n_basecase( prodp, up, size );
6082 else {
6083 mpi_ptr_t tspace;
6084 secure = m_is_secure( up );
6085 tspace = mpi_alloc_limb_space( 2 * size, secure );
6086 mpih_sqr_n( prodp, up, size, tspace );
6087 mpi_free_limb_space( tspace );
6088 }
6089 }
6090 else {
6091 if( size < KARATSUBA_THRESHOLD )
6092 mul_n_basecase( prodp, up, vp, size );
6093 else {
6094 mpi_ptr_t tspace;
6095 secure = m_is_secure( up ) || m_is_secure( vp );
6096 tspace = mpi_alloc_limb_space( 2 * size, secure );
6097 mul_n (prodp, up, vp, size, tspace);
6098 mpi_free_limb_space( tspace );
6099 }
6100 }
6101 }
6102
6103
6104
6105 void
6106 mpihelp_mul_karatsuba_case( mpi_ptr_t prodp,
6107 mpi_ptr_t up, mpi_size_t usize,
6108 mpi_ptr_t vp, mpi_size_t vsize,
6109 struct karatsuba_ctx *ctx )
6110 {
6111 mpi_limb_t cy;
6112
6113 if( !ctx->tspace || ctx->tspace_size < vsize ) {
6114 if( ctx->tspace )
6115 mpi_free_limb_space( ctx->tspace );
6116 ctx->tspace = mpi_alloc_limb_space( 2 * vsize,
6117 m_is_secure( up ) || m_is_secure( vp ) );
6118 ctx->tspace_size = vsize;
6119 }
6120
6121 MPN_MUL_N_RECURSE( prodp, up, vp, vsize, ctx->tspace );
6122
6123 prodp += vsize;
6124 up += vsize;
6125 usize -= vsize;
6126 if( usize >= vsize ) {
6127 if( !ctx->tp || ctx->tp_size < vsize ) {
6128 if( ctx->tp )
6129 mpi_free_limb_space( ctx->tp );
6130 ctx->tp = mpi_alloc_limb_space( 2 * vsize, m_is_secure( up )
6131 || m_is_secure( vp ) );
6132 ctx->tp_size = vsize;
6133 }
6134
6135 do {
6136 MPN_MUL_N_RECURSE( ctx->tp, up, vp, vsize, ctx->tspace );
6137 cy = mpihelp_add_n( prodp, prodp, ctx->tp, vsize );
6138 mpihelp_add_1( prodp + vsize, ctx->tp + vsize, vsize, cy );
6139 prodp += vsize;
6140 up += vsize;
6141 usize -= vsize;
6142 } while( usize >= vsize );
6143 }
6144
6145 if( usize ) {
6146 if( usize < KARATSUBA_THRESHOLD ) {
6147 mpihelp_mul( ctx->tspace, vp, vsize, up, usize );
6148 }
6149 else {
6150 if( !ctx->next ) {
6151 ctx->next = xmalloc_clear( sizeof *ctx );
6152 }
6153 mpihelp_mul_karatsuba_case( ctx->tspace,
6154 vp, vsize,
6155 up, usize,
6156 ctx->next );
6157 }
6158
6159 cy = mpihelp_add_n( prodp, prodp, ctx->tspace, vsize);
6160 mpihelp_add_1( prodp + vsize, ctx->tspace + vsize, usize, cy );
6161 }
6162 }
6163
6164
6165 void
6166 mpihelp_release_karatsuba_ctx( struct karatsuba_ctx *ctx )
6167 {
6168 struct karatsuba_ctx *ctx2;
6169
6170 if( ctx->tp )
6171 mpi_free_limb_space( ctx->tp );
6172 if( ctx->tspace )
6173 mpi_free_limb_space( ctx->tspace );
6174 for( ctx=ctx->next; ctx; ctx = ctx2 ) {
6175 ctx2 = ctx->next;
6176 if( ctx->tp )
6177 mpi_free_limb_space( ctx->tp );
6178 if( ctx->tspace )
6179 mpi_free_limb_space( ctx->tspace );
6180 xfree( ctx );
6181 }
6182 }
6183
6184 /* Multiply the natural numbers u (pointed to by UP, with USIZE limbs)
6185 * and v (pointed to by VP, with VSIZE limbs), and store the result at
6186 * PRODP. USIZE + VSIZE limbs are always stored, but if the input
6187 * operands are normalized. Return the most significant limb of the
6188 * result.
6189 *
6190 * NOTE: The space pointed to by PRODP is overwritten before finished
6191 * with U and V, so overlap is an error.
6192 *
6193 * Argument constraints:
6194 * 1. USIZE >= VSIZE.
6195 * 2. PRODP != UP and PRODP != VP, i.e. the destination
6196 * must be distinct from the multiplier and the multiplicand.
6197 */
6198
6199 mpi_limb_t
6200 mpihelp_mul( mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t usize,
6201 mpi_ptr_t vp, mpi_size_t vsize)
6202 {
6203 mpi_ptr_t prod_endp = prodp + usize + vsize - 1;
6204 mpi_limb_t cy;
6205 struct karatsuba_ctx ctx;
6206
6207 if( vsize < KARATSUBA_THRESHOLD ) {
6208 mpi_size_t i;
6209 mpi_limb_t v_limb;
6210
6211 if( !vsize )
6212 return 0;
6213
6214 /* Multiply by the first limb in V separately, as the result can be
6215 * stored (not added) to PROD. We also avoid a loop for zeroing. */
6216 v_limb = vp[0];
6217 if( v_limb <= 1 ) {
6218 if( v_limb == 1 )
6219 MPN_COPY( prodp, up, usize );
6220 else
6221 MPN_ZERO( prodp, usize );
6222 cy = 0;
6223 }
6224 else
6225 cy = mpihelp_mul_1( prodp, up, usize, v_limb );
6226
6227 prodp[usize] = cy;
6228 prodp++;
6229
6230 /* For each iteration in the outer loop, multiply one limb from
6231 * U with one limb from V, and add it to PROD. */
6232 for( i = 1; i < vsize; i++ ) {
6233 v_limb = vp[i];
6234 if( v_limb <= 1 ) {
6235 cy = 0;
6236 if( v_limb == 1 )
6237 cy = mpihelp_add_n(prodp, prodp, up, usize);
6238 }
6239 else
6240 cy = mpihelp_addmul_1(prodp, up, usize, v_limb);
6241
6242 prodp[usize] = cy;
6243 prodp++;
6244 }
6245
6246 return cy;
6247 }
6248
6249 memset( &ctx, 0, sizeof ctx );
6250 mpihelp_mul_karatsuba_case( prodp, up, usize, vp, vsize, &ctx );
6251 mpihelp_release_karatsuba_ctx( &ctx );
6252 return *prod_endp;
6253 }
6254
6255