1/* SPDX-License-Identifier: GPL-2.0-or-later */
2/* mpi-inline.h  -  Internal to the Multi Precision Integers
3 *	Copyright (C) 1994, 1996, 1998, 1999 Free Software Foundation, Inc.
4 *
5 * This file is part of GnuPG.
6 *
7 * Note: This code is heavily based on the GNU MP Library.
8 *	 Actually it's the same code with only minor changes in the
9 *	 way the data is stored; this is to support the abstraction
10 *	 of an optional secure memory allocation which may be used
11 *	 to avoid revealing of sensitive data due to paging etc.
12 *	 The GNU MP Library itself is published under the LGPL;
13 *	 however I decided to publish this code under the plain GPL.
14 */
15
16#ifndef G10_MPI_INLINE_H
17#define G10_MPI_INLINE_H
18
19#ifndef G10_MPI_INLINE_DECL
20#define G10_MPI_INLINE_DECL  static inline
21#endif
22
23G10_MPI_INLINE_DECL mpi_limb_t
24mpihelp_add_1(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
25	      mpi_size_t s1_size, mpi_limb_t s2_limb)
26{
27	mpi_limb_t x;
28
29	x = *s1_ptr++;
30	s2_limb += x;
31	*res_ptr++ = s2_limb;
32	if (s2_limb < x) {	/* sum is less than the left operand: handle carry */
33		while (--s1_size) {
34			x = *s1_ptr++ + 1;	/* add carry */
35			*res_ptr++ = x;	/* and store */
36			if (x)	/* not 0 (no overflow): we can stop */
37				goto leave;
38		}
39		return 1;	/* return carry (size of s1 to small) */
40	}
41
42leave:
43	if (res_ptr != s1_ptr) {	/* not the same variable */
44		mpi_size_t i;	/* copy the rest */
45		for (i = 0; i < s1_size - 1; i++)
46			res_ptr[i] = s1_ptr[i];
47	}
48	return 0;		/* no carry */
49}
50
51G10_MPI_INLINE_DECL mpi_limb_t
52mpihelp_add(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, mpi_size_t s1_size,
53	    mpi_ptr_t s2_ptr, mpi_size_t s2_size)
54{
55	mpi_limb_t cy = 0;
56
57	if (s2_size)
58		cy = mpihelp_add_n(res_ptr, s1_ptr, s2_ptr, s2_size);
59
60	if (s1_size - s2_size)
61		cy = mpihelp_add_1(res_ptr + s2_size, s1_ptr + s2_size,
62				   s1_size - s2_size, cy);
63	return cy;
64}
65
66G10_MPI_INLINE_DECL mpi_limb_t
67mpihelp_sub_1(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
68	      mpi_size_t s1_size, mpi_limb_t s2_limb)
69{
70	mpi_limb_t x;
71
72	x = *s1_ptr++;
73	s2_limb = x - s2_limb;
74	*res_ptr++ = s2_limb;
75	if (s2_limb > x) {
76		while (--s1_size) {
77			x = *s1_ptr++;
78			*res_ptr++ = x - 1;
79			if (x)
80				goto leave;
81		}
82		return 1;
83	}
84
85leave:
86	if (res_ptr != s1_ptr) {
87		mpi_size_t i;
88		for (i = 0; i < s1_size - 1; i++)
89			res_ptr[i] = s1_ptr[i];
90	}
91	return 0;
92}
93
94G10_MPI_INLINE_DECL mpi_limb_t
95mpihelp_sub(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, mpi_size_t s1_size,
96	    mpi_ptr_t s2_ptr, mpi_size_t s2_size)
97{
98	mpi_limb_t cy = 0;
99
100	if (s2_size)
101		cy = mpihelp_sub_n(res_ptr, s1_ptr, s2_ptr, s2_size);
102
103	if (s1_size - s2_size)
104		cy = mpihelp_sub_1(res_ptr + s2_size, s1_ptr + s2_size,
105				   s1_size - s2_size, cy);
106	return cy;
107}
108
109#endif /*G10_MPI_INLINE_H */
110