Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F35336833
mpi-pow.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
9 KB
Subscribers
None
mpi-pow.c
View Options
/* mpi-pow.c - MPI functions for exponentiation
* Copyright (C) 1994, 1996, 1998, 2000, 2002
* 2003 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 <http://www.gnu.org/licenses/>.
*
* Note: This code is heavily based on the GNU MP Library.
* Actually it's the same code with only minor changes in the
* way the data is stored; this is to support the abstraction
* of an optional secure memory allocation which may be used
* to avoid revealing of sensitive data due to paging etc.
*/
#include
<config.h>
#include
<stdio.h>
#include
<stdlib.h>
#include
<string.h>
#include
"mpi-internal.h"
#include
"longlong.h"
/****************
* RES = BASE ^ EXPO mod MOD
*/
void
gcry_mpi_powm
(
gcry_mpi_t
res
,
gcry_mpi_t
base
,
gcry_mpi_t
expo
,
gcry_mpi_t
mod
)
{
/* Pointer to the limbs of the arguments, their size and signs. */
mpi_ptr_t
rp
,
ep
,
mp
,
bp
;
mpi_size_t
esize
,
msize
,
bsize
,
rsize
;
int
msign
,
bsign
,
rsign
;
/* Flags telling the secure allocation status of the arguments. */
int
esec
,
msec
,
bsec
,
rsec
;
/* Size of the result including space for temporary values. */
mpi_size_t
size
;
/* Helper. */
int
mod_shift_cnt
;
int
negative_result
;
mpi_ptr_t
mp_marker
=
NULL
;
mpi_ptr_t
bp_marker
=
NULL
;
mpi_ptr_t
ep_marker
=
NULL
;
mpi_ptr_t
xp_marker
=
NULL
;
unsigned
int
mp_nlimbs
=
0
;
unsigned
int
bp_nlimbs
=
0
;
unsigned
int
ep_nlimbs
=
0
;
unsigned
int
xp_nlimbs
=
0
;
mpi_ptr_t
tspace
=
NULL
;
mpi_size_t
tsize
=
0
;
esize
=
expo
->
nlimbs
;
msize
=
mod
->
nlimbs
;
size
=
2
*
msize
;
msign
=
mod
->
sign
;
esec
=
mpi_is_secure
(
expo
);
msec
=
mpi_is_secure
(
mod
);
bsec
=
mpi_is_secure
(
base
);
rsec
=
mpi_is_secure
(
res
);
rp
=
res
->
d
;
ep
=
expo
->
d
;
if
(
!
msize
)
msize
=
1
/
msize
;
/* Provoke a signal. */
if
(
!
esize
)
{
/* Exponent is zero, result is 1 mod MOD, i.e., 1 or 0 depending
on if MOD equals 1. */
rp
[
0
]
=
1
;
res
->
nlimbs
=
(
msize
==
1
&&
mod
->
d
[
0
]
==
1
)
?
0
:
1
;
res
->
sign
=
0
;
goto
leave
;
}
/* Normalize MOD (i.e. make its most significant bit set) as
required by mpn_divrem. This will make the intermediate values
in the calculation slightly larger, but the correct result is
obtained after a final reduction using the original MOD value. */
mp_nlimbs
=
msec
?
msize
:
0
;
mp
=
mp_marker
=
mpi_alloc_limb_space
(
msize
,
msec
);
count_leading_zeros
(
mod_shift_cnt
,
mod
->
d
[
msize
-1
]);
if
(
mod_shift_cnt
)
_gcry_mpih_lshift
(
mp
,
mod
->
d
,
msize
,
mod_shift_cnt
);
else
MPN_COPY
(
mp
,
mod
->
d
,
msize
);
bsize
=
base
->
nlimbs
;
bsign
=
base
->
sign
;
if
(
bsize
>
msize
)
{
/* The base is larger than the module. Reduce it.
Allocate (BSIZE + 1) with space for remainder and quotient.
(The quotient is (bsize - msize + 1) limbs.) */
bp_nlimbs
=
bsec
?
(
bsize
+
1
)
:
0
;
bp
=
bp_marker
=
mpi_alloc_limb_space
(
bsize
+
1
,
bsec
);
MPN_COPY
(
bp
,
base
->
d
,
bsize
);
/* We don't care about the quotient, store it above the
* remainder, at BP + MSIZE. */
_gcry_mpih_divrem
(
bp
+
msize
,
0
,
bp
,
bsize
,
mp
,
msize
);
bsize
=
msize
;
/* Canonicalize the base, since we are going to multiply with it
quite a few times. */
MPN_NORMALIZE
(
bp
,
bsize
);
}
else
bp
=
base
->
d
;
if
(
!
bsize
)
{
res
->
nlimbs
=
0
;
res
->
sign
=
0
;
goto
leave
;
}
/* Make BASE, EXPO and MOD not overlap with RES. */
if
(
rp
==
bp
)
{
/* RES and BASE are identical. Allocate temp. space for BASE. */
gcry_assert
(
!
bp_marker
);
bp_nlimbs
=
bsec
?
bsize
:
0
;
bp
=
bp_marker
=
mpi_alloc_limb_space
(
bsize
,
bsec
);
MPN_COPY
(
bp
,
rp
,
bsize
);
}
if
(
rp
==
ep
)
{
/* RES and EXPO are identical. Allocate temp. space for EXPO. */
ep_nlimbs
=
esec
?
esize
:
0
;
ep
=
ep_marker
=
mpi_alloc_limb_space
(
esize
,
esec
);
MPN_COPY
(
ep
,
rp
,
esize
);
}
if
(
rp
==
mp
)
{
/* RES and MOD are identical. Allocate temporary space for MOD.*/
gcry_assert
(
!
mp_marker
);
mp_nlimbs
=
msec
?
msize
:
0
;
mp
=
mp_marker
=
mpi_alloc_limb_space
(
msize
,
msec
);
MPN_COPY
(
mp
,
rp
,
msize
);
}
/* Copy base to the result. */
if
(
res
->
alloced
<
size
)
{
mpi_resize
(
res
,
size
);
rp
=
res
->
d
;
}
MPN_COPY
(
rp
,
bp
,
bsize
);
rsize
=
bsize
;
rsign
=
bsign
;
/* Main processing. */
{
mpi_size_t
i
;
mpi_ptr_t
xp
;
int
c
;
mpi_limb_t
e
;
mpi_limb_t
carry_limb
;
struct
karatsuba_ctx
karactx
;
xp_nlimbs
=
msec
?
(
2
*
(
msize
+
1
))
:
0
;
xp
=
xp_marker
=
mpi_alloc_limb_space
(
2
*
(
msize
+
1
),
msec
);
memset
(
&
karactx
,
0
,
sizeof
karactx
);
negative_result
=
(
ep
[
0
]
&
1
)
&&
base
->
sign
;
i
=
esize
-
1
;
e
=
ep
[
i
];
count_leading_zeros
(
c
,
e
);
e
=
(
e
<<
c
)
<<
1
;
/* Shift the expo bits to the left, lose msb. */
c
=
BITS_PER_MPI_LIMB
-
1
-
c
;
/* Main loop.
Make the result be pointed to alternately by XP and RP. This
helps us avoid block copying, which would otherwise be
necessary with the overlap restrictions of
_gcry_mpih_divmod. With 50% probability the result after this
loop will be in the area originally pointed by RP (==RES->d),
and with 50% probability in the area originally pointed to by XP. */
for
(;;)
{
while
(
c
)
{
mpi_ptr_t
tp
;
mpi_size_t
xsize
;
/*mpih_mul_n(xp, rp, rp, rsize);*/
if
(
rsize
<
KARATSUBA_THRESHOLD
)
_gcry_mpih_sqr_n_basecase
(
xp
,
rp
,
rsize
);
else
{
if
(
!
tspace
)
{
tsize
=
2
*
rsize
;
tspace
=
mpi_alloc_limb_space
(
tsize
,
0
);
}
else
if
(
tsize
<
(
2
*
rsize
)
)
{
_gcry_mpi_free_limb_space
(
tspace
,
0
);
tsize
=
2
*
rsize
;
tspace
=
mpi_alloc_limb_space
(
tsize
,
0
);
}
_gcry_mpih_sqr_n
(
xp
,
rp
,
rsize
,
tspace
);
}
xsize
=
2
*
rsize
;
if
(
xsize
>
msize
)
{
_gcry_mpih_divrem
(
xp
+
msize
,
0
,
xp
,
xsize
,
mp
,
msize
);
xsize
=
msize
;
}
tp
=
rp
;
rp
=
xp
;
xp
=
tp
;
rsize
=
xsize
;
if
(
(
mpi_limb_signed_t
)
e
<
0
)
{
/*mpih_mul( xp, rp, rsize, bp, bsize );*/
if
(
bsize
<
KARATSUBA_THRESHOLD
)
_gcry_mpih_mul
(
xp
,
rp
,
rsize
,
bp
,
bsize
);
else
_gcry_mpih_mul_karatsuba_case
(
xp
,
rp
,
rsize
,
bp
,
bsize
,
&
karactx
);
xsize
=
rsize
+
bsize
;
if
(
xsize
>
msize
)
{
_gcry_mpih_divrem
(
xp
+
msize
,
0
,
xp
,
xsize
,
mp
,
msize
);
xsize
=
msize
;
}
tp
=
rp
;
rp
=
xp
;
xp
=
tp
;
rsize
=
xsize
;
}
e
<<=
1
;
c
--
;
}
i
--
;
if
(
i
<
0
)
break
;
e
=
ep
[
i
];
c
=
BITS_PER_MPI_LIMB
;
}
/* We shifted MOD, the modulo reduction argument, left
MOD_SHIFT_CNT steps. Adjust the result by reducing it with the
original MOD.
Also make sure the result is put in RES->d (where it already
might be, see above). */
if
(
mod_shift_cnt
)
{
carry_limb
=
_gcry_mpih_lshift
(
res
->
d
,
rp
,
rsize
,
mod_shift_cnt
);
rp
=
res
->
d
;
if
(
carry_limb
)
{
rp
[
rsize
]
=
carry_limb
;
rsize
++
;
}
}
else
if
(
res
->
d
!=
rp
)
{
MPN_COPY
(
res
->
d
,
rp
,
rsize
);
rp
=
res
->
d
;
}
if
(
rsize
>=
msize
)
{
_gcry_mpih_divrem
(
rp
+
msize
,
0
,
rp
,
rsize
,
mp
,
msize
);
rsize
=
msize
;
}
/* Remove any leading zero words from the result. */
if
(
mod_shift_cnt
)
_gcry_mpih_rshift
(
rp
,
rp
,
rsize
,
mod_shift_cnt
);
MPN_NORMALIZE
(
rp
,
rsize
);
_gcry_mpih_release_karatsuba_ctx
(
&
karactx
);
}
/* Fixup for negative results. */
if
(
negative_result
&&
rsize
)
{
if
(
mod_shift_cnt
)
_gcry_mpih_rshift
(
mp
,
mp
,
msize
,
mod_shift_cnt
);
_gcry_mpih_sub
(
rp
,
mp
,
msize
,
rp
,
rsize
);
rsize
=
msize
;
rsign
=
msign
;
MPN_NORMALIZE
(
rp
,
rsize
);
}
gcry_assert
(
res
->
d
==
rp
);
res
->
nlimbs
=
rsize
;
res
->
sign
=
rsign
;
leave
:
if
(
mp_marker
)
_gcry_mpi_free_limb_space
(
mp_marker
,
mp_nlimbs
);
if
(
bp_marker
)
_gcry_mpi_free_limb_space
(
bp_marker
,
bp_nlimbs
);
if
(
ep_marker
)
_gcry_mpi_free_limb_space
(
ep_marker
,
ep_nlimbs
);
if
(
xp_marker
)
_gcry_mpi_free_limb_space
(
xp_marker
,
xp_nlimbs
);
if
(
tspace
)
_gcry_mpi_free_limb_space
(
tspace
,
0
);
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Fri, Feb 6, 8:09 AM (1 h, 35 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
c2/e7/f149cf3b22e86ebaa16f044fc9e4
Attached To
rC libgcrypt
Event Timeline
Log In to Comment