libmp.h


1
#ifndef LIBMP_H
2
#define LIBMP_H
3
4
#include <stdint.h>
5
#include <avr/pgmspace.h>
6
7
#define R_NUM   "r24"
8
#define R_CARRY "r25"
9
10
#define mp_add(N, A, B)         mp_adc (N, A, B, 0)
11
#define mp_lsl(N, A)            mp_rol (N, A, 0)
12
#define mp_lsr(N, A)            mp_ror (N, A, 0)
13
14
#define MP_INLINE __inline__ __attribute__((__always_inline__))
15
16
typedef struct
17
{
18
    uint8_t mask;
19
    uint8_t offset;
20
} mp_msb_t;
21
22
extern void mp_adc_asm (void);
23
extern void mp_ror_asm (void);
24
extern void mp_rol_asm (void);
25
extern void mp_rol8_asm (void);
26
extern void mp_sub_asm (void);
27
extern void mp_cmp_asm (void);
28
extern void mp_add0_asm (void);
29
extern void mp_sub0_asm (void);
30
extern void mp_set0_asm (void);
31
extern void mp_and_asm (void);
32
extern void mp_com_asm (void);
33
extern void mp_msb_asm (void);
34
extern void mp_copy_asm (void);
35
extern void mp_push_digit_asm (void);
36
37
extern void mp_out_hex (uint8_t, uint8_t*);
38
extern void mp_out_bin (uint8_t, const uint8_t*);
39
extern void mp_out_dec (uint8_t, const uint8_t*, uint8_t);
40
extern void mp_from_string (uint8_t, uint8_t*, const char*);
41
extern uint8_t mp_pop_digit (uint8_t, uint8_t*, uint8_t);
42
extern void mp_udivmod (uint8_t, uint8_t*, uint8_t*);
43
extern void mp_udivmod_1 (uint8_t, uint8_t*, uint8_t*, uint8_t);
44
extern void mp_mod (uint8_t, uint8_t*, const uint8_t*);
45
extern void mp_add_m (uint8_t, uint8_t*, const uint8_t*, const uint8_t*);
46
extern void mp_mul_m (uint8_t, uint8_t*, const uint8_t*, const uint8_t*);
47
extern void mp_mul2_m (uint8_t, uint8_t*, const uint8_t*);
48
extern void mp_exp_m (uint8_t, uint8_t*, const uint8_t*, const uint8_t*);
49
50
static MP_INLINE
51
uint8_t mp_udivmod0 (uint8_t n, uint8_t *a, uint8_t divisor)
52
{
53
    return mp_pop_digit (n, a, divisor);
54
}
55
56
extern uint8_t mp_zero_p;
57
58
static MP_INLINE
59
void mp_copy_P (uint8_t n, uint8_t *a, const __flash uint8_t *b)
60
{
61
    struct S { uint8_t a[n]; };
62
    * (struct S*) a = * (const __flash struct S*) b;
63
}
64
65
static MP_INLINE
66
uint8_t mp_getbit (uint8_t *a, unsigned bit)
67
{
68
    uint8_t val = a[bit >> 3];
69
    uint8_t bit8 = bit & 7;
70
    val >>= bit8;
71
    val &= 1;
72
    return val;
73
}
74
75
76
static MP_INLINE
77
uint8_t mp_adc (uint8_t n, uint8_t *a, const uint8_t *b, uint8_t carry)
78
{
79
    register uint8_t rn asm (R_NUM) = n;
80
    register uint8_t *ra asm ("r26") = a;
81
    register const uint8_t *rb asm ("r30") = b;
82
    register uint8_t rcarry asm (R_CARRY) = carry;
83
    asm volatile ("%~call %x[f]"
84
        : "+r" (rcarry)
85
        : [f] "s" (mp_adc_asm), "r" (rn), "r" (ra), "r" (rb)
86
        : "memory");
87
        
88
    return rcarry;
89
}
90
91
static MP_INLINE
92
uint8_t mp_add0 (uint8_t n, uint8_t *a, int8_t val)
93
{
94
    register uint8_t rn asm (R_NUM) = n;
95
    register uint8_t *ra asm ("r26") = a;
96
    register int8_t rcarry asm ("r25") = val;
97
    asm volatile ("%~call %x[f]"
98
        : "+r" (rcarry)
99
        : [f] "s" (mp_add0_asm), "r" (rn), "r" (ra)
100
        : "memory");
101
    if (val < 0)
102
        rcarry ^= 1;
103
    return rcarry;
104
}
105
106
107
static MP_INLINE
108
uint8_t mp_rol8 (uint8_t n, uint8_t *a, uint8_t val)
109
{
110
    register uint8_t rn asm (R_NUM) = n;
111
    register uint8_t *ra asm ("r26") = a;
112
    register uint8_t rval asm ("r25") = val;
113
    asm volatile ("%~call %x[f]"
114
        : "+r" (rval)
115
        : [f] "s" (mp_rol8_asm), "r" (rn), "r" (ra)
116
        : "memory");
117
118
    return rval;
119
}
120
121
static MP_INLINE
122
uint8_t mp_and (uint8_t n, uint8_t *a, const uint8_t *b)
123
{
124
    register uint8_t rn asm (R_NUM) = n;
125
    register uint8_t *ra asm ("r26") = a;
126
    register const uint8_t *rb asm ("r30") = b;
127
    register uint8_t rnonzero_p asm ("r25");
128
    asm volatile ("%~call %x[f]"
129
        : "=r" (rnonzero_p)
130
        : [f] "s" (mp_and_asm), "r" (rn), "r" (ra), "r" (rb)
131
        : "memory");
132
        
133
    return rnonzero_p;
134
}
135
136
static MP_INLINE
137
void mp_com (uint8_t n, uint8_t *a)
138
{
139
    register uint8_t rn asm (R_NUM) = n;
140
    register uint8_t *ra asm ("r26") = a;
141
    asm volatile ("%~call %x[f]"
142
        :
143
        : [f] "s" (mp_com_asm), "r" (rn), "r" (ra)
144
        : "memory");
145
}
146
147
static MP_INLINE
148
void mp_neg (uint8_t n, uint8_t *a)
149
{
150
    mp_add0 (n, a, -1);
151
    mp_com (n, a);
152
}
153
154
static MP_INLINE
155
void mp_set0 (uint8_t n, uint8_t *a, int8_t val)
156
{
157
    register uint8_t rn asm (R_NUM) = n;
158
    register uint8_t *ra asm ("r26") = a;
159
    register uint8_t rval asm ("r25") = val;
160
    asm volatile ("%~call %x[f]"
161
        : "+r" (rval)
162
        : [f] "s" (mp_set0_asm), "r" (rn), "r" (ra)
163
        : "memory");
164
}
165
166
static MP_INLINE
167
uint8_t mp_ror (uint8_t n, uint8_t *a, uint8_t carry)
168
{
169
    register uint8_t rn asm (R_NUM) = n;
170
    register uint8_t *ra asm ("r26") = a;
171
    register uint8_t rcarry asm (R_CARRY) = carry;
172
    asm volatile ("%~call %x[f]"
173
        : "+r" (rcarry)
174
        : [f] "s" (mp_ror_asm), "r" (rn), "r" (ra)
175
        : "memory");
176
        
177
    return rcarry;
178
}
179
180
static MP_INLINE
181
uint8_t mp_rol (uint8_t n, uint8_t *a, uint8_t carry)
182
{
183
    register uint8_t rn asm (R_NUM) = n;
184
    register uint8_t *ra asm ("r26") = a;
185
    register uint8_t rcarry asm (R_CARRY) = carry;
186
    asm volatile ("%~call %x[f]"
187
        : "+r" (rcarry)
188
        : [f] "s" (mp_rol_asm), "r" (rn), "r" (ra)
189
        : "memory");
190
        
191
    return rcarry;
192
}
193
194
static MP_INLINE
195
void mp_sub (uint8_t n, uint8_t *a, const uint8_t *b)
196
{
197
    register uint8_t rn asm (R_NUM) = n;
198
    register uint8_t *ra asm ("r26") = a;
199
    register const uint8_t *rb asm ("r30") = b;
200
    asm volatile ("%~call %x[f]"
201
        :
202
        : [f] "s" (mp_sub_asm), "r" (rn), "r" (ra), "r" (rb)
203
        : "25", "memory");
204
}
205
206
static MP_INLINE
207
int8_t mp_cmp (uint8_t n, const uint8_t *a, const uint8_t *b, uint8_t signed_p)
208
{
209
    register uint8_t rn asm (R_NUM) = n;
210
    register const uint8_t *ra asm ("r26") = a;
211
    register const uint8_t *rb asm ("r30") = b;
212
    register uint8_t rs asm ("r25") = signed_p;
213
    asm volatile ("%~call %x[f]"
214
        : "+r" (rs), "+r" (ra), "+r" (rb)
215
        : [f] "s" (mp_cmp_asm), "r" (rn)
216
        );
217
    return rs;
218
}
219
220
static MP_INLINE
221
mp_msb_t mp_msb (uint8_t n, const uint8_t *a)
222
{
223
    register uint8_t rn asm (R_NUM) = n;
224
    register const uint8_t *ra asm ("r26") = a;
225
    register mp_msb_t rmsb asm ("r22");
226
    asm volatile ("%~call %x[f]"
227
        : "=r" (rmsb)
228
        : [f] "s" (mp_msb_asm), "r" (rn), "r" (ra)
229
        );
230
    return rmsb;
231
}
232
233
234
static MP_INLINE
235
uint8_t mp_push_digit (uint8_t n, uint8_t *a, uint8_t b, uint8_t d)
236
{
237
    register uint8_t rn asm (R_NUM) = n;
238
    register uint8_t *ra asm ("r26") = a;
239
    register uint8_t rb asm ("r22") = b;
240
    register uint8_t rd asm ("r25") = d;
241
    asm volatile ("%~call %x[f]"
242
        : "+r" (rd)
243
        : [f] "s" (mp_push_digit_asm), "r" (rn), "r" (ra), "r" (rb)
244
        : "memory");
245
246
    return rd;
247
}
248
249
static MP_INLINE
250
void mp_copy (uint8_t n, uint8_t *a, const uint8_t *b)
251
{
252
    register uint8_t rn asm (R_NUM) = n;
253
    register uint8_t *ra asm ("r26") = a;
254
    register const uint8_t *rb asm ("r30") = b;
255
    asm volatile ("%~call %x[f]"
256
        :
257
        : [f] "s" (mp_copy_asm), "r" (rn), "r" (ra), "r" (rb)
258
        : "memory");
259
}
260
261
262
static MP_INLINE
263
void mp_add0_m (uint8_t n, uint8_t *a, int8_t b, const uint8_t *m)
264
{
265
    uint8_t carry = mp_add0 (n, a, b);
266
    
267
    if (b >= 0)
268
    {
269
        if (carry || mp_cmp (n, a, m, 0) >= 0)
270
        {
271
            mp_sub (n, a, m);
272
        }
273
    }
274
    else if (carry)
275
    {
276
        mp_add (n, a, m);
277
    }
278
}
279
280
#endif