bee2-rs 0.2.3

Bindings for cryptographic library Bee2
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
/*
*******************************************************************************
\file zz.h
\brief Multiple-precision unsigned integers
\project bee2 [cryptographic library]
\created 2012.04.22
\version 2023.09.23
\copyright The Bee2 authors
\license Licensed under the Apache License, Version 2.0 (see LICENSE.txt).
*******************************************************************************
*/

/*!
*******************************************************************************
\file zz.h
\brief Большие неотрицательные целые числа
*******************************************************************************
*/

#ifndef __ZZ_H
#define __ZZ_H

#include "bee2/defs.h"
#include "bee2/core/safe.h"

#ifdef __cplusplus
extern "C" {
#endif

/*!
*******************************************************************************
\file zz.h	

\section zz-common Общие положения

Реализованы операции с большими неотрицательными целыми числами.

Число задается массивом машинных слов: word w[n]. Машинное слово w[0] --
младшее, машинное слово w[n - 1] -- старшее.

Пустое число (n = 0) считается нулевым.

В описаниях функций B = 2^{B_PER_W} --- основание системы счисления.

Функция zzDoubleMod() совместно с функциями zzAddMod() и zzSubMod()
позволяет организовать быстрое модулярное умножение числа на малую
константу. Например, вычисление b <- 7 a \mod mod может быть организовано
следующим образом:
\code
	zzDoubleMod(b, a, mod, n);
	zzDoubleMod(b, b, mod, n);
	zzDoubleMod(b, b, mod, n);
	zzSubMod(b, a, mod, n);
\endcode
Аналогично, функция zzHalfMod() позволяет организовать быстрое модулярное
деление на определенные константы.

\pre Все входные указатели действительны.

\pre В функциях работы с числами по адресам памяти для чисел
зарезервировано ясное из конекста либо уточняемое в описаниях функций
число машинных слов.

\pre Вспомогательный буфер stack не пересекается с другими буферами.
*******************************************************************************
*/

/*
*******************************************************************************
Свойства
*******************************************************************************
*/

/*!	\brief Четное число?

	Проверяется, что число [n]a является четным.
	\return Признак четности.
*/
bool_t zzIsEven(
	const word a[],		/*!< [in] число */
	size_t n			/*!< [in] длина a в машинных словах */
);

/*!	\brief Нечетное число?

	Проверяется, что число [n]a является нечетным.
	\return Признак нечетности.
*/
bool_t zzIsOdd(
	const word a[],		/*!< [in] число */
	size_t n			/*!< [in] длина a в машинных словах */
);

/*
*******************************************************************************
Аддитивные операции
*******************************************************************************
*/

/*!	\brief Сложение чисел

	Определяется сумма [n]с чисел [n]a и [n]b:
	\code
		c <- (a + b) \mod B^n, carry <- (a + b) \div B^n,
		c + B^n * carry == a + b.
	\endcode
	\pre Буфер c либо не пересекается, либо совпадает с каждым из буферов a, b.
	\return Слово переноса carry.
*/
word zzAdd(
	word c[],			/*!< [out] сумма */
	const word a[],		/*!< [in] первое слагаемое */
	const word b[],		/*!< [in] второе слагаемое */
	size_t n			/*!< [in] длина a, b в машинных словах */
);

/*!	\brief Добавление числа

	К числу [n]b добавляется число [n]a:
	\code
		b <- (a + b) \mod B^n, carry <- (a + b) \div B^n.
	\endcode
	\pre Буфер b либо не пересекается, либо совпадает с буфером a.
	\return Слово переноса carry.
*/
word zzAdd2(
	word b[],			/*!< [in,out] первое слагаемое / сумма */
	const word a[],		/*!< [in] второе слагаемое */
	size_t n			/*!< [in] длина a, b в машинных словах */
);

/*!	\brief Сложение чисел проивольной длины

	Определяется сумма [max(n, m)]с чисел [n]a и [m]b:
	\code
		c <- (a + b) \mod B^{max(n,m)}, carry <- (a + b) \div B^{max(n,m)}.
	\endcode
	\pre Буфер c либо не пересекается, либо совпадает с каждым из буферов a, b.
	\return Слово переноса carry.
*/
word zzAdd3(
	word c[],			/*!< [out] сумма */
	const word a[],		/*!< [in] первое слагаемое */
	size_t n,			/*!< [in] длина a в машинных словах */
	const word b[],		/*!< [in] второе слагаемое */
	size_t m			/*!< [in] длина b в машинных словах */
);

/*!	\brief Сложение числа со словом

	Определяется сумма [n]b числа [n]a и слова w:
	\code
		b <- (a + w) \mod B^n, carry <- (a + w) \div B^n.
	\endcode
	\pre Буфер b либо не пересекается, либо совпадает с буфером a.
	\return Слово переноса carry.
*/
word zzAddW(
	word b[],			/*!< [out] сумма */
	const word a[],		/*!< [in] первое слагаемое */
	size_t n,			/*!< [in] длина a в машинных словах */
	register word w		/*!< [in] второе слагаемое */
);

/*!	\brief Добавление слова

	К числу [n]a добавляется слово w:
	\code
		a <- (a + w) \mod B^n, carry <- (a + w) \div B^n.
	\endcode
	\return Слово переноса carry.
*/
word zzAddW2(
	word a[],			/*!< [in,out] слагаемое / сумма */
	size_t n,			/*!< [in] длина a в машинных словах */
	register word w		/*!< [in] второе слагаемое */
);

/*!	\brief Сумма чисел равняется числу?

	Проверяется, что сумма чисел [n]a и [n]b равняется числу [n]c:
	\code
		a + b == c?
	\endcode
	\remark Переставляя операнды, можно проверять не только суммы,
	но и разности.
	\return Признак равенства.
	\safe Имеется ускоренная нерегулярная редакция.
*/
bool_t zzIsSumEq(
	const word c[],		/*!< [in] сумма */
	const word a[],		/*!< [in] первое слагаемое */
	const word b[],		/*!< [in] второе слагаемое */
	size_t n			/*!< [in] длина a, b, c в машинных словах */
);

bool_t SAFE(zzIsSumEq)(const word c[], const word a[], const word b[],
	size_t n);
bool_t FAST(zzIsSumEq)(const word c[], const word a[], const word b[],
	size_t n);

/*!	\brief Сумма числа и слова равняется числу?

	Проверяется, что сумма числа [n]a и слова w равняется числу [n]b:
	\code
		a + w == b?
	\endcode
	\return Признак равенства.
	\safe Имеется ускоренная нерегулярная редакция.
*/
bool_t zzIsSumWEq(
	const word b[],		/*!< [in] сумма */
	const word a[],		/*!< [in] первое слагаемое */
	size_t n,			/*!< [in] длина a, b в машинных словах */
	register word w		/*!< [in] второе слагаемое */
);

bool_t SAFE(zzIsSumWEq)(const word b[], const word a[], size_t n,
	register word w);
bool_t FAST(zzIsSumWEq)(const word b[], const word a[], size_t n,
	register word w);

/*!	\brief Вычитание чисел

	Определяется разность [n]c чисел [n]a и [n]b:
	\code
		c <- (a - b) \mod B^n, borrow <- (a < b),
		c - B^n * borrow == a - b.
	\endcode
	\pre Буфер c либо не пересекается, либо совпадает с каждым из буферов a, b.
	\return Слово заема borrow.
*/
word zzSub(
	word c[],			/*!< [out] разность */
	const word a[],		/*!< [in] уменьшаемое */
	const word b[],		/*!< [in] вычитаемое */
	size_t n			/*!< [in] длина a, b в машинных словах */
);

/*!	\brief Уменьшение числа

	Число [n]b уменьшается на число [n]a:
	\code
		b <- (b - a) \mod B^n, borrow <- (b < a).
	\endcode
	\pre Буфер c либо не пересекается, либо совпадает с каждым из буферов a, b.
	\return Слово заема borrow.
*/
word zzSub2(
	word b[],			/*!< [in,out] уменьшаемое / разность */
	const word a[],		/*!< [in] вычитаемое */
	size_t n			/*!< [in] длина a, b в машинных словах */
);

/*!	\brief Вычитание из числа слова

	Определяется разность [n]b числа [n]a и слова w:
	\code
		b <- (a - w) \mod B^n, borrow <- (a < w).
	\endcode
	\pre Буфер b либо не пересекается, либо совпадает с буфером a.
	\return Слово заема borrow.
*/
word zzSubW(
	word b[],			/*!< [out] разность */
	const word a[],		/*!< [in] уменьшаемое */
	size_t n,			/*!< [in] длина a в машинных словах */
	register word w		/*!< [in] вычитаемое */
);

/*!	\brief Уменьшение числа на слова

	Число [n]a уменьшается на слово w:
	\code
		a <- (a - w) \mod B^n, borrow <- (a < w).
	\endcode
	\return Слово заема borrow.
*/
word zzSubW2(
	word a[],			/*!< [in,out] уменьшаемое / разность */
	size_t n,			/*!< [in] длина a в машинных словах */
	register word w		/*!< [in] вычитаемое */
);

/*!	\brief Минус

	Определяется число [n]b, отрицательное к [n]a по модулю B^n:
	\code
		b <- B^n - a.
	\endcode
	\pre Буфер b либо не пересекается, либо совпадает с буфером a.
*/
void zzNeg(
	word b[],			/*!< [out] отрицательное число */
	const word a[],		/*!< [in] число */
	size_t n			/*!< [in] длина a в машинных словах */
);

/*
*******************************************************************************
Мультипликативные операции
*******************************************************************************
*/

/*!	\brief Умножение числа на слово

	Определяется произведение [n]b числа [n]a на слово w:
	\code
		b <- (a * w) \mod B^n, carry <- (a * w) \div B^n.
	\endcode
	\pre Буфер b либо не пересекается, либо совпадает с буфером a.
	\return Слово переноса carry.
*/
word zzMulW(
	word b[],			/*!< [out] произведение */
	const word a[],		/*!< [in] первый множитель */
	size_t n,			/*!< [in] длина a, b в машинных словах */
	register word w		/*!< [in] второй множитель */
);

/*!	\brief Сложение с произведением числа на слово

	К числу [n]b добавляется произведение числа [n]a на машинное слово w:
	\code
		b <- (b + a * w) \mod B^n, carry <- (b + a * w) \div B^n.
	\endcode
	\pre Буфер b либо не пересекается, либо совпадает с буфером a.
	\return Слово переноса carry.
*/
word zzAddMulW(
	word b[],			/*!< [in,out] слагаемое / сумма */
	const word a[],		/*!< [in] первый множитель */
	size_t n,			/*!< [in] длина a, b в машинных словах */
	register word w		/*!< [in] второй множитель */
);

/*!	\brief Вычитание произведения числа на слово

	Из числа [n]b вычитается произведение числа [n]a на машинное слово w:
	\code
		b <- (b - a * w) \mod B^n, carry <- (b < a * w).
	\endcode
	\pre Буфер b либо не пересекается, либо совпадает с буфером a.
	\return Слово заема borrow.
*/
word zzSubMulW(
	word b[],			/*!< [in,out] вычитаемое / разность */
	const word a[],		/*!< [in] первый множитель */
	size_t n,			/*!< [in] длина a, b в машинных словах */
	register word w		/*!< [in] второй множитель */
);

/*!	\brief Умножение чисел

	Определяется произведение [n + m]c чисел [n]a на [m]b:
	\code
		c <- a * b.
	\endcode
	\pre Буфер c не пересекается с буферами a и b.
	\deep{stack} zzMul_deep(n, m).
*/
void zzMul(
	word c[],			/*!< [out] произведение */
	const word a[],		/*!< [in] первый множитель */
	size_t n,			/*!< [in] длина a в машинных словах */
	const word b[],		/*!< [in] второй множитель */
	size_t m,			/*!< [in] длина b в машинных словах */
	void* stack			/*!< [in] вспомогательная память */
);

size_t zzMul_deep(size_t n, size_t m);

size_t zzMulADK(word c[], const word a[], const word b[], size_t n, void* stack);


/*!	\brief Возведение числа в квадрат

	Определяется квадрат [2n]b числа [n]a:
	\code
		b <- a * a.
	\endcode
	\pre Буфер b не пересекается с буфером a.
	\deep{stack} zzSqr_deep(n).
*/
void zzSqr(
	word b[],			/*!< [out] квадрат */
	const word a[],		/*!< [in] множитель */
	size_t n,			/*!< [in] длина a в машинных словах */
	void* stack			/*!< [in] вспомогательная память */
);

size_t zzSqr_deep(size_t n);

/*!	\brief Извлечение квадратного корня

	Определяется максимальное целое [(n + 1) / 2]b, квадрат которого 
	не превосходит [n]a:
	\code
		b <- \floor(\sqrt(a)).
	\endcode
	\return Признак того, что a является полным квадратом (a == b * b).
	\pre Буфер b не пересекается с буфером a.
	\deep{stack} zzSqrt_deep(n).
	\safe Функция нерегулярна: условные переходы, нерегулярные блоки.
*/
bool_t zzSqrt(
	word b[],			/*!< [out] квадратный корень */
	const word a[],		/*!< [in] число */
	size_t n,			/*!< [in] длина a в машинных словах */
	void* stack			/*!< [in] вспомогательная память */
);

size_t zzSqrt_deep(size_t n);

/*!	\brief Деление числа на машинное слово

	Определяется частное [n]q от деления числа [n]a на машинное слово w:
	\code
		q <- a \div w.
	\endcode
	\pre w != 0.
	\pre Буфер q либо не пересекается, либо совпадает с буфером a.
	\return Остаток от деления.
*/
word zzDivW(
	word q[],			/*!< [out] частное */
	const word a[],		/*!< [in] делимое */
	size_t n,			/*!< [in] длина a в машинных словах */
	register word w		/*!< [in] делитель */
);

/*!	\brief Остаток от деления числа на машинное слово

	Определяется остаток от деления числа [n]a на машинное слово w:
	\code
		r <- a \mod w.
	\endcode
	\pre w != 0.
	\return Остаток от деления r.
*/
word zzModW(
	const word a[],		/*!< [in] делимое */
	size_t n,			/*!< [in] длина a в машинных словах */
	register word w		/*!< [in] делитель */
);

/*!	\brief Остаток от деления числа на малое машинное слово

	Определяется остаток от деления числа [n]a на малое машинное слово w:
	\code
		r <- a \mod w.
	\endcode
	\pre w != 0 && w^2 <= B.
	\return Остаток от деления r.
	\remark Функция zzModW2() работает быстрее zzModW() на тех платформах,
	где деление не менее чем в 2 раза медленнее умножения.
*/
word zzModW2(
	const word a[],		/*!< [in] делимое */
	size_t n,			/*!< [in] длина a в машинных словах */
	register word w		/*!< [in] делитель */
);

/*!	\brief Деление чисел

	Определяются частное [n - m + 1]q и остаток [m]r от деления числа [n]a
	на число [m]b:
	\code
		q <- a \div b, r <- r \mod b,
		a == q * b + r, r < b.
	\endcode
	\pre n >= m.
	\pre m > 0 && b[m - 1] != 0.
	\pre Буферы q и r не пересекаются.
	\pre Буфер r либо не пересекается с буфером a, либо r == a.
	\deep{stack} zzDiv_deep(n, m).
	\safe Функция нерегулярна.
*/
void zzDiv(
	word q[],			/*!< [out] частное */
	word r[],			/*!< [out] остаток */
	const word a[],		/*!< [in] делимое */
	size_t n,			/*!< [in] длина a в машинных словах */
	const word b[],		/*!< [in] делитель */
	size_t m,			/*!< [in] длина b в машинных словах */
	void* stack			/*!< [in] вспомогательная память */
);

size_t zzDiv_deep(size_t n, size_t m);

/*!	\brief Остаток от деления чисел

	Определяется остаток [m]r от деления числа [n]a на число [m]b:
	\code
		a <- a \mod b.
	\endcode
	\pre m > 0 && b[m - 1] != 0.
	\pre Буфер r либо не пересекается с буфером a, либо r == a.
	\deep{stack} zzMod_deep(n, m).
	\safe Функция нерегулярна.
*/
void zzMod(
	word r[],			/*!< [out] остаток */
	const word a[],		/*!< [in] делимое */
	size_t n,			/*!< [in] длина a в машинных словах */
	const word b[],		/*!< [in] делитель */
	size_t m,			/*!< [in] длина b в машинных словах */
	void* stack			/*!< [in] вспомогательная память */
);

size_t zzMod_deep(size_t n, size_t m);

/*
*******************************************************************************
Алгоритм Евклида
*******************************************************************************
*/

/*!	\brief Наибольший общий делитель

	Определяется наибольший общий делитель [min(n, m)]d чисел [n]a и [m]b:
	\code
		d <- \gcd(a, b).
	\endcode
	\pre a != 0 && b != 0.
	\pre Буфер d не пересекается с буферами a и b.
	\remark Использование нулевых a и b запрещается для того, чтобы
	наибольший общий делитель d укладывался в [min(n, m)] слов.
	\remark Считается, что \gcd(0, b) = b, в частности, \gcd(0, 0) = 0.
	\deep{stack} zzGCD_deep(n, m).
	\safe Функция нерегулярна.
*/
void zzGCD(
	word d[],			/*!< [out] н.о.д. */
	const word a[],		/*!< [in] первое число */
	size_t n,			/*!< [in] длина a в машинных словах */
	const word b[],		/*!< [in] второе число */
	size_t m,			/*!< [in] длина b в машинных словах */
	void* stack			/*!< [in] вспомогательная память */
);

size_t zzGCD_deep(size_t n, size_t m);

/*!	\brief Взаимная простота

	Проверяется, что числа [n]a и [m]b взаимно просты:
	\code
		\gcd(a, b) == 1?
	\endcode
	\return Признак взаимной простоты a и b.
	\deep{stack} zzIsCoprime_deep(n, m).
	\safe Функция нерегулярна.
*/
bool_t zzIsCoprime(
	const word a[],		/*!< [in] первое число */
	size_t n,			/*!< [in] длина a в машинных словах */
	const word b[],		/*!< [in] второе число */
	size_t m,			/*!< [in] длина b в машинных словах */
	void* stack			/*!< [in] вспомогательная память */
);

size_t zzIsCoprime_deep(size_t n, size_t m);

/*!	\brief Наименьшее общее кратное

	Определяется наименьшее общее кратное [n + m]d чисел [n]a и [m]b:
	\code
		d <- \lcm[a, b].
	\endcode
	\pre a != 0 && b != 0.
	\pre Буфер d не пересекается с буферами a и b.
	\remark Использование нулевых a и b запрещается для согласованости с
	zzGCD() и избежания разбора редких, неиспользуемых на практике случаев.
	\deep{stack} zzLCM_deep(n, m).
	\safe Функция нерегулярна.
*/
void zzLCM(
	word d[],			/*!< [out] н.о.к. */
	const word a[],		/*!< [in] первое число */
	size_t n,			/*!< [in] длина a в машинных словах */
	const word b[],		/*!< [in] второе число */
	size_t m,			/*!< [in] длина b в машинных словах */
	void* stack			/*!< [in] вспомогательная память */
);

size_t zzLCM_deep(size_t n, size_t m);

/*!	\brief Расширенный алгоритм Евклида

	Определяется наибольший общий делитель [min(n, m)]d чисел [n]a и [m]b:
	\code
		d <- \gcd(a, b),
	\endcode
	а также положительные числа [m]da и [n]db (коэффициенты Безу) такие, что
	\code
		da * a - db * b == d
	\endcode
	\pre a != 0 && b != 0.
	\pre Буферы d, da, db не пересекаются между собой и с буферами a, b.
	\deep{stack} zzExGCD_deep(n, m).
	\safe Функция нерегулярна.
*/
void zzExGCD(
	word d[],			/*!< [out] н.о.д. */
	word da[],			/*!< [out] первый коэффициент Безу */
	word db[],			/*!< [out] второй коэффициент Безу */
	const word a[],		/*!< [in] первое число */
	size_t n,			/*!< [in] длина a в машинных словах */
	const word b[],		/*!< [in] второе число */
	size_t m,			/*!< [in] длина b в машинных словах */
	void* stack			/*!< [in] вспомогательная память */
);

size_t zzExGCD_deep(size_t n, size_t m);

/*
*******************************************************************************
Квадратичные вычеты
*******************************************************************************
*/

/*!	\brief Символ Якоби

	Определяется символ Якоби (a / b) чисел [n]a и [m]b.
	\pre b -- нечетное.
	\remark Если b является произведением простых p_1, p_2,.., p_k, то
	(a / b) = (a / p_1) * (a / p_2) *... * (a / p_k).
	Здесь (a / p_i) --- символ Лежандра: (a / p) равняется 0,
	если a делится на p, равняется 1, если a -- квадратичный вычет \mod p,
	и равняется -1 в остальных случаях.
	\return Символ Якоби (a / b): 0, 1 или -1.
	\deep{stack} zzJacobi_deep(n, m).
	\safe Функция нерегулярна.
*/
int zzJacobi(
	const word a[],		/*!< [in] первое число */
	size_t n,			/*!< [in] длина a в машинных словах */
	const word b[],		/*!< [in] второе число */
	size_t m,			/*!< [in] длина b в машинных словах */
	void* stack			/*!< [in] вспомогательная память */
);

size_t zzJacobi_deep(size_t n, size_t m);

/*
*******************************************************************************
Модулярная арифметика
*******************************************************************************
*/

/*!	\brief Сложение чисел по модулю

	Определяется сумма [n]c чисел [n]a и [n]b по модулю [n]mod:
	\code
		с <- (b + a) \mod mod.
	\endcode
	\pre a < mod && b < mod.
	\pre Буфер c либо не пересекается, либо совпадает с каждым из буферов a, b.
	\pre Буфер с не пересекается с буфером mod.
	\safe Имеется ускоренная нерегулярная редакция.
*/
void zzAddMod(
	word c[],			/*!< [out] сумма */
	const word a[],		/*!< [in] первое слагаемое */
	const word b[],		/*!< [in] второе слагаемое */
	const word mod[],	/*!< [in] модуль */
	size_t n			/*!< [in] длина чисел в машинных словах */
);

void SAFE(zzAddMod)(word c[], const word a[], const word b[], const word mod[],
	size_t n);
void FAST(zzAddMod)(word c[], const word a[], const word b[], const word mod[],
	size_t n);

/*!	\brief Сложение числа со словом по модулю

	Определяется сумма [n]b числа [n]a и слова w по модулю [n]mod:
	\code
		b <- (a + w) \mod mod.
	\endcode
	\pre a < mod && w < mod.
	\pre Буфер b либо не пересекается, либо совпадает с буфером a.
	\pre Буфер b не пересекается с буфером mod.
	\safe Имеется ускоренная нерегулярная редакция.
*/
void zzAddWMod(
	word b[],			/*!< [out] сумма */
	const word a[],		/*!< [in] первое слагаемое */
	register word w,	/*!< [in] второе слагаемое */
	const word mod[],	/*!< [in] модуль */
	size_t n			/*!< [in] длина чисел в машинных словах */
);

void SAFE(zzAddWMod)(word b[], const word a[], register word w,
	const word mod[], size_t n);
void FAST(zzAddWMod)(word b[], const word a[], register word w,
	const word mod[], size_t n);

/*!	\brief Вычитание чисел по модулю

	Определяется разность [n]с чисел [n]a и [n]b по модулю [n]mod:
	\code
		c <- (a - b) \mod mod.
	\endcode
	\pre n > 0 && mod[n - 1] != 0.
	\pre a < mod && b < mod.
	\pre Буфер c либо не пересекается, либо совпадает с каждым из буферов a, b.
	\pre Буфер с не пересекается с буфером mod.
	\safe Имеется ускоренная нерегулярная редакция.
*/
void zzSubMod(
	word c[],			/*!< [out] разность */
	const word a[],		/*!< [in] уменьшаемое */
	const word b[],		/*!< [in] вычитаемое */
	const word mod[],	/*!< [in] модуль */
	size_t n			/*!< [in] длина чисел в машинных словах */
);

void SAFE(zzSubMod)(word c[], const word a[], const word b[],
	const word mod[], size_t n);
void FAST(zzSubMod)(word c[], const word a[], const word b[],
	const word mod[], size_t n);

/*!	\brief Вычитание из числа слова по модулю

	Определяется разность [n]b числа [n]a и слова w по модулю [n]mod:
	\code
		b <- (a - w) \mod mod.
	\endcode
	\pre a < mod && w < mod.
	\pre Буфер b либо не пересекается, либо совпадает с буфером a.
	\pre Буфер b не пересекается с буфером mod.
	\safe Имеется ускоренная нерегулярная редакция.
*/
void zzSubWMod(
	word b[],			/*!< [out] разность */
	const word a[],		/*!< [in] уменьшаемое */
	register word w,	/*!< [in] вычитаемое */
	const word mod[],	/*!< [in] модуль */
	size_t n			/*!< [in] длина чисел в машинных словах */
);

void SAFE(zzSubWMod)(word b[], const word a[], register word w,
	const word mod[], size_t n);
void FAST(zzSubWMod)(word b[], const word a[], register word w,
	const word mod[], size_t n);

/*!	\brief Аддитивное обращение чисел по модулю

	Определяется число [n]b, аддитивно обратное к [n]a по модулю [n]mod:
	\code
		b <- -a \mod mod.
	\endcode
	\pre n > 0 && mod[n - 1] != 0.
	\pre a < mod.
	\pre Буфер b либо не пересекается, либо совпадает с буфером a.
	\pre Буфер b не пересекается с буфером mod.
	\safe Имеется ускоренная нерегулярная редакция.
*/
void zzNegMod(
	word b[],			/*!< [in,out] обратное число */
	const word a[],		/*!< [in] число */
	const word mod[],	/*!< [in] модуль */
	size_t n			/*!< [in] длина чисел в машинных словах */
);

void SAFE(zzNegMod)(word b[], const word a[], const word mod[], size_t n);
void FAST(zzNegMod)(word b[], const word a[], const word mod[], size_t n);

/*!	\brief Умножение чисел по модулю

	Определяется произведение [n]c чисел [n]a и [n]b по модулю [n]mod:
	\code
		c <- a * b \mod mod.
	\endcode
	\pre n > 0 && mod[n - 1] != 0.
	\pre a < mod && b < mod.
	\deep{stack} zzMulMod_deep(n).
*/
void zzMulMod(
	word c[],			/*!< [out] произведение */
	const word a[],		/*!< [in] первый множитель */
	const word b[],		/*!< [in] второй множитель */
	const word mod[],	/*!< [in] модуль */
	size_t n,			/*!< [in] длина чисел в машинных словах */
	void* stack			/*!< [in] вспомогательная память */
);

size_t zzMulMod_deep(size_t n);

/*!	\brief Умножение числа на слово по модулю

	Определяется произведение [n]b числа [n]a на слово w по модулю [n]mod:
	\code
		b <- a * w \mod mod.
	\endcode
	\pre n > 0 && mod[n - 1] != 0.
	\pre a < mod.
	\deep{stack} zzMulWMod_deep(n).
*/
void zzMulWMod(
	word b[],			/*!< [out] произведение */
	const word a[],		/*!< [in] первый множитель */
	register word w,	/*!< [in] второй множитель */
	const word mod[],	/*!< [in] модуль */
	size_t n,			/*!< [in] длина чисел в машинных словах */
	void* stack			/*!< [in] вспомогательная память */
);

size_t zzMulWMod_deep(size_t n);

/*!	\brief Возведение чисел в квадрат по модулю

	Определяется квадрат [n]b числа [n]a по модулю [n]mod:
	\code
		b <- a * a \mod mod.
	\endcode
	\pre n > 0 && mod[n - 1] != 0.
	\pre a < mod.
	\deep{stack} zzSqrMod_deep(n).
*/
void zzSqrMod(
	word b[],			/*!< [out] квадрат */
	const word a[],		/*!< [in] множитель */
	const word mod[],	/*!< [in] модуль */
	size_t n,			/*!< [in] длина чисел в машинных словах */
	void* stack			/*!< [in] вспомогательная память */
);

size_t zzSqrMod_deep(size_t n);

/*!	\brief Обращение по модулю

	Определяется число [n]b, мультипликативно обратное к [n]a по модулю [n]mod:
	\code
		b <- a^{-1} \mod mod.
	\endcode
	\pre mod -- нечетное && mod[n - 1] != 0.
	\pre a < mod.
	\pre Буфер b не пересекается с буфером mod.
	\expect \gcd(a, mod) == 1.
	\remark Если \gcd(a, mod) != 1, то b <- 0.
	\deep{stack} zzInvMod_deep(n).
	\safe Функция нерегулярна.
*/
void zzInvMod(
	word b[],			/*!< [out] обратное число */
	const word a[],		/*!< [in] обращаемое число */
	const word mod[],	/*!< [in] модуль */
	size_t n,			/*!< [in] длина чисел в машинных словах */
	void* stack			/*!< [in] вспомогательная память */
);

size_t zzInvMod_deep(size_t n);

/*!	\brief Деление по модулю

	Определяется частное [n]b от деления числа [n]divident на число [n]a по
	модулю [n]mod:
	\code
		b <- divident * a^{-1} \mod mod.
	\endcode
	\pre mod -- нечетное && mod[n - 1] != 0.
	\pre a, divident < mod.
	\pre Буфер b не пересекается с буфером mod.
	\expect \gcd(a, mod) = 1.
	\remark Если \gcd(a, mod) != 1, то b <- 0.
	\deep{stack} zzDivMod_deep(n).
	\safe Функция нерегулярна.
*/
void zzDivMod(
	word b[],				/*!< [out] частное */
	const word divident[],	/*!< [in] делимое */
	const word a[],			/*!< [in] делитель */
	const word mod[],		/*!< [in] модуль */
	size_t n,				/*!< [in] длина чисел в машинных словах */
	void* stack				/*!< [in] вспомогательная память */
);

size_t zzDivMod_deep(size_t n);

/*!	\brief Удвоение числа по модулю

	Определяется произведение [n]b числа [n]a на число 2 по модулю [n]mod:
	\code
		b <- 2 * a \mod mod.
	\endcode
	\pre a < mod.
	\pre Буфер b либо не пересекается, либо совпадает с буфером a.
	\pre Буфер b не пересекается с буфером mod.
	\safe Имеется ускоренная нерегулярная реализация.
*/
void zzDoubleMod(
	word b[],			/*!< [out] произведение */
	const word a[],		/*!< [in] множитель */
	const word mod[],	/*!< [in] модуль */
	size_t n			/*!< [in] длина чисел в машинных словах */
);

void SAFE(zzDoubleMod)(word b[], const word a[], const word mod[], size_t n);
void FAST(zzDoubleMod)(word b[], const word a[], const word mod[], size_t n);

/*!	\brief Половина числа по модулю

	Определяется частное [n]b от деления числа [n]a на число 2 по модулю [n]mod:
	\code
		b <- a * 2^{-1} \mod mod.
	\endcode
	\pre mod -- нечетное && mod[n - 1] != 0.
	\pre a < mod.
	\pre Буфер b либо не пересекается, либо совпадает с буфером a.
	\pre Буфер b не пересекается с буфером mod.
	\safe Имеется ускоренная нерегулярная реализация.
*/
void zzHalfMod(
	word b[],			/*!< [out] частное */
	const word a[],		/*!< [in] делимое */
	const word mod[],	/*!< [in] модуль */
	size_t n			/*!< [in] длина чисел в машинных словах */
);

void SAFE(zzHalfMod)(word b[], const word a[], const word mod[], size_t n);
void FAST(zzHalfMod)(word b[], const word a[], const word mod[], size_t n);

/*!	\brief Почти-обращение по модулю

	Определяется число [n]b, почти-мультипликативно обратное к [n]a 
	по модулю [n]mod:
	\code
		b <- a^{-1} * 2^k \mod mod,
	\endcode
	где wwBitSize(mod) <= k <= 2 * wwBitSize(mod).
	\pre mod -- нечетное && mod[n - 1] != 0.
	\pre 0 < a < mod.
	\pre Буфер b не пересекается с буфером mod.
	\expect \gcd(a, mod) == 1.
	\return Параметр k.
	\remark Если \gcd(a, mod) != 1, то b <- 0.
	\remark Применяя k раз zzHalfMod(), можно определить по b обычный обратный 
	элемент. Применяя n * B_PER_W - k раз zzDoubleMod(), можно определить по b
	обратный элемент относительно умножения Монтгомери.
	\deep{stack} zzAlmostInvMod_deep(n).
	\safe Функция нерегулярна.
*/
size_t zzAlmostInvMod(
	word b[],			/*!< [out] обратное число */
	const word a[],		/*!< [in] обращаемое число */
	const word mod[],	/*!< [in] модуль */
	size_t n,			/*!< [in] длина чисел в машинных словах */
	void* stack			/*!< [in] вспомогательная память */
);

size_t zzAlmostInvMod_deep(size_t n);

/*!	\brief Случайный вычет по модулю

	С помощью генератора rng с состоянием rng_state
	определяется случайный вычет [n]a по модулю [n]mod:
	\code
		a <-R {0, 1,..., mod - 1}.
	\endcode
	\pre n > 0 && mod[n - 1] != 0.
	\pre Буфер a не пересекается с буфером mod.
	\return Признак успеха.
	\remark Если 2^{l - 1} <= mod < 2^l, то для генерации a потребуется
		O_OF_B(l) * 2^l / mod <= 2 * O_OF_B(l)
	случайных октетов rng в среднем. 
	\remark Если rng выдает данные низкого статистического качества, 
	то для генерации может потребоваться больше октетов, чем указано
	выше. Более того, как только количество потребовавшихся октетов превысит
	определенный порог d, будет возвращен отрицательный результат. Порог d 
	выбирается так, что вероятность события "для генерации потребуется d 
	истинно случайных октетов" не превосходит 2^{-B_PER_IMPOSSIBLE}.
	\safe Время выполнения может флуктуировать. По времени выполнения можно 
	судить о выходных данных rng, но не тех, которые используются для 
	формирования a.
*/
bool_t zzRandMod(
	word a[],			/*!< [out] случайное число */
	const word mod[],	/*!< [in] модуль */
	size_t n,			/*!< [in] длина a и mod в машинных словах */
	gen_i rng,			/*!< [in] генератор случайных чисел */
	void* rng_state		/*!< [in,out] состояние генератора */
);

/*!	\brief Случайный ненулевой вычет по модулю

	С помощью генератора rng с состоянием rng_state
	определяется случайный ненулевой вычет [n]a по модулю [n]mod:
	\code
		a <-R {1, 2,..., mod - 1}.
	\endcode
	\pre n > 0 && mod[n - 1] != 0 && mod != 1.
	\pre Буфер a не пересекается с буфером mod.
	\return Признак успеха.
	\remark Если 2^{l - 1} <= mod < 2^l, то для генерации a потребуется
		O_OF_B(l) * 2^l / (mod - 1) \leq 2^l / (2^{l - 1} - 1) O_OF_B(l)
	случайных октетов rng в среднем. 
	\remark Повторяется последнее замечание по функции zzRandMod().
	\safe Время выполнения может флуктуировать. По времени выполнения можно 
	судить о выходных данных rng, но не тех, которые используются для 
	формирования a.
*/
bool_t zzRandNZMod(
	word a[],			/*!< [out] случайное число */
	const word mod[],	/*!< [in] модуль */
	size_t n,			/*!< [in] длина a и mod в машинных словах */
	gen_i rng,			/*!< [in] генератор случайных чисел */
	void* rng_state		/*!< [in,out] состояние генератора */
);

/*!
*******************************************************************************
\file zz.h

\section zz-red Редукция

Редукция состоит в определении вычета числа [2n]a по модулю [n]mod.
Обрабатываемое число всегда состоит из 2n машинных слов и результат всегда 
возвращается на месте а (ср. с zzMod()). Чтобы подчеркнуть данные соглашения 
вместо Mod (остаток от деления) пишется Red (редукция).

Кроме обычной редукции реализованы быстрые редукции по специальным модулям.
*******************************************************************************
*/

/*!	\brief Стандартная редукция

	Определяется остаток [n]a от деления числа [2n]a на модуль [n]mod.
	\pre n >= 1 && mod[n - 1] != 0.
	\pre Буферы a и mod не пересекаются.
	\deep{stack} zzRed_deep(n).
	\safe Функция нерегулярна.
*/
void zzRed(
	word a[],					/*!< [in,out] делимое / остаток */
	const word mod[],			/*!< [in] модуль */
	size_t n,					/*!< [in] длина mod в машинных словах */
	void* stack					/*!< [in] вспомогательная память */
);

size_t zzRed_deep(size_t n);

/*!	\brief Редукция Крэндалла

	Определяется остаток  [n]a от деления числа [2n]a на модуль [n]mod,
	который близок снизу к B^n.
	\pre n >= 2 && mod[n - 1] != 0.
	\pre Модуль mod имеет вид B^n - c, где 0 < c < B.
	\pre Буферы a и mod не пересекаются.
	\deep{stack} zzRedCrand_deep(n).
	\safe Имеется ускоренная нерегулярная редакция.
*/
void zzRedCrand(
	word a[],					/*!< [in,out] делимое / остаток */
	const word mod[],			/*!< [in] модуль Крэндалла */
	size_t n,					/*!< [in] длина mod в машинных словах */
	void* stack					/*!< [in] вспомогательная память (не исп.) */
);

void SAFE(zzRedCrand)(word a[], const word mod[], size_t n, void* stack);
void FAST(zzRedCrand)(word a[], const word mod[], size_t n, void* stack);

size_t zzRedCrand_deep(size_t n);

/*!	\brief Инициализация редукции Барретта

	По модулю [n]mod определяется параметр [n + 2]barr_param:
	\code
		barr_param <- B^{2n} \div mod.
	\endcode
	Этот параметр используется в редукции Барретта.
	\pre n > 0 && mod[n] != 0.
	\pre Буферы barr_param и mod не пересекаются.
	\deep{stack} zzRedBarrStart_deep(n).
*/
void zzRedBarrStart(
	word barr_param[],			/*!< [out] параметр Барретта */
	const word mod[],			/*!< [in] модуль */
	size_t n,					/*!< [in] длина mod в машинных словах */
	void* stack					/*!< [in] вспомогательная память */
);

size_t zzRedBarrStart_deep(size_t n);

/*!	\brief Редукция Барретта

	Определяется остаток [n]a от деления числа [2n]a на модуль [n]mod.
	При вычислениях используется параметр Барретта [n + 2]barr_param.
	\pre n > 0 && mod[n - 1] != 0.
	\pre Буфер a не пересекается с буфером mod.
	\expect barr_param рассчитан с помощью функции zzRedBarrStart().
	\deep{stack} zzRedBarr_deep(n).
	\safe Имеется ускоренная нерегулярная редакция.
*/
void zzRedBarr(
	word a[],					/*!< [in,out] делимое / остаток */
	const word mod[],			/*!< [in] модуль */
	size_t n,					/*!< [in] длина mod в машинных словах */
	const word barr_param[],	/*!< [in] параметр Барретта */
	void* stack					/*!< [in] вспомогательная память */
);

void SAFE(zzRedBarr)(word a[], const word mod[], size_t n,
	const word barr_param[], void* stack);
void FAST(zzRedBarr)(word a[], const word mod[], size_t n,
	const word barr_param[], void* stack);

size_t zzRedBarr_deep(size_t n);

/*!	\brief Редукция Монтгомери

	Определяется результат [n]a редукции Монтгомери числа [2n]a по
	модулю [n]mod:
	\code
		a <- a * R^{-1} \mod mod, R == B^n.
	\endcode
	При вычислениях используется параметр Монтгомери mont_param.
	\pre mod -- нечетное && mod[n - 1] != 0.
	\pre a < mod * R.
	\pre mont_param рассчитан с помощью функции wordNegInv().
	\pre Буфер a не пересекается с буфером mod.
	\remark Редукция предложена в статье [Montgomery P. L. Modular
	multiplication without trial division. Mathematics of Computation,
	44(170): 519–521, 1985].
	\deep{stack} zzRedMont_deep(n).
	\safe Имеется ускоренная нерегулярная редакция.
*/
void zzRedMont(
	word a[],					/*!< [in,out] входное число / результат */
	const word mod[],			/*!< [in] модуль */
	size_t n,					/*!< [in] длина mod в машинных словах */
	register word mont_param,	/*!< [in] параметр Монтгомери */
	void* stack					/*!< [in] вспомогательная память */
);

void SAFE(zzRedMont)(word a[], const word mod[], size_t n,
	register word mont_param, void* stack);
void FAST(zzRedMont)(word a[], const word mod[], size_t n,
	register word mont_param, void* stack);

size_t zzRedMont_deep(size_t n);

/*!	\brief Редукция Монтгомери по модулю Крэндалла

	Определяется результат [n]a редукции Монтгомери числа [2n]a по
	модулю [n]mod, который близок снизу к B^n:
	\code
		a <- a * R^{-1} \mod mod, R == B^n.
	\endcode
	При вычислениях используется параметр Монтгомери mont_param.
	\pre n >= 2 && mod -- нечетное && mod имеет вид B^n - c, где 0 < c < B.
	\pre a < mod * R.
	\pre mont_param рассчитан с помощью функции wordNegInv().
	\pre Буфер a не пересекается с буфером mod.
	\deep{stack} zzRedCrandMont_deep(n).
	\safe Имеется ускоренная нерегулярная редакция.
*/
void zzRedCrandMont(
	word a[],					/*!< [in,out] входное число / результат */
	const word mod[],			/*!< [in] модуль */
	size_t n,					/*!< [in] длина mod в машинных словах */
	register word mont_param,	/*!< [in] параметр Монтгомери */
	void* stack					/*!< [in] вспомогательная память */
);

void SAFE(zzRedCrandMont)(word a[], const word mod[], size_t n,
	register word mont_param, void* stack);
void FAST(zzRedCrandMont)(word a[], const word mod[], size_t n,
	register word mont_param, void* stack);

size_t zzRedCrandMont_deep(size_t n);

/*
*******************************************************************************
Возведение в степень
*******************************************************************************
*/

/*!	\brief Возведение в степень по модулю

	Определяется число [n]c, которое является [m]b-ой степенью числа [n]a
	по модулю [n]mod:
	\code
		c <- a^b \mod mod.
	\endcode
	\pre n > 0 && mod[n - 1] != 0.
	\pre a < mod.
	\remark 0^0 == 1.
	\deep{stack} zzPowerMod_deep(n, m).
	\safe todo
*/
void zzPowerMod(
	word c[],				/*!< [out] степень */
	const word a[],			/*!< [in] основание */
	size_t n,				/*!< [in] длина a, mod в машинных словах */
	const word b[],			/*!< [in] показатель */
	size_t m,				/*!< [in] длина b в машинных словах */
	const word mod[],		/*!< [in] модуль */
	void* stack				/*!< [in] вспомогательная память */
);

size_t zzPowerMod_deep(size_t n, size_t m);

/*!	\brief Возведение в степень по модулю машинного слова

	Определяется b-ая степень числа a по модулю машинного слова mod.
	\pre mod != 0.
	\return Степень.
	\deep{stack} zzPowerModW_deep().
	\safe todo
*/
word zzPowerModW(
	register word a,		/*!< [in] основание */
	register word b,		/*!< [in] показатель */
	register word mod,		/*!< [in] модуль */
	void* stack				/*!< [in] вспомогательная память */
);

size_t zzPowerModW_deep();

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* __ZZ_H */