-
+ B320709B57B3CF0C00BC98277B037494C62FED93FD99BCA0412EA633F8662844D35ED62990CBE1FC02A47DEE5795D3A7B6B401440F6E80A8A00243868815C06A
mpi/mpi-div.c
(0 . 0)(1 . 321)
6646 /* mpi-div.c - MPI functions
6647 * Copyright (C) 1994, 1996 Free Software Foundation, Inc.
6648 * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
6649 *
6650 * This file is part of GnuPG.
6651 *
6652 * GnuPG is free software; you can redistribute it and/or modify
6653 * it under the terms of the GNU General Public License as published by
6654 * the Free Software Foundation; either version 3 of the License, or
6655 * (at your option) any later version.
6656 *
6657 * GnuPG is distributed in the hope that it will be useful,
6658 * but WITHOUT ANY WARRANTY; without even the implied warranty of
6659 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
6660 * GNU General Public License for more details.
6661 *
6662 * You should have received a copy of the GNU General Public License
6663 * along with this program; if not, see <http://www.gnu.org/licenses/>.
6664 *
6665 * Note: This code is heavily based on the GNU MP Library.
6666 * Actually it's the same code with only minor changes in the
6667 * way the data is stored; this is to support the abstraction
6668 * of an optional secure memory allocation which may be used
6669 * to avoid revealing of sensitive data due to paging etc.
6670 * The GNU MP Library itself is published under the LGPL;
6671 * however I decided to publish this code under the plain GPL.
6672 */
6673
6674 #include <config.h>
6675 #include <stdio.h>
6676 #include <stdlib.h>
6677 #include "mpi-internal.h"
6678 #include "longlong.h"
6679
6680
6681
6682 void
6683 mpi_fdiv_r( MPI rem, MPI dividend, MPI divisor )
6684 {
6685 int divisor_sign = divisor->sign;
6686 MPI temp_divisor = NULL;
6687
6688 /* We need the original value of the divisor after the remainder has been
6689 * preliminary calculated. We have to copy it to temporary space if it's
6690 * the same variable as REM. */
6691 if( rem == divisor ) {
6692 temp_divisor = mpi_copy( divisor );
6693 divisor = temp_divisor;
6694 }
6695
6696 mpi_tdiv_r( rem, dividend, divisor );
6697
6698 if( ((divisor_sign?1:0) ^ (dividend->sign?1:0)) && rem->nlimbs )
6699 mpi_add( rem, rem, divisor);
6700
6701 if( temp_divisor )
6702 mpi_free(temp_divisor);
6703 }
6704
6705
6706
6707 /****************
6708 * Division rounding the quotient towards -infinity.
6709 * The remainder gets the same sign as the denominator.
6710 * rem is optional
6711 */
6712
6713 ulong
6714 mpi_fdiv_r_ui( MPI rem, MPI dividend, ulong divisor )
6715 {
6716 mpi_limb_t rlimb;
6717
6718 rlimb = mpihelp_mod_1( dividend->d, dividend->nlimbs, divisor );
6719 if( rlimb && dividend->sign )
6720 rlimb = divisor - rlimb;
6721
6722 if( rem ) {
6723 rem->d[0] = rlimb;
6724 rem->nlimbs = rlimb? 1:0;
6725 }
6726 return rlimb;
6727 }
6728
6729
6730 void
6731 mpi_fdiv_q( MPI quot, MPI dividend, MPI divisor )
6732 {
6733 MPI tmp = mpi_alloc( mpi_get_nlimbs(quot) );
6734 mpi_fdiv_qr( quot, tmp, dividend, divisor);
6735 mpi_free(tmp);
6736 }
6737
6738 void
6739 mpi_fdiv_qr( MPI quot, MPI rem, MPI dividend, MPI divisor )
6740 {
6741 int divisor_sign = divisor->sign;
6742 MPI temp_divisor = NULL;
6743
6744 if( quot == divisor || rem == divisor ) {
6745 temp_divisor = mpi_copy( divisor );
6746 divisor = temp_divisor;
6747 }
6748
6749 mpi_tdiv_qr( quot, rem, dividend, divisor );
6750
6751 if( (divisor_sign ^ dividend->sign) && rem->nlimbs ) {
6752 mpi_sub_ui( quot, quot, 1 );
6753 mpi_add( rem, rem, divisor);
6754 }
6755
6756 if( temp_divisor )
6757 mpi_free(temp_divisor);
6758 }
6759
6760
6761 /* If den == quot, den needs temporary storage.
6762 * If den == rem, den needs temporary storage.
6763 * If num == quot, num needs temporary storage.
6764 * If den has temporary storage, it can be normalized while being copied,
6765 * i.e no extra storage should be allocated.
6766 */
6767
6768 void
6769 mpi_tdiv_r( MPI rem, MPI num, MPI den)
6770 {
6771 mpi_tdiv_qr(NULL, rem, num, den );
6772 }
6773
6774 void
6775 mpi_tdiv_qr( MPI quot, MPI rem, MPI num, MPI den)
6776 {
6777 mpi_ptr_t np, dp;
6778 mpi_ptr_t qp, rp;
6779 mpi_size_t nsize = num->nlimbs;
6780 mpi_size_t dsize = den->nlimbs;
6781 mpi_size_t qsize, rsize;
6782 mpi_size_t sign_remainder = num->sign;
6783 mpi_size_t sign_quotient = num->sign ^ den->sign;
6784 unsigned normalization_steps;
6785 mpi_limb_t q_limb;
6786 mpi_ptr_t marker[5];
6787 int markidx=0;
6788
6789 /* Ensure space is enough for quotient and remainder.
6790 * We need space for an extra limb in the remainder, because it's
6791 * up-shifted (normalized) below. */
6792 rsize = nsize + 1;
6793 mpi_resize( rem, rsize);
6794
6795 qsize = rsize - dsize; /* qsize cannot be bigger than this. */
6796 if( qsize <= 0 ) {
6797 if( num != rem ) {
6798 rem->nlimbs = num->nlimbs;
6799 rem->sign = num->sign;
6800 MPN_COPY(rem->d, num->d, nsize);
6801 }
6802 if( quot ) {
6803 /* This needs to follow the assignment to rem, in case the
6804 * numerator and quotient are the same. */
6805 quot->nlimbs = 0;
6806 quot->sign = 0;
6807 }
6808 return;
6809 }
6810
6811 if( quot )
6812 mpi_resize( quot, qsize);
6813
6814 /* Read pointers here, when reallocation is finished. */
6815 np = num->d;
6816 dp = den->d;
6817 rp = rem->d;
6818
6819 /* Optimize division by a single-limb divisor. */
6820 if( dsize == 1 ) {
6821 mpi_limb_t rlimb;
6822 if( quot ) {
6823 qp = quot->d;
6824 rlimb = mpihelp_divmod_1( qp, np, nsize, dp[0] );
6825 qsize -= qp[qsize - 1] == 0;
6826 quot->nlimbs = qsize;
6827 quot->sign = sign_quotient;
6828 }
6829 else
6830 rlimb = mpihelp_mod_1( np, nsize, dp[0] );
6831 rp[0] = rlimb;
6832 rsize = rlimb != 0?1:0;
6833 rem->nlimbs = rsize;
6834 rem->sign = sign_remainder;
6835 return;
6836 }
6837
6838
6839 if( quot ) {
6840 qp = quot->d;
6841 /* Make sure QP and NP point to different objects. Otherwise the
6842 * numerator would be gradually overwritten by the quotient limbs. */
6843 if(qp == np) { /* Copy NP object to temporary space. */
6844 np = marker[markidx++] = mpi_alloc_limb_space(nsize,
6845 mpi_is_secure(quot));
6846 MPN_COPY(np, qp, nsize);
6847 }
6848 }
6849 else /* Put quotient at top of remainder. */
6850 qp = rp + dsize;
6851
6852 count_leading_zeros( normalization_steps, dp[dsize - 1] );
6853
6854 /* Normalize the denominator, i.e. make its most significant bit set by
6855 * shifting it NORMALIZATION_STEPS bits to the left. Also shift the
6856 * numerator the same number of steps (to keep the quotient the same!).
6857 */
6858 if( normalization_steps ) {
6859 mpi_ptr_t tp;
6860 mpi_limb_t nlimb;
6861
6862 /* Shift up the denominator setting the most significant bit of
6863 * the most significant word. Use temporary storage not to clobber
6864 * the original contents of the denominator. */
6865 tp = marker[markidx++] = mpi_alloc_limb_space(dsize,mpi_is_secure(den));
6866 mpihelp_lshift( tp, dp, dsize, normalization_steps );
6867 dp = tp;
6868
6869 /* Shift up the numerator, possibly introducing a new most
6870 * significant word. Move the shifted numerator in the remainder
6871 * meanwhile. */
6872 nlimb = mpihelp_lshift(rp, np, nsize, normalization_steps);
6873 if( nlimb ) {
6874 rp[nsize] = nlimb;
6875 rsize = nsize + 1;
6876 }
6877 else
6878 rsize = nsize;
6879 }
6880 else {
6881 /* The denominator is already normalized, as required. Copy it to
6882 * temporary space if it overlaps with the quotient or remainder. */
6883 if( dp == rp || (quot && (dp == qp))) {
6884 mpi_ptr_t tp;
6885
6886 tp = marker[markidx++] = mpi_alloc_limb_space(dsize, mpi_is_secure(den));
6887 MPN_COPY( tp, dp, dsize );
6888 dp = tp;
6889 }
6890
6891 /* Move the numerator to the remainder. */
6892 if( rp != np )
6893 MPN_COPY(rp, np, nsize);
6894
6895 rsize = nsize;
6896 }
6897
6898 q_limb = mpihelp_divrem( qp, 0, rp, rsize, dp, dsize );
6899
6900 if( quot ) {
6901 qsize = rsize - dsize;
6902 if(q_limb) {
6903 qp[qsize] = q_limb;
6904 qsize += 1;
6905 }
6906
6907 quot->nlimbs = qsize;
6908 quot->sign = sign_quotient;
6909 }
6910
6911 rsize = dsize;
6912 MPN_NORMALIZE (rp, rsize);
6913
6914 if( normalization_steps && rsize ) {
6915 mpihelp_rshift(rp, rp, rsize, normalization_steps);
6916 rsize -= rp[rsize - 1] == 0?1:0;
6917 }
6918
6919 rem->nlimbs = rsize;
6920 rem->sign = sign_remainder;
6921 while( markidx )
6922 mpi_free_limb_space(marker[--markidx]);
6923 }
6924
6925 void
6926 mpi_tdiv_q_2exp( MPI w, MPI u, unsigned count )
6927 {
6928 mpi_size_t usize, wsize;
6929 mpi_size_t limb_cnt;
6930
6931 usize = u->nlimbs;
6932 limb_cnt = count / BITS_PER_MPI_LIMB;
6933 wsize = usize - limb_cnt;
6934 if( limb_cnt >= usize )
6935 w->nlimbs = 0;
6936 else {
6937 mpi_ptr_t wp;
6938 mpi_ptr_t up;
6939
6940 RESIZE_IF_NEEDED( w, wsize );
6941 wp = w->d;
6942 up = u->d;
6943
6944 count %= BITS_PER_MPI_LIMB;
6945 if( count ) {
6946 mpihelp_rshift( wp, up + limb_cnt, wsize, count );
6947 wsize -= !wp[wsize - 1];
6948 }
6949 else {
6950 MPN_COPY_INCR( wp, up + limb_cnt, wsize);
6951 }
6952
6953 w->nlimbs = wsize;
6954 }
6955 }
6956
6957 /****************
6958 * Check whether dividend is divisible by divisor
6959 * (note: divisor must fit into a limb)
6960 */
6961 int
6962 mpi_divisible_ui(MPI dividend, ulong divisor )
6963 {
6964 return !mpihelp_mod_1( dividend->d, dividend->nlimbs, divisor );
6965 }
6966