work in progress; to be tidied and fixed
[u/mdw/putty] / bn-internal.h
CommitLineData
f85d8186
MW
1/*
2 * Internals details of the bignum representation.
3 */
4
5#ifndef PUTTY_BN_INTERNAL_H
6#define PUTTY_BN_INTERNAL_H
7
8/*
9 * Usage notes:
10 * * Do not call the DIVMOD_WORD macro with expressions such as array
11 * subscripts, as some implementations object to this (see below).
12 * * Note that none of the division methods below will cope if the
13 * quotient won't fit into BIGNUM_INT_BITS. Callers should be careful
14 * to avoid this case.
15 * If this condition occurs, in the case of the x86 DIV instruction,
16 * an overflow exception will occur, which (according to a correspondent)
17 * will manifest on Windows as something like
18 * 0xC0000095: Integer overflow
19 * The C variant won't give the right answer, either.
20 */
21
22#if defined __GNUC__ && defined __i386__
23typedef unsigned long BignumInt;
24typedef unsigned long long BignumDblInt;
25#define BIGNUM_INT_MASK 0xFFFFFFFFUL
26#define BIGNUM_TOP_BIT 0x80000000UL
27#define BIGNUM_INT_BITS 32
28#define MUL_WORD(w1, w2) ((BignumDblInt)w1 * w2)
29#define DIVMOD_WORD(q, r, hi, lo, w) \
30 __asm__("div %2" : \
31 "=d" (r), "=a" (q) : \
32 "r" (w), "d" (hi), "a" (lo))
33#elif defined _MSC_VER && defined _M_IX86
34typedef unsigned __int32 BignumInt;
35typedef unsigned __int64 BignumDblInt;
36#define BIGNUM_INT_MASK 0xFFFFFFFFUL
37#define BIGNUM_TOP_BIT 0x80000000UL
38#define BIGNUM_INT_BITS 32
39#define MUL_WORD(w1, w2) ((BignumDblInt)w1 * w2)
40/* Note: MASM interprets array subscripts in the macro arguments as
41 * assembler syntax, which gives the wrong answer. Don't supply them.
42 * <http://msdn2.microsoft.com/en-us/library/bf1dw62z.aspx> */
43#define DIVMOD_WORD(q, r, hi, lo, w) do { \
44 __asm mov edx, hi \
45 __asm mov eax, lo \
46 __asm div w \
47 __asm mov r, edx \
48 __asm mov q, eax \
49} while(0)
50#elif defined _LP64
51/* 64-bit architectures can do 32x32->64 chunks at a time */
52typedef unsigned int BignumInt;
53typedef unsigned long BignumDblInt;
54#define BIGNUM_INT_MASK 0xFFFFFFFFU
55#define BIGNUM_TOP_BIT 0x80000000U
56#define BIGNUM_INT_BITS 32
57#define MUL_WORD(w1, w2) ((BignumDblInt)w1 * w2)
58#define DIVMOD_WORD(q, r, hi, lo, w) do { \
59 BignumDblInt n = (((BignumDblInt)hi) << BIGNUM_INT_BITS) | lo; \
60 q = n / w; \
61 r = n % w; \
62} while (0)
63#elif defined _LLP64
64/* 64-bit architectures in which unsigned long is 32 bits, not 64 */
65typedef unsigned long BignumInt;
66typedef unsigned long long BignumDblInt;
67#define BIGNUM_INT_MASK 0xFFFFFFFFUL
68#define BIGNUM_TOP_BIT 0x80000000UL
69#define BIGNUM_INT_BITS 32
70#define MUL_WORD(w1, w2) ((BignumDblInt)w1 * w2)
71#define DIVMOD_WORD(q, r, hi, lo, w) do { \
72 BignumDblInt n = (((BignumDblInt)hi) << BIGNUM_INT_BITS) | lo; \
73 q = n / w; \
74 r = n % w; \
75} while (0)
76#else
77/* Fallback for all other cases */
78typedef unsigned short BignumInt;
79typedef unsigned long BignumDblInt;
80#define BIGNUM_INT_MASK 0xFFFFU
81#define BIGNUM_TOP_BIT 0x8000U
82#define BIGNUM_INT_BITS 16
83#define MUL_WORD(w1, w2) ((BignumDblInt)w1 * w2)
84#define DIVMOD_WORD(q, r, hi, lo, w) do { \
85 BignumDblInt n = (((BignumDblInt)hi) << BIGNUM_INT_BITS) | lo; \
86 q = n / w; \
87 r = n % w; \
88} while (0)
89#endif
90
91#define BIGNUM_INT_BYTES (BIGNUM_INT_BITS / 8)
92
93#define BIGNUM_INTERNAL
94typedef BignumInt *Bignum;
95
96#endif