diff --git a/.gitignore b/.gitignore index 76f5bd8b1e..01161b1254 100644 --- a/.gitignore +++ b/.gitignore @@ -159,19 +159,23 @@ third_party/openssl-nistz256/measure third_party/curve25519-donna-c64/measure src/ExtractionHaskell/saturated_solinas src/ExtractionHaskell/unsaturated_solinas +src/ExtractionHaskell/solinas_reduction src/ExtractionHaskell/word_by_word_montgomery src/ExtractionHaskell/base_conversion src/ExtractionHaskell/*.hs src/ExtractionOCaml/saturated_solinas src/ExtractionOCaml/unsaturated_solinas +src/ExtractionOCaml/solinas_reduction src/ExtractionOCaml/word_by_word_montgomery src/ExtractionOCaml/base_conversion src/ExtractionOCaml/bedrock2_saturated_solinas src/ExtractionOCaml/bedrock2_unsaturated_solinas +src/ExtractionOCaml/bedrock2_solinas_reduction src/ExtractionOCaml/bedrock2_word_by_word_montgomery src/ExtractionOCaml/bedrock2_base_conversion src/ExtractionOCaml/with_bedrock2_saturated_solinas src/ExtractionOCaml/with_bedrock2_unsaturated_solinas +src/ExtractionOCaml/with_bedrock2_solinas_reduction src/ExtractionOCaml/with_bedrock2_word_by_word_montgomery src/ExtractionOCaml/with_bedrock2_base_conversion src/ExtractionOCaml/perf_unsaturated_solinas diff --git a/Makefile.config b/Makefile.config index 1781fb0e64..fec9c14604 100644 --- a/Makefile.config +++ b/Makefile.config @@ -50,7 +50,7 @@ else if_SKIP_BEDROCK2 = $(1) endif -BASE_STANDALONE := unsaturated_solinas saturated_solinas word_by_word_montgomery base_conversion +BASE_STANDALONE := unsaturated_solinas saturated_solinas word_by_word_montgomery base_conversion solinas_reduction BEDROCK2_STANDALONE := $(addprefix bedrock2_,$(BASE_STANDALONE)) $(addprefix with_bedrock2_,$(BASE_STANDALONE)) STANDALONE := $(BASE_STANDALONE) $(call if_SKIP_BEDROCK2,,$(BEDROCK2_STANDALONE) $(WITH_BEDROCK2_STANDALONE)) PERF_STANDALONE := perf_unsaturated_solinas perf_word_by_word_montgomery diff --git a/Makefile.examples b/Makefile.examples index 7afd1b3da0..44adbe3865 100644 --- a/Makefile.examples +++ b/Makefile.examples @@ -87,8 +87,10 @@ endef UNSATURATED_SOLINAS_FUNCTIONS := carry_mul carry_square carry add sub opp selectznz to_bytes from_bytes relax FUNCTIONS_FOR_25519 := $(UNSATURATED_SOLINAS_FUNCTIONS) carry_scmul121666 WORD_BY_WORD_MONTGOMERY_FUNCTIONS := mul square add sub opp from_montgomery to_montgomery nonzero selectznz to_bytes from_bytes one msat divstep divstep_precomp +SOLINAS_REDUCTION_FUNCTIONS := mul square UNSATURATED_SOLINAS := src/ExtractionOCaml/unsaturated_solinas WORD_BY_WORD_MONTGOMERY := src/ExtractionOCaml/word_by_word_montgomery +SOLINAS_REDUCTION := src/ExtractionOCaml/solinas_reduction UNSATURATED_SOLINAS_BASE_FILES := # p224_solinas_64 WORD_BY_WORD_MONTGOMERY_BASE_FILES := # p434_32 @@ -118,6 +120,8 @@ $(foreach bw,64 32,$(eval $(call add_curve_keys,p256_scalar_$(bw),WORD_BY_WORD_M $(foreach bw,64 32,$(eval $(call add_curve_keys,p384_scalar_$(bw),WORD_BY_WORD_MONTGOMERY,'p384_scalar',$(bw),'2^384 - 1388124618062372383947042015309946732620727252194336364173',$(WORD_BY_WORD_MONTGOMERY_FUNCTIONS),WORD_BY_WORD_MONTGOMERY))) $(foreach bw,64 32,$(eval $(call add_curve_keys,secp256k1_scalar_$(bw),WORD_BY_WORD_MONTGOMERY,'secp256k1_scalar',$(bw),'2^256 - 432420386565659656852420866394968145599',$(WORD_BY_WORD_MONTGOMERY_FUNCTIONS),WORD_BY_WORD_MONTGOMERY))) +$(foreach bw,64,$(eval $(call add_curve_keys,curve25519_solinas_$(bw),SOLINAS_REDUCTION,'curve25519_solinas',$(bw),'2^255 - 19',$(SOLINAS_REDUCTION_FUNCTIONS),SOLINAS_REDUCTION))) + # Files taking 30s or less LITE_BASE_FILES := curve25519_64 poly1305_64 poly1305_32 p256_64 secp256k1_64 p384_64 p224_32 p434_64 p448_solinas_64 secp256k1_32 p256_32 p448_solinas_32 \ curve25519_scalar_64 p256_scalar_64 secp256k1_scalar_64 p384_scalar_64 secp256k1_scalar_32 p256_scalar_32 @@ -143,6 +147,7 @@ LITE_ZIG_FILES := $(patsubst %,$(ZIG_DIR)%.zig,$(LITE_BASE_FILES)) BEDROCK2_UNSATURATED_SOLINAS := src/ExtractionOCaml/bedrock2_unsaturated_solinas BEDROCK2_WORD_BY_WORD_MONTGOMERY := src/ExtractionOCaml/bedrock2_word_by_word_montgomery +BEDROCK2_SOLINAS_REDUCTION := src/ExtractionOCaml/bedrock2_solinas_reduction C_EXTRA_ARGS := --inline --static --use-value-barrier @@ -359,7 +364,7 @@ test-amd64-files-status only-test-amd64-files-status test-amd64-files-lite-statu .PHONY: test-amd64-files-status only-test-amd64-files-status test-amd64-files-lite-status only-test-amd64-files-lite-status -test-amd64-files test-amd64-files-lite: $(UNSATURATED_SOLINAS) $(WORD_BY_WORD_MONTGOMERY) +test-amd64-files test-amd64-files-lite: $(UNSATURATED_SOLINAS) $(WORD_BY_WORD_MONTGOMERY) $(SOLINAS_REDUCTION) test-amd64-files: test-amd64-files-print-report test-amd64-files-status diff --git a/etc/ensure_stack_limit.sh b/etc/ensure_stack_limit.sh index 846e071bb3..c654d70a03 100755 --- a/etc/ensure_stack_limit.sh +++ b/etc/ensure_stack_limit.sh @@ -2,7 +2,7 @@ set -eu -recstacksize=32768 +recstacksize=65536 if command -v ulimit >/dev/null 2>/dev/null; then hardstacksize="$(ulimit -H -s || true)" ( diff --git a/fiat-bedrock2/src/curve25519_solinas_64.c b/fiat-bedrock2/src/curve25519_solinas_64.c new file mode 100644 index 0000000000..aa2992a056 --- /dev/null +++ b/fiat-bedrock2/src/curve25519_solinas_64.c @@ -0,0 +1,501 @@ +/* Autogenerated: 'src/ExtractionOCaml/bedrock2_solinas_reduction' --lang bedrock2 --static --no-wide-int --widen-carry --widen-bytes --split-multiret --no-select --no-field-element-typedefs curve25519_solinas 64 '2^255 - 19' mul square */ +/* curve description: curve25519_solinas */ +/* machine_wordsize = 64 (from "64") */ +/* requested operations: mul, square */ +/* s-c = 2^255 - [(1, 19)] (from "2^255 - 19") */ +/* */ +/* Computed values: */ +/* */ + +#include +#include +#include + +static __attribute__((constructor)) void _br2_preconditions(void) { + static_assert(~(intptr_t)0 == -(intptr_t)1, "two's complement"); + assert(((void)"two's complement", ~(intptr_t)0 == -(intptr_t)1)); + assert(((void)"little-endian", 1 == *(unsigned char *)&(const uintptr_t){1})); + assert(((void)"little-endian", 1 == *(unsigned char *)&(const intptr_t){1})); +} + +// We use memcpy to work around -fstrict-aliasing. +// A plain memcpy is enough on clang 10, but not on gcc 10, which fails +// to infer the bounds on an integer loaded by memcpy. +// Adding a range mask after memcpy in turn makes slower code in clang. +// Loading individual bytes, shifting them together, and or-ing is fast +// on clang and sometimes on GCC, but other times GCC inlines individual +// byte operations without reconstructing wider accesses. +// The little-endian idiom below seems fast in gcc 9+ and clang 10. +static inline __attribute__((always_inline, unused)) +uintptr_t _br2_load(uintptr_t a, uintptr_t sz) { + switch (sz) { + case 1: { uint8_t r = 0; memcpy(&r, (void*)a, 1); return r; } + case 2: { uint16_t r = 0; memcpy(&r, (void*)a, 2); return r; } + case 4: { uint32_t r = 0; memcpy(&r, (void*)a, 4); return r; } + case 8: { uint64_t r = 0; memcpy(&r, (void*)a, 8); return r; } + default: __builtin_unreachable(); + } +} + +static inline __attribute__((always_inline, unused)) +void _br2_store(uintptr_t a, uintptr_t v, uintptr_t sz) { + memcpy((void*)a, &v, sz); +} + +static inline __attribute__((always_inline, unused)) +uintptr_t _br2_mulhuu(uintptr_t a, uintptr_t b) { + #if (UINTPTR_MAX == (UINTMAX_C(1)<<31) - 1 + (UINTMAX_C(1)<<31)) + return ((uint64_t)a * b) >> 32; + #elif (UINTPTR_MAX == (UINTMAX_C(1)<<63) - 1 + (UINTMAX_C(1)<<63)) + return ((unsigned __int128)a * b) >> 64; + #else + #error "32-bit or 64-bit uintptr_t required" + #endif +} + +static inline __attribute__((always_inline, unused)) +uintptr_t _br2_divu(uintptr_t a, uintptr_t b) { + if (!b) return -1; + return a/b; +} + +static inline __attribute__((always_inline, unused)) +uintptr_t _br2_remu(uintptr_t a, uintptr_t b) { + if (!b) return a; + return a%b; +} + +static inline __attribute__((always_inline, unused)) +uintptr_t _br2_shamt(uintptr_t a) { + return a&(sizeof(uintptr_t)*8-1); +} + + +/* + * Input Bounds: + * in0: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] + * in1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] + * Output Bounds: + * out0: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] + */ +static +void internal_fiat_curve25519_solinas_mul(uintptr_t out0, uintptr_t in0, uintptr_t in1) { + uintptr_t x3, x2, x1, x7, x6, x5, x0, x4, x14, x35, x41, x33, x42, x12, x43, x45, x46, x25, x20, x40, x49, x44, x50, x15, x51, x53, x54, x47, x56, x17, x22, x37, x59, x48, x60, x23, x61, x63, x64, x52, x65, x18, x66, x68, x69, x55, x70, x10, x71, x73, x74, x57, x76, x9, x28, x58, x79, x62, x80, x26, x81, x83, x84, x67, x85, x21, x86, x88, x89, x72, x90, x13, x91, x93, x94, x75, x96, x77, x30, x39, x99, x78, x100, x31, x101, x103, x104, x82, x105, x29, x106, x108, x109, x87, x110, x24, x111, x113, x114, x92, x115, x16, x116, x118, x119, x95, x120, x8, x121, x123, x124, x97, x36, x98, x127, x102, x128, x34, x129, x131, x132, x107, x133, x32, x134, x136, x137, x112, x138, x27, x139, x141, x142, x117, x143, x19, x144, x146, x147, x122, x148, x11, x149, x151, x152, x125, x153, x150, x145, x140, x158, x126, x163, x130, x164, x156, x165, x167, x168, x135, x169, x154, x170, x172, x173, x155, x160, x38, x176, x162, x177, x161, x178, x180, x181, x166, x182, x159, x183, x185, x186, x171, x187, x157, x188, x190, x191, x174, x192, x193, x175, x195, x179, x197, x184, x199, x189, x201, x202, x203, x204, x194, x205, x196, x198, x200, x206, x207, x208, x209; + x0 = _br2_load((in0)+((uintptr_t)(UINTMAX_C(0))), sizeof(uintptr_t)); + x1 = _br2_load((in0)+((uintptr_t)(UINTMAX_C(8))), sizeof(uintptr_t)); + x2 = _br2_load((in0)+((uintptr_t)(UINTMAX_C(16))), sizeof(uintptr_t)); + x3 = _br2_load((in0)+((uintptr_t)(UINTMAX_C(24))), sizeof(uintptr_t)); + /*skip*/ + x4 = _br2_load((in1)+((uintptr_t)(UINTMAX_C(0))), sizeof(uintptr_t)); + x5 = _br2_load((in1)+((uintptr_t)(UINTMAX_C(8))), sizeof(uintptr_t)); + x6 = _br2_load((in1)+((uintptr_t)(UINTMAX_C(16))), sizeof(uintptr_t)); + x7 = _br2_load((in1)+((uintptr_t)(UINTMAX_C(24))), sizeof(uintptr_t)); + /*skip*/ + /*skip*/ + x8 = (x3)*(x7); + x9 = _br2_mulhuu((x3), (x7)); + x10 = (x3)*(x6); + x11 = _br2_mulhuu((x3), (x6)); + x12 = (x3)*(x5); + x13 = _br2_mulhuu((x3), (x5)); + x14 = (x3)*(x4); + x15 = _br2_mulhuu((x3), (x4)); + x16 = (x2)*(x7); + x17 = _br2_mulhuu((x2), (x7)); + x18 = (x2)*(x6); + x19 = _br2_mulhuu((x2), (x6)); + x20 = (x2)*(x5); + x21 = _br2_mulhuu((x2), (x5)); + x22 = (x2)*(x4); + x23 = _br2_mulhuu((x2), (x4)); + x24 = (x1)*(x7); + x25 = _br2_mulhuu((x1), (x7)); + x26 = (x1)*(x6); + x27 = _br2_mulhuu((x1), (x6)); + x28 = (x1)*(x5); + x29 = _br2_mulhuu((x1), (x5)); + x30 = (x1)*(x4); + x31 = _br2_mulhuu((x1), (x4)); + x32 = (x0)*(x7); + x33 = _br2_mulhuu((x0), (x7)); + x34 = (x0)*(x6); + x35 = _br2_mulhuu((x0), (x6)); + x36 = (x0)*(x5); + x37 = _br2_mulhuu((x0), (x5)); + x38 = (x0)*(x4); + x39 = _br2_mulhuu((x0), (x4)); + x40 = (x35)+(x14); + x41 = (uintptr_t)((x40)<(x35)); + x42 = (x41)+(x33); + x43 = (uintptr_t)((x42)<(x33)); + x44 = (x42)+(x12); + x45 = (uintptr_t)((x44)<(x12)); + x46 = (x43)+(x45); + x47 = (x46)+(x25); + x48 = (x40)+(x20); + x49 = (uintptr_t)((x48)<(x40)); + x50 = (x49)+(x44); + x51 = (uintptr_t)((x50)<(x44)); + x52 = (x50)+(x15); + x53 = (uintptr_t)((x52)<(x15)); + x54 = (x51)+(x53); + x55 = (x54)+(x47); + x56 = (uintptr_t)((x55)<(x47)); + x57 = (x56)+(x17); + x58 = (x37)+(x22); + x59 = (uintptr_t)((x58)<(x37)); + x60 = (x59)+(x48); + x61 = (uintptr_t)((x60)<(x48)); + x62 = (x60)+(x23); + x63 = (uintptr_t)((x62)<(x23)); + x64 = (x61)+(x63); + x65 = (x64)+(x52); + x66 = (uintptr_t)((x65)<(x52)); + x67 = (x65)+(x18); + x68 = (uintptr_t)((x67)<(x18)); + x69 = (x66)+(x68); + x70 = (x69)+(x55); + x71 = (uintptr_t)((x70)<(x55)); + x72 = (x70)+(x10); + x73 = (uintptr_t)((x72)<(x10)); + x74 = (x71)+(x73); + x75 = (x74)+(x57); + x76 = (uintptr_t)((x75)<(x57)); + x77 = (x76)+(x9); + x78 = (x58)+(x28); + x79 = (uintptr_t)((x78)<(x58)); + x80 = (x79)+(x62); + x81 = (uintptr_t)((x80)<(x62)); + x82 = (x80)+(x26); + x83 = (uintptr_t)((x82)<(x26)); + x84 = (x81)+(x83); + x85 = (x84)+(x67); + x86 = (uintptr_t)((x85)<(x67)); + x87 = (x85)+(x21); + x88 = (uintptr_t)((x87)<(x21)); + x89 = (x86)+(x88); + x90 = (x89)+(x72); + x91 = (uintptr_t)((x90)<(x72)); + x92 = (x90)+(x13); + x93 = (uintptr_t)((x92)<(x13)); + x94 = (x91)+(x93); + x95 = (x94)+(x75); + x96 = (uintptr_t)((x95)<(x75)); + x97 = (x96)+(x77); + x98 = (x39)+(x30); + x99 = (uintptr_t)((x98)<(x39)); + x100 = (x99)+(x78); + x101 = (uintptr_t)((x100)<(x78)); + x102 = (x100)+(x31); + x103 = (uintptr_t)((x102)<(x31)); + x104 = (x101)+(x103); + x105 = (x104)+(x82); + x106 = (uintptr_t)((x105)<(x82)); + x107 = (x105)+(x29); + x108 = (uintptr_t)((x107)<(x29)); + x109 = (x106)+(x108); + x110 = (x109)+(x87); + x111 = (uintptr_t)((x110)<(x87)); + x112 = (x110)+(x24); + x113 = (uintptr_t)((x112)<(x24)); + x114 = (x111)+(x113); + x115 = (x114)+(x92); + x116 = (uintptr_t)((x115)<(x92)); + x117 = (x115)+(x16); + x118 = (uintptr_t)((x117)<(x16)); + x119 = (x116)+(x118); + x120 = (x119)+(x95); + x121 = (uintptr_t)((x120)<(x95)); + x122 = (x120)+(x8); + x123 = (uintptr_t)((x122)<(x8)); + x124 = (x121)+(x123); + x125 = (x124)+(x97); + x126 = (x98)+(x36); + x127 = (uintptr_t)((x126)<(x98)); + x128 = (x127)+(x102); + x129 = (uintptr_t)((x128)<(x102)); + x130 = (x128)+(x34); + x131 = (uintptr_t)((x130)<(x34)); + x132 = (x129)+(x131); + x133 = (x132)+(x107); + x134 = (uintptr_t)((x133)<(x107)); + x135 = (x133)+(x32); + x136 = (uintptr_t)((x135)<(x32)); + x137 = (x134)+(x136); + x138 = (x137)+(x112); + x139 = (uintptr_t)((x138)<(x112)); + x140 = (x138)+(x27); + x141 = (uintptr_t)((x140)<(x27)); + x142 = (x139)+(x141); + x143 = (x142)+(x117); + x144 = (uintptr_t)((x143)<(x117)); + x145 = (x143)+(x19); + x146 = (uintptr_t)((x145)<(x19)); + x147 = (x144)+(x146); + x148 = (x147)+(x122); + x149 = (uintptr_t)((x148)<(x122)); + x150 = (x148)+(x11); + x151 = (uintptr_t)((x150)<(x11)); + x152 = (x149)+(x151); + x153 = (x152)+(x125); + x154 = ((uintptr_t)(UINTMAX_C(38)))*(x153); + x155 = _br2_mulhuu(((uintptr_t)(UINTMAX_C(38))), (x153)); + x156 = ((uintptr_t)(UINTMAX_C(38)))*(x150); + x157 = _br2_mulhuu(((uintptr_t)(UINTMAX_C(38))), (x150)); + x158 = ((uintptr_t)(UINTMAX_C(38)))*(x145); + x159 = _br2_mulhuu(((uintptr_t)(UINTMAX_C(38))), (x145)); + x160 = ((uintptr_t)(UINTMAX_C(38)))*(x140); + x161 = _br2_mulhuu(((uintptr_t)(UINTMAX_C(38))), (x140)); + x162 = (x126)+(x158); + x163 = (uintptr_t)((x162)<(x126)); + x164 = (x163)+(x130); + x165 = (uintptr_t)((x164)<(x130)); + x166 = (x164)+(x156); + x167 = (uintptr_t)((x166)<(x156)); + x168 = (x165)+(x167); + x169 = (x168)+(x135); + x170 = (uintptr_t)((x169)<(x135)); + x171 = (x169)+(x154); + x172 = (uintptr_t)((x171)<(x154)); + x173 = (x170)+(x172); + x174 = (x173)+(x155); + x175 = (x38)+(x160); + x176 = (uintptr_t)((x175)<(x38)); + x177 = (x176)+(x162); + x178 = (uintptr_t)((x177)<(x162)); + x179 = (x177)+(x161); + x180 = (uintptr_t)((x179)<(x161)); + x181 = (x178)+(x180); + x182 = (x181)+(x166); + x183 = (uintptr_t)((x182)<(x166)); + x184 = (x182)+(x159); + x185 = (uintptr_t)((x184)<(x159)); + x186 = (x183)+(x185); + x187 = (x186)+(x171); + x188 = (uintptr_t)((x187)<(x171)); + x189 = (x187)+(x157); + x190 = (uintptr_t)((x189)<(x157)); + x191 = (x188)+(x190); + x192 = (x191)+(x174); + x193 = ((uintptr_t)(UINTMAX_C(38)))*(x192); + x194 = (x175)+(x193); + x195 = (uintptr_t)((x194)<(x175)); + x196 = (x195)+(x179); + x197 = (uintptr_t)((x196)<(x179)); + x198 = (x197)+(x184); + x199 = (uintptr_t)((x198)<(x184)); + x200 = (x199)+(x189); + x201 = (uintptr_t)((x200)<(x189)); + x202 = ((uintptr_t)(UINTMAX_C(-1)))+((uintptr_t)((x201)==((uintptr_t)(UINTMAX_C(0))))); + x203 = (x202)^((uintptr_t)(UINTMAX_C(18446744073709551615))); + x204 = (((uintptr_t)(UINTMAX_C(38)))&(x202))|(((uintptr_t)(UINTMAX_C(0)))&(x203)); + x205 = (x204)+(x194); + x206 = x205; + x207 = x196; + x208 = x198; + x209 = x200; + /*skip*/ + _br2_store((out0)+((uintptr_t)(UINTMAX_C(0))), x206, sizeof(uintptr_t)); + _br2_store((out0)+((uintptr_t)(UINTMAX_C(8))), x207, sizeof(uintptr_t)); + _br2_store((out0)+((uintptr_t)(UINTMAX_C(16))), x208, sizeof(uintptr_t)); + _br2_store((out0)+((uintptr_t)(UINTMAX_C(24))), x209, sizeof(uintptr_t)); + /*skip*/ + return; +} + +/* NOTE: The following wrapper function is not covered by Coq proofs */ +static void fiat_curve25519_solinas_mul(uint64_t out1[4], const uint64_t arg1[4], const uint64_t arg2[4]) { + internal_fiat_curve25519_solinas_mul((uintptr_t)out1, (uintptr_t)arg1, (uintptr_t)arg2); +} + + +/* + * Input Bounds: + * in0: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] + * Output Bounds: + * out0: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] + */ +static +void internal_fiat_curve25519_solinas_square(uintptr_t out0, uintptr_t in0) { + uintptr_t x6, x9, x15, x7, x16, x4, x17, x19, x20, x5, x21, x12, x22, x24, x25, x13, x26, x10, x27, x29, x30, x11, x32, x18, x35, x23, x36, x33, x37, x39, x40, x28, x42, x31, x8, x46, x47, x14, x48, x50, x51, x52, x34, x53, x55, x56, x57, x38, x58, x60, x61, x62, x41, x63, x65, x66, x67, x43, x68, x70, x71, x44, x3, x2, x1, x0, x80, x45, x82, x49, x83, x77, x84, x86, x87, x54, x88, x78, x89, x91, x92, x59, x93, x75, x94, x96, x97, x64, x98, x76, x99, x101, x102, x69, x103, x73, x104, x106, x107, x72, x108, x74, x109, x105, x100, x95, x114, x81, x119, x85, x120, x112, x121, x123, x124, x90, x125, x110, x126, x128, x129, x111, x116, x79, x132, x118, x133, x117, x134, x136, x137, x122, x138, x115, x139, x141, x142, x127, x143, x113, x144, x146, x147, x130, x148, x149, x131, x151, x135, x153, x140, x155, x145, x157, x158, x159, x160, x150, x161, x152, x154, x156, x162, x163, x164, x165; + x0 = _br2_load((in0)+((uintptr_t)(UINTMAX_C(0))), sizeof(uintptr_t)); + x1 = _br2_load((in0)+((uintptr_t)(UINTMAX_C(8))), sizeof(uintptr_t)); + x2 = _br2_load((in0)+((uintptr_t)(UINTMAX_C(16))), sizeof(uintptr_t)); + x3 = _br2_load((in0)+((uintptr_t)(UINTMAX_C(24))), sizeof(uintptr_t)); + /*skip*/ + /*skip*/ + x4 = (x0)*(x3); + x5 = _br2_mulhuu((x0), (x3)); + x6 = (x0)*(x2); + x7 = _br2_mulhuu((x0), (x2)); + x8 = (x0)*(x1); + x9 = _br2_mulhuu((x0), (x1)); + x10 = (x3)*(x2); + x11 = _br2_mulhuu((x3), (x2)); + x12 = (x3)*(x1); + x13 = _br2_mulhuu((x3), (x1)); + x14 = (x9)+(x6); + x15 = (uintptr_t)((x14)<(x9)); + x16 = (x15)+(x7); + x17 = (uintptr_t)((x16)<(x7)); + x18 = (x16)+(x4); + x19 = (uintptr_t)((x18)<(x4)); + x20 = (x17)+(x19); + x21 = (x20)+(x5); + x22 = (uintptr_t)((x21)<(x5)); + x23 = (x21)+(x12); + x24 = (uintptr_t)((x23)<(x12)); + x25 = (x22)+(x24); + x26 = (x25)+(x13); + x27 = (uintptr_t)((x26)<(x13)); + x28 = (x26)+(x10); + x29 = (uintptr_t)((x28)<(x10)); + x30 = (x27)+(x29); + x31 = (x30)+(x11); + x32 = (x1)*(x2); + x33 = _br2_mulhuu((x1), (x2)); + x34 = (x18)+(x32); + x35 = (uintptr_t)((x34)<(x18)); + x36 = (x35)+(x23); + x37 = (uintptr_t)((x36)<(x23)); + x38 = (x36)+(x33); + x39 = (uintptr_t)((x38)<(x33)); + x40 = (x37)+(x39); + x41 = (x40)+(x28); + x42 = (uintptr_t)((x41)<(x28)); + x43 = (x42)+(x31); + x44 = (uintptr_t)((x43)<(x31)); + x45 = (x8)+(x8); + x46 = (uintptr_t)((x45)<(x8)); + x47 = (x46)+(x14); + x48 = (uintptr_t)((x47)<(x14)); + x49 = (x47)+(x14); + x50 = (uintptr_t)((x49)<(x14)); + x51 = (x48)+(x50); + x52 = (x51)+(x34); + x53 = (uintptr_t)((x52)<(x34)); + x54 = (x52)+(x34); + x55 = (uintptr_t)((x54)<(x34)); + x56 = (x53)+(x55); + x57 = (x56)+(x38); + x58 = (uintptr_t)((x57)<(x38)); + x59 = (x57)+(x38); + x60 = (uintptr_t)((x59)<(x38)); + x61 = (x58)+(x60); + x62 = (x61)+(x41); + x63 = (uintptr_t)((x62)<(x41)); + x64 = (x62)+(x41); + x65 = (uintptr_t)((x64)<(x41)); + x66 = (x63)+(x65); + x67 = (x66)+(x43); + x68 = (uintptr_t)((x67)<(x43)); + x69 = (x67)+(x43); + x70 = (uintptr_t)((x69)<(x43)); + x71 = (x68)+(x70); + x72 = ((x71)+(x44))+(x44); + x73 = (x3)*(x3); + x74 = _br2_mulhuu((x3), (x3)); + x75 = (x2)*(x2); + x76 = _br2_mulhuu((x2), (x2)); + x77 = (x1)*(x1); + x78 = _br2_mulhuu((x1), (x1)); + x79 = (x0)*(x0); + x80 = _br2_mulhuu((x0), (x0)); + x81 = (x45)+(x80); + x82 = (uintptr_t)((x81)<(x45)); + x83 = (x82)+(x49); + x84 = (uintptr_t)((x83)<(x49)); + x85 = (x83)+(x77); + x86 = (uintptr_t)((x85)<(x77)); + x87 = (x84)+(x86); + x88 = (x87)+(x54); + x89 = (uintptr_t)((x88)<(x54)); + x90 = (x88)+(x78); + x91 = (uintptr_t)((x90)<(x78)); + x92 = (x89)+(x91); + x93 = (x92)+(x59); + x94 = (uintptr_t)((x93)<(x59)); + x95 = (x93)+(x75); + x96 = (uintptr_t)((x95)<(x75)); + x97 = (x94)+(x96); + x98 = (x97)+(x64); + x99 = (uintptr_t)((x98)<(x64)); + x100 = (x98)+(x76); + x101 = (uintptr_t)((x100)<(x76)); + x102 = (x99)+(x101); + x103 = (x102)+(x69); + x104 = (uintptr_t)((x103)<(x69)); + x105 = (x103)+(x73); + x106 = (uintptr_t)((x105)<(x73)); + x107 = (x104)+(x106); + x108 = (x107)+(x72); + x109 = (x108)+(x74); + x110 = ((uintptr_t)(UINTMAX_C(38)))*(x109); + x111 = _br2_mulhuu(((uintptr_t)(UINTMAX_C(38))), (x109)); + x112 = ((uintptr_t)(UINTMAX_C(38)))*(x105); + x113 = _br2_mulhuu(((uintptr_t)(UINTMAX_C(38))), (x105)); + x114 = ((uintptr_t)(UINTMAX_C(38)))*(x100); + x115 = _br2_mulhuu(((uintptr_t)(UINTMAX_C(38))), (x100)); + x116 = ((uintptr_t)(UINTMAX_C(38)))*(x95); + x117 = _br2_mulhuu(((uintptr_t)(UINTMAX_C(38))), (x95)); + x118 = (x81)+(x114); + x119 = (uintptr_t)((x118)<(x81)); + x120 = (x119)+(x85); + x121 = (uintptr_t)((x120)<(x85)); + x122 = (x120)+(x112); + x123 = (uintptr_t)((x122)<(x112)); + x124 = (x121)+(x123); + x125 = (x124)+(x90); + x126 = (uintptr_t)((x125)<(x90)); + x127 = (x125)+(x110); + x128 = (uintptr_t)((x127)<(x110)); + x129 = (x126)+(x128); + x130 = (x129)+(x111); + x131 = (x79)+(x116); + x132 = (uintptr_t)((x131)<(x79)); + x133 = (x132)+(x118); + x134 = (uintptr_t)((x133)<(x118)); + x135 = (x133)+(x117); + x136 = (uintptr_t)((x135)<(x117)); + x137 = (x134)+(x136); + x138 = (x137)+(x122); + x139 = (uintptr_t)((x138)<(x122)); + x140 = (x138)+(x115); + x141 = (uintptr_t)((x140)<(x115)); + x142 = (x139)+(x141); + x143 = (x142)+(x127); + x144 = (uintptr_t)((x143)<(x127)); + x145 = (x143)+(x113); + x146 = (uintptr_t)((x145)<(x113)); + x147 = (x144)+(x146); + x148 = (x147)+(x130); + x149 = ((uintptr_t)(UINTMAX_C(38)))*(x148); + x150 = (x131)+(x149); + x151 = (uintptr_t)((x150)<(x131)); + x152 = (x151)+(x135); + x153 = (uintptr_t)((x152)<(x135)); + x154 = (x153)+(x140); + x155 = (uintptr_t)((x154)<(x140)); + x156 = (x155)+(x145); + x157 = (uintptr_t)((x156)<(x145)); + x158 = ((uintptr_t)(UINTMAX_C(-1)))+((uintptr_t)((x157)==((uintptr_t)(UINTMAX_C(0))))); + x159 = (x158)^((uintptr_t)(UINTMAX_C(18446744073709551615))); + x160 = (((uintptr_t)(UINTMAX_C(38)))&(x158))|(((uintptr_t)(UINTMAX_C(0)))&(x159)); + x161 = (x160)+(x150); + x162 = x161; + x163 = x152; + x164 = x154; + x165 = x156; + /*skip*/ + _br2_store((out0)+((uintptr_t)(UINTMAX_C(0))), x162, sizeof(uintptr_t)); + _br2_store((out0)+((uintptr_t)(UINTMAX_C(8))), x163, sizeof(uintptr_t)); + _br2_store((out0)+((uintptr_t)(UINTMAX_C(16))), x164, sizeof(uintptr_t)); + _br2_store((out0)+((uintptr_t)(UINTMAX_C(24))), x165, sizeof(uintptr_t)); + /*skip*/ + return; +} + +/* NOTE: The following wrapper function is not covered by Coq proofs */ +static void fiat_curve25519_solinas_square(uint64_t out1[4], const uint64_t arg1[4]) { + internal_fiat_curve25519_solinas_square((uintptr_t)out1, (uintptr_t)arg1); +} diff --git a/fiat-c/src/curve25519_solinas_64.c b/fiat-c/src/curve25519_solinas_64.c new file mode 100644 index 0000000000..3448f17d51 --- /dev/null +++ b/fiat-c/src/curve25519_solinas_64.c @@ -0,0 +1,528 @@ +/* Autogenerated: 'src/ExtractionOCaml/solinas_reduction' --inline --static --use-value-barrier curve25519_solinas 64 '2^255 - 19' mul square */ +/* curve description: curve25519_solinas */ +/* machine_wordsize = 64 (from "64") */ +/* requested operations: mul, square */ +/* s-c = 2^255 - [(1, 19)] (from "2^255 - 19") */ +/* */ +/* Computed values: */ +/* */ + +#include +typedef unsigned char fiat_curve25519_solinas_uint1; +typedef signed char fiat_curve25519_solinas_int1; +#if defined(__GNUC__) || defined(__clang__) +# define FIAT_CURVE25519_SOLINAS_FIAT_EXTENSION __extension__ +# define FIAT_CURVE25519_SOLINAS_FIAT_INLINE __inline__ +#else +# define FIAT_CURVE25519_SOLINAS_FIAT_EXTENSION +# define FIAT_CURVE25519_SOLINAS_FIAT_INLINE +#endif + +FIAT_CURVE25519_SOLINAS_FIAT_EXTENSION typedef signed __int128 fiat_curve25519_solinas_int128; +FIAT_CURVE25519_SOLINAS_FIAT_EXTENSION typedef unsigned __int128 fiat_curve25519_solinas_uint128; + +#if (-1 & 3) != 3 +#error "This code only works on a two's complement system" +#endif + +#if !defined(FIAT_CURVE25519_SOLINAS_NO_ASM) && (defined(__GNUC__) || defined(__clang__)) +static __inline__ uint64_t fiat_curve25519_solinas_value_barrier_u64(uint64_t a) { + __asm__("" : "+r"(a) : /* no inputs */); + return a; +} +#else +# define fiat_curve25519_solinas_value_barrier_u64(x) (x) +#endif + + +/* + * The function fiat_curve25519_solinas_addcarryx_u64 is an addition with carry. + * + * Postconditions: + * out1 = (arg1 + arg2 + arg3) mod 2^64 + * out2 = ⌊(arg1 + arg2 + arg3) / 2^64⌋ + * + * Input Bounds: + * arg1: [0x0 ~> 0x1] + * arg2: [0x0 ~> 0xffffffffffffffff] + * arg3: [0x0 ~> 0xffffffffffffffff] + * Output Bounds: + * out1: [0x0 ~> 0xffffffffffffffff] + * out2: [0x0 ~> 0x1] + */ +static FIAT_CURVE25519_SOLINAS_FIAT_INLINE void fiat_curve25519_solinas_addcarryx_u64(uint64_t* out1, fiat_curve25519_solinas_uint1* out2, fiat_curve25519_solinas_uint1 arg1, uint64_t arg2, uint64_t arg3) { + fiat_curve25519_solinas_uint128 x1; + uint64_t x2; + fiat_curve25519_solinas_uint1 x3; + x1 = ((arg1 + (fiat_curve25519_solinas_uint128)arg2) + arg3); + x2 = (uint64_t)(x1 & UINT64_C(0xffffffffffffffff)); + x3 = (fiat_curve25519_solinas_uint1)(x1 >> 64); + *out1 = x2; + *out2 = x3; +} + +/* + * The function fiat_curve25519_solinas_subborrowx_u64 is a subtraction with borrow. + * + * Postconditions: + * out1 = (-arg1 + arg2 + -arg3) mod 2^64 + * out2 = -⌊(-arg1 + arg2 + -arg3) / 2^64⌋ + * + * Input Bounds: + * arg1: [0x0 ~> 0x1] + * arg2: [0x0 ~> 0xffffffffffffffff] + * arg3: [0x0 ~> 0xffffffffffffffff] + * Output Bounds: + * out1: [0x0 ~> 0xffffffffffffffff] + * out2: [0x0 ~> 0x1] + */ +static FIAT_CURVE25519_SOLINAS_FIAT_INLINE void fiat_curve25519_solinas_subborrowx_u64(uint64_t* out1, fiat_curve25519_solinas_uint1* out2, fiat_curve25519_solinas_uint1 arg1, uint64_t arg2, uint64_t arg3) { + fiat_curve25519_solinas_int128 x1; + fiat_curve25519_solinas_int1 x2; + uint64_t x3; + x1 = ((arg2 - (fiat_curve25519_solinas_int128)arg1) - arg3); + x2 = (fiat_curve25519_solinas_int1)(x1 >> 64); + x3 = (uint64_t)(x1 & UINT64_C(0xffffffffffffffff)); + *out1 = x3; + *out2 = (fiat_curve25519_solinas_uint1)(0x0 - x2); +} + +/* + * The function fiat_curve25519_solinas_mulx_u64 is a multiplication, returning the full double-width result. + * + * Postconditions: + * out1 = (arg1 * arg2) mod 2^64 + * out2 = ⌊arg1 * arg2 / 2^64⌋ + * + * Input Bounds: + * arg1: [0x0 ~> 0xffffffffffffffff] + * arg2: [0x0 ~> 0xffffffffffffffff] + * Output Bounds: + * out1: [0x0 ~> 0xffffffffffffffff] + * out2: [0x0 ~> 0xffffffffffffffff] + */ +static FIAT_CURVE25519_SOLINAS_FIAT_INLINE void fiat_curve25519_solinas_mulx_u64(uint64_t* out1, uint64_t* out2, uint64_t arg1, uint64_t arg2) { + fiat_curve25519_solinas_uint128 x1; + uint64_t x2; + uint64_t x3; + x1 = ((fiat_curve25519_solinas_uint128)arg1 * arg2); + x2 = (uint64_t)(x1 & UINT64_C(0xffffffffffffffff)); + x3 = (uint64_t)(x1 >> 64); + *out1 = x2; + *out2 = x3; +} + +/* + * The function fiat_curve25519_solinas_cmovznz_u64 is a single-word conditional move. + * + * Postconditions: + * out1 = (if arg1 = 0 then arg2 else arg3) + * + * Input Bounds: + * arg1: [0x0 ~> 0x1] + * arg2: [0x0 ~> 0xffffffffffffffff] + * arg3: [0x0 ~> 0xffffffffffffffff] + * Output Bounds: + * out1: [0x0 ~> 0xffffffffffffffff] + */ +static FIAT_CURVE25519_SOLINAS_FIAT_INLINE void fiat_curve25519_solinas_cmovznz_u64(uint64_t* out1, fiat_curve25519_solinas_uint1 arg1, uint64_t arg2, uint64_t arg3) { + fiat_curve25519_solinas_uint1 x1; + uint64_t x2; + uint64_t x3; + x1 = (!(!arg1)); + x2 = ((fiat_curve25519_solinas_int1)(0x0 - x1) & UINT64_C(0xffffffffffffffff)); + x3 = ((fiat_curve25519_solinas_value_barrier_u64(x2) & arg3) | (fiat_curve25519_solinas_value_barrier_u64((~x2)) & arg2)); + *out1 = x3; +} + +/* + * The function fiat_curve25519_solinas_mul multiplies two field elements. + * + * Postconditions: + * eval out1 mod 57896044618658097711785492504343953926634992332820282019728792003956564819949 = (eval arg1 * eval arg2) mod 57896044618658097711785492504343953926634992332820282019728792003956564819949 + * + * Input Bounds: + * arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] + * arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] + * Output Bounds: + * out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] + */ +static FIAT_CURVE25519_SOLINAS_FIAT_INLINE void fiat_curve25519_solinas_mul(uint64_t out1[4], const uint64_t arg1[4], const uint64_t arg2[4]) { + uint64_t x1; + uint64_t x2; + uint64_t x3; + uint64_t x4; + uint64_t x5; + uint64_t x6; + uint64_t x7; + uint64_t x8; + uint64_t x9; + uint64_t x10; + uint64_t x11; + uint64_t x12; + uint64_t x13; + uint64_t x14; + uint64_t x15; + uint64_t x16; + uint64_t x17; + uint64_t x18; + uint64_t x19; + uint64_t x20; + uint64_t x21; + uint64_t x22; + uint64_t x23; + uint64_t x24; + uint64_t x25; + uint64_t x26; + uint64_t x27; + uint64_t x28; + uint64_t x29; + uint64_t x30; + uint64_t x31; + uint64_t x32; + uint64_t x33; + fiat_curve25519_solinas_uint1 x34; + uint64_t x35; + fiat_curve25519_solinas_uint1 x36; + uint64_t x37; + uint64_t x38; + fiat_curve25519_solinas_uint1 x39; + uint64_t x40; + fiat_curve25519_solinas_uint1 x41; + uint64_t x42; + fiat_curve25519_solinas_uint1 x43; + uint64_t x44; + uint64_t x45; + fiat_curve25519_solinas_uint1 x46; + uint64_t x47; + fiat_curve25519_solinas_uint1 x48; + uint64_t x49; + fiat_curve25519_solinas_uint1 x50; + uint64_t x51; + fiat_curve25519_solinas_uint1 x52; + uint64_t x53; + fiat_curve25519_solinas_uint1 x54; + uint64_t x55; + uint64_t x56; + fiat_curve25519_solinas_uint1 x57; + uint64_t x58; + fiat_curve25519_solinas_uint1 x59; + uint64_t x60; + fiat_curve25519_solinas_uint1 x61; + uint64_t x62; + fiat_curve25519_solinas_uint1 x63; + uint64_t x64; + fiat_curve25519_solinas_uint1 x65; + uint64_t x66; + fiat_curve25519_solinas_uint1 x67; + uint64_t x68; + fiat_curve25519_solinas_uint1 x69; + uint64_t x70; + fiat_curve25519_solinas_uint1 x71; + uint64_t x72; + fiat_curve25519_solinas_uint1 x73; + uint64_t x74; + fiat_curve25519_solinas_uint1 x75; + uint64_t x76; + fiat_curve25519_solinas_uint1 x77; + uint64_t x78; + fiat_curve25519_solinas_uint1 x79; + uint64_t x80; + fiat_curve25519_solinas_uint1 x81; + uint64_t x82; + fiat_curve25519_solinas_uint1 x83; + uint64_t x84; + fiat_curve25519_solinas_uint1 x85; + uint64_t x86; + fiat_curve25519_solinas_uint1 x87; + uint64_t x88; + fiat_curve25519_solinas_uint1 x89; + uint64_t x90; + fiat_curve25519_solinas_uint1 x91; + uint64_t x92; + fiat_curve25519_solinas_uint1 x93; + uint64_t x94; + fiat_curve25519_solinas_uint1 x95; + uint64_t x96; + uint64_t x97; + uint64_t x98; + uint64_t x99; + uint64_t x100; + uint64_t x101; + uint64_t x102; + uint64_t x103; + uint64_t x104; + fiat_curve25519_solinas_uint1 x105; + uint64_t x106; + fiat_curve25519_solinas_uint1 x107; + uint64_t x108; + fiat_curve25519_solinas_uint1 x109; + uint64_t x110; + uint64_t x111; + fiat_curve25519_solinas_uint1 x112; + uint64_t x113; + fiat_curve25519_solinas_uint1 x114; + uint64_t x115; + fiat_curve25519_solinas_uint1 x116; + uint64_t x117; + fiat_curve25519_solinas_uint1 x118; + uint64_t x119; + uint64_t x120; + uint64_t x121; + uint64_t x122; + fiat_curve25519_solinas_uint1 x123; + uint64_t x124; + fiat_curve25519_solinas_uint1 x125; + uint64_t x126; + fiat_curve25519_solinas_uint1 x127; + uint64_t x128; + fiat_curve25519_solinas_uint1 x129; + uint64_t x130; + uint64_t x131; + fiat_curve25519_solinas_uint1 x132; + fiat_curve25519_solinas_mulx_u64(&x1, &x2, (arg1[3]), (arg2[3])); + fiat_curve25519_solinas_mulx_u64(&x3, &x4, (arg1[3]), (arg2[2])); + fiat_curve25519_solinas_mulx_u64(&x5, &x6, (arg1[3]), (arg2[1])); + fiat_curve25519_solinas_mulx_u64(&x7, &x8, (arg1[3]), (arg2[0])); + fiat_curve25519_solinas_mulx_u64(&x9, &x10, (arg1[2]), (arg2[3])); + fiat_curve25519_solinas_mulx_u64(&x11, &x12, (arg1[2]), (arg2[2])); + fiat_curve25519_solinas_mulx_u64(&x13, &x14, (arg1[2]), (arg2[1])); + fiat_curve25519_solinas_mulx_u64(&x15, &x16, (arg1[2]), (arg2[0])); + fiat_curve25519_solinas_mulx_u64(&x17, &x18, (arg1[1]), (arg2[3])); + fiat_curve25519_solinas_mulx_u64(&x19, &x20, (arg1[1]), (arg2[2])); + fiat_curve25519_solinas_mulx_u64(&x21, &x22, (arg1[1]), (arg2[1])); + fiat_curve25519_solinas_mulx_u64(&x23, &x24, (arg1[1]), (arg2[0])); + fiat_curve25519_solinas_mulx_u64(&x25, &x26, (arg1[0]), (arg2[3])); + fiat_curve25519_solinas_mulx_u64(&x27, &x28, (arg1[0]), (arg2[2])); + fiat_curve25519_solinas_mulx_u64(&x29, &x30, (arg1[0]), (arg2[1])); + fiat_curve25519_solinas_mulx_u64(&x31, &x32, (arg1[0]), (arg2[0])); + fiat_curve25519_solinas_addcarryx_u64(&x33, &x34, 0x0, x28, x7); + fiat_curve25519_solinas_addcarryx_u64(&x35, &x36, x34, x26, x5); + x37 = (x36 + x18); + fiat_curve25519_solinas_addcarryx_u64(&x38, &x39, 0x0, x33, x13); + fiat_curve25519_solinas_addcarryx_u64(&x40, &x41, x39, x35, x8); + fiat_curve25519_solinas_addcarryx_u64(&x42, &x43, x41, x37, 0x0); + x44 = (x43 + x10); + fiat_curve25519_solinas_addcarryx_u64(&x45, &x46, 0x0, x30, x15); + fiat_curve25519_solinas_addcarryx_u64(&x47, &x48, x46, x38, x16); + fiat_curve25519_solinas_addcarryx_u64(&x49, &x50, x48, x40, x11); + fiat_curve25519_solinas_addcarryx_u64(&x51, &x52, x50, x42, x3); + fiat_curve25519_solinas_addcarryx_u64(&x53, &x54, x52, x44, 0x0); + x55 = (x54 + x2); + fiat_curve25519_solinas_addcarryx_u64(&x56, &x57, 0x0, x45, x21); + fiat_curve25519_solinas_addcarryx_u64(&x58, &x59, x57, x47, x19); + fiat_curve25519_solinas_addcarryx_u64(&x60, &x61, x59, x49, x14); + fiat_curve25519_solinas_addcarryx_u64(&x62, &x63, x61, x51, x6); + fiat_curve25519_solinas_addcarryx_u64(&x64, &x65, x63, x53, 0x0); + fiat_curve25519_solinas_addcarryx_u64(&x66, &x67, x65, x55, 0x0); + fiat_curve25519_solinas_addcarryx_u64(&x68, &x69, 0x0, x32, x23); + fiat_curve25519_solinas_addcarryx_u64(&x70, &x71, x69, x56, x24); + fiat_curve25519_solinas_addcarryx_u64(&x72, &x73, x71, x58, x22); + fiat_curve25519_solinas_addcarryx_u64(&x74, &x75, x73, x60, x17); + fiat_curve25519_solinas_addcarryx_u64(&x76, &x77, x75, x62, x9); + fiat_curve25519_solinas_addcarryx_u64(&x78, &x79, x77, x64, x1); + fiat_curve25519_solinas_addcarryx_u64(&x80, &x81, x79, x66, 0x0); + fiat_curve25519_solinas_addcarryx_u64(&x82, &x83, 0x0, x68, x29); + fiat_curve25519_solinas_addcarryx_u64(&x84, &x85, x83, x70, x27); + fiat_curve25519_solinas_addcarryx_u64(&x86, &x87, x85, x72, x25); + fiat_curve25519_solinas_addcarryx_u64(&x88, &x89, x87, x74, x20); + fiat_curve25519_solinas_addcarryx_u64(&x90, &x91, x89, x76, x12); + fiat_curve25519_solinas_addcarryx_u64(&x92, &x93, x91, x78, x4); + fiat_curve25519_solinas_addcarryx_u64(&x94, &x95, x93, x80, 0x0); + fiat_curve25519_solinas_mulx_u64(&x96, &x97, UINT8_C(0x26), x94); + fiat_curve25519_solinas_mulx_u64(&x98, &x99, UINT8_C(0x26), x92); + fiat_curve25519_solinas_mulx_u64(&x100, &x101, UINT8_C(0x26), x90); + fiat_curve25519_solinas_mulx_u64(&x102, &x103, UINT8_C(0x26), x88); + fiat_curve25519_solinas_addcarryx_u64(&x104, &x105, 0x0, x82, x100); + fiat_curve25519_solinas_addcarryx_u64(&x106, &x107, x105, x84, x98); + fiat_curve25519_solinas_addcarryx_u64(&x108, &x109, x107, x86, x96); + x110 = (x109 + x97); + fiat_curve25519_solinas_addcarryx_u64(&x111, &x112, 0x0, x31, x102); + fiat_curve25519_solinas_addcarryx_u64(&x113, &x114, x112, x104, x103); + fiat_curve25519_solinas_addcarryx_u64(&x115, &x116, x114, x106, x101); + fiat_curve25519_solinas_addcarryx_u64(&x117, &x118, x116, x108, x99); + x119 = (x118 + x110); + fiat_curve25519_solinas_mulx_u64(&x120, &x121, UINT8_C(0x26), x119); + fiat_curve25519_solinas_addcarryx_u64(&x122, &x123, 0x0, x111, x120); + fiat_curve25519_solinas_addcarryx_u64(&x124, &x125, x123, x113, 0x0); + fiat_curve25519_solinas_addcarryx_u64(&x126, &x127, x125, x115, 0x0); + fiat_curve25519_solinas_addcarryx_u64(&x128, &x129, x127, x117, 0x0); + fiat_curve25519_solinas_cmovznz_u64(&x130, x129, 0x0, UINT8_C(0x26)); + fiat_curve25519_solinas_addcarryx_u64(&x131, &x132, 0x0, x130, x122); + out1[0] = x131; + out1[1] = x124; + out1[2] = x126; + out1[3] = x128; +} + +/* + * The function fiat_curve25519_solinas_square squares a field element. + * + * Postconditions: + * eval out1 mod 57896044618658097711785492504343953926634992332820282019728792003956564819949 = (eval arg1 * eval arg1) mod 57896044618658097711785492504343953926634992332820282019728792003956564819949 + * + * Input Bounds: + * arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] + * Output Bounds: + * out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] + */ +static FIAT_CURVE25519_SOLINAS_FIAT_INLINE void fiat_curve25519_solinas_square(uint64_t out1[4], const uint64_t arg1[4]) { + uint64_t x1; + uint64_t x2; + uint64_t x3; + uint64_t x4; + uint64_t x5; + uint64_t x6; + uint64_t x7; + uint64_t x8; + uint64_t x9; + uint64_t x10; + uint64_t x11; + fiat_curve25519_solinas_uint1 x12; + uint64_t x13; + fiat_curve25519_solinas_uint1 x14; + uint64_t x15; + fiat_curve25519_solinas_uint1 x16; + uint64_t x17; + fiat_curve25519_solinas_uint1 x18; + uint64_t x19; + uint64_t x20; + uint64_t x21; + uint64_t x22; + fiat_curve25519_solinas_uint1 x23; + uint64_t x24; + fiat_curve25519_solinas_uint1 x25; + uint64_t x26; + fiat_curve25519_solinas_uint1 x27; + uint64_t x28; + fiat_curve25519_solinas_uint1 x29; + uint64_t x30; + fiat_curve25519_solinas_uint1 x31; + uint64_t x32; + fiat_curve25519_solinas_uint1 x33; + uint64_t x34; + fiat_curve25519_solinas_uint1 x35; + uint64_t x36; + fiat_curve25519_solinas_uint1 x37; + uint64_t x38; + fiat_curve25519_solinas_uint1 x39; + uint64_t x40; + fiat_curve25519_solinas_uint1 x41; + uint64_t x42; + uint64_t x43; + uint64_t x44; + uint64_t x45; + uint64_t x46; + uint64_t x47; + uint64_t x48; + uint64_t x49; + uint64_t x50; + uint64_t x51; + fiat_curve25519_solinas_uint1 x52; + uint64_t x53; + fiat_curve25519_solinas_uint1 x54; + uint64_t x55; + fiat_curve25519_solinas_uint1 x56; + uint64_t x57; + fiat_curve25519_solinas_uint1 x58; + uint64_t x59; + fiat_curve25519_solinas_uint1 x60; + uint64_t x61; + fiat_curve25519_solinas_uint1 x62; + uint64_t x63; + fiat_curve25519_solinas_uint1 x64; + uint64_t x65; + uint64_t x66; + uint64_t x67; + uint64_t x68; + uint64_t x69; + uint64_t x70; + uint64_t x71; + uint64_t x72; + uint64_t x73; + fiat_curve25519_solinas_uint1 x74; + uint64_t x75; + fiat_curve25519_solinas_uint1 x76; + uint64_t x77; + fiat_curve25519_solinas_uint1 x78; + uint64_t x79; + uint64_t x80; + fiat_curve25519_solinas_uint1 x81; + uint64_t x82; + fiat_curve25519_solinas_uint1 x83; + uint64_t x84; + fiat_curve25519_solinas_uint1 x85; + uint64_t x86; + fiat_curve25519_solinas_uint1 x87; + uint64_t x88; + uint64_t x89; + uint64_t x90; + uint64_t x91; + fiat_curve25519_solinas_uint1 x92; + uint64_t x93; + fiat_curve25519_solinas_uint1 x94; + uint64_t x95; + fiat_curve25519_solinas_uint1 x96; + uint64_t x97; + fiat_curve25519_solinas_uint1 x98; + uint64_t x99; + uint64_t x100; + fiat_curve25519_solinas_uint1 x101; + fiat_curve25519_solinas_mulx_u64(&x1, &x2, (arg1[0]), (arg1[3])); + fiat_curve25519_solinas_mulx_u64(&x3, &x4, (arg1[0]), (arg1[2])); + fiat_curve25519_solinas_mulx_u64(&x5, &x6, (arg1[0]), (arg1[1])); + fiat_curve25519_solinas_mulx_u64(&x7, &x8, (arg1[3]), (arg1[2])); + fiat_curve25519_solinas_mulx_u64(&x9, &x10, (arg1[3]), (arg1[1])); + fiat_curve25519_solinas_addcarryx_u64(&x11, &x12, 0x0, x6, x3); + fiat_curve25519_solinas_addcarryx_u64(&x13, &x14, x12, x4, x1); + fiat_curve25519_solinas_addcarryx_u64(&x15, &x16, x14, x2, x9); + fiat_curve25519_solinas_addcarryx_u64(&x17, &x18, x16, x10, x7); + x19 = (x18 + x8); + fiat_curve25519_solinas_mulx_u64(&x20, &x21, (arg1[1]), (arg1[2])); + fiat_curve25519_solinas_addcarryx_u64(&x22, &x23, 0x0, x13, x20); + fiat_curve25519_solinas_addcarryx_u64(&x24, &x25, x23, x15, x21); + fiat_curve25519_solinas_addcarryx_u64(&x26, &x27, x25, x17, 0x0); + fiat_curve25519_solinas_addcarryx_u64(&x28, &x29, x27, x19, 0x0); + fiat_curve25519_solinas_addcarryx_u64(&x30, &x31, 0x0, x5, x5); + fiat_curve25519_solinas_addcarryx_u64(&x32, &x33, x31, x11, x11); + fiat_curve25519_solinas_addcarryx_u64(&x34, &x35, x33, x22, x22); + fiat_curve25519_solinas_addcarryx_u64(&x36, &x37, x35, x24, x24); + fiat_curve25519_solinas_addcarryx_u64(&x38, &x39, x37, x26, x26); + fiat_curve25519_solinas_addcarryx_u64(&x40, &x41, x39, x28, x28); + x42 = (((uint64_t)x41 + x29) + (uint64_t)x29); + fiat_curve25519_solinas_mulx_u64(&x43, &x44, (arg1[3]), (arg1[3])); + fiat_curve25519_solinas_mulx_u64(&x45, &x46, (arg1[2]), (arg1[2])); + fiat_curve25519_solinas_mulx_u64(&x47, &x48, (arg1[1]), (arg1[1])); + fiat_curve25519_solinas_mulx_u64(&x49, &x50, (arg1[0]), (arg1[0])); + fiat_curve25519_solinas_addcarryx_u64(&x51, &x52, 0x0, x30, x50); + fiat_curve25519_solinas_addcarryx_u64(&x53, &x54, x52, x32, x47); + fiat_curve25519_solinas_addcarryx_u64(&x55, &x56, x54, x34, x48); + fiat_curve25519_solinas_addcarryx_u64(&x57, &x58, x56, x36, x45); + fiat_curve25519_solinas_addcarryx_u64(&x59, &x60, x58, x38, x46); + fiat_curve25519_solinas_addcarryx_u64(&x61, &x62, x60, x40, x43); + fiat_curve25519_solinas_addcarryx_u64(&x63, &x64, x62, x42, x44); + fiat_curve25519_solinas_mulx_u64(&x65, &x66, UINT8_C(0x26), x63); + fiat_curve25519_solinas_mulx_u64(&x67, &x68, UINT8_C(0x26), x61); + fiat_curve25519_solinas_mulx_u64(&x69, &x70, UINT8_C(0x26), x59); + fiat_curve25519_solinas_mulx_u64(&x71, &x72, UINT8_C(0x26), x57); + fiat_curve25519_solinas_addcarryx_u64(&x73, &x74, 0x0, x51, x69); + fiat_curve25519_solinas_addcarryx_u64(&x75, &x76, x74, x53, x67); + fiat_curve25519_solinas_addcarryx_u64(&x77, &x78, x76, x55, x65); + x79 = (x78 + x66); + fiat_curve25519_solinas_addcarryx_u64(&x80, &x81, 0x0, x49, x71); + fiat_curve25519_solinas_addcarryx_u64(&x82, &x83, x81, x73, x72); + fiat_curve25519_solinas_addcarryx_u64(&x84, &x85, x83, x75, x70); + fiat_curve25519_solinas_addcarryx_u64(&x86, &x87, x85, x77, x68); + x88 = (x87 + x79); + fiat_curve25519_solinas_mulx_u64(&x89, &x90, UINT8_C(0x26), x88); + fiat_curve25519_solinas_addcarryx_u64(&x91, &x92, 0x0, x80, x89); + fiat_curve25519_solinas_addcarryx_u64(&x93, &x94, x92, x82, 0x0); + fiat_curve25519_solinas_addcarryx_u64(&x95, &x96, x94, x84, 0x0); + fiat_curve25519_solinas_addcarryx_u64(&x97, &x98, x96, x86, 0x0); + fiat_curve25519_solinas_cmovznz_u64(&x99, x98, 0x0, UINT8_C(0x26)); + fiat_curve25519_solinas_addcarryx_u64(&x100, &x101, 0x0, x99, x91); + out1[0] = x100; + out1[1] = x93; + out1[2] = x95; + out1[3] = x97; +} diff --git a/fiat-go/64/curve25519solinas/curve25519solinas.go b/fiat-go/64/curve25519solinas/curve25519solinas.go new file mode 100644 index 0000000000..4bab5cc64d --- /dev/null +++ b/fiat-go/64/curve25519solinas/curve25519solinas.go @@ -0,0 +1,411 @@ +// Code generated by Fiat Cryptography. DO NOT EDIT. +// +// Autogenerated: 'src/ExtractionOCaml/solinas_reduction' --lang Go --no-wide-int --relax-primitive-carry-to-bitwidth 32,64 --cmovznz-by-mul --internal-static --package-case flatcase --public-function-case UpperCamelCase --private-function-case camelCase --public-type-case UpperCamelCase --private-type-case camelCase --no-prefix-fiat --doc-newline-in-typedef-bounds --doc-prepend-header 'Code generated by Fiat Cryptography. DO NOT EDIT.' --doc-text-before-function-name '' --doc-text-before-type-name '' --package-name curve25519solinas '' 64 '2^255 - 19' mul square +// +// curve description (via package name): curve25519solinas +// +// machine_wordsize = 64 (from "64") +// +// requested operations: mul, square +// +// s-c = 2^255 - [(1, 19)] (from "2^255 - 19") +// +// +// +// Computed values: +// +// +package curve25519solinas + +import "math/bits" + +type uint1 uint64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927 +type int1 int64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927 + +// cmovznzU64 is a single-word conditional move. +// +// Postconditions: +// out1 = (if arg1 = 0 then arg2 else arg3) +// +// Input Bounds: +// arg1: [0x0 ~> 0x1] +// arg2: [0x0 ~> 0xffffffffffffffff] +// arg3: [0x0 ~> 0xffffffffffffffff] +// Output Bounds: +// out1: [0x0 ~> 0xffffffffffffffff] +func cmovznzU64(out1 *uint64, arg1 uint1, arg2 uint64, arg3 uint64) { + x1 := (uint64(arg1) * 0xffffffffffffffff) + x2 := ((x1 & arg3) | ((^x1) & arg2)) + *out1 = x2 +} + +// Mul multiplies two field elements. +// +// Postconditions: +// eval out1 mod 57896044618658097711785492504343953926634992332820282019728792003956564819949 = (eval arg1 * eval arg2) mod 57896044618658097711785492504343953926634992332820282019728792003956564819949 +// +// Input Bounds: +// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// Output Bounds: +// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +func Mul(out1 *[4]uint64, arg1 *[4]uint64, arg2 *[4]uint64) { + var x1 uint64 + var x2 uint64 + x2, x1 = bits.Mul64(arg1[3], arg2[3]) + var x3 uint64 + var x4 uint64 + x4, x3 = bits.Mul64(arg1[3], arg2[2]) + var x5 uint64 + var x6 uint64 + x6, x5 = bits.Mul64(arg1[3], arg2[1]) + var x7 uint64 + var x8 uint64 + x8, x7 = bits.Mul64(arg1[3], arg2[0]) + var x9 uint64 + var x10 uint64 + x10, x9 = bits.Mul64(arg1[2], arg2[3]) + var x11 uint64 + var x12 uint64 + x12, x11 = bits.Mul64(arg1[2], arg2[2]) + var x13 uint64 + var x14 uint64 + x14, x13 = bits.Mul64(arg1[2], arg2[1]) + var x15 uint64 + var x16 uint64 + x16, x15 = bits.Mul64(arg1[2], arg2[0]) + var x17 uint64 + var x18 uint64 + x18, x17 = bits.Mul64(arg1[1], arg2[3]) + var x19 uint64 + var x20 uint64 + x20, x19 = bits.Mul64(arg1[1], arg2[2]) + var x21 uint64 + var x22 uint64 + x22, x21 = bits.Mul64(arg1[1], arg2[1]) + var x23 uint64 + var x24 uint64 + x24, x23 = bits.Mul64(arg1[1], arg2[0]) + var x25 uint64 + var x26 uint64 + x26, x25 = bits.Mul64(arg1[0], arg2[3]) + var x27 uint64 + var x28 uint64 + x28, x27 = bits.Mul64(arg1[0], arg2[2]) + var x29 uint64 + var x30 uint64 + x30, x29 = bits.Mul64(arg1[0], arg2[1]) + var x31 uint64 + var x32 uint64 + x32, x31 = bits.Mul64(arg1[0], arg2[0]) + var x33 uint64 + var x34 uint64 + x33, x34 = bits.Add64(x28, x7, uint64(0x0)) + var x35 uint64 + var x36 uint64 + x35, x36 = bits.Add64(x26, x5, uint64(uint1(x34))) + x37 := (uint64(uint1(x36)) + x18) + var x38 uint64 + var x39 uint64 + x38, x39 = bits.Add64(x33, x13, uint64(0x0)) + var x40 uint64 + var x41 uint64 + x40, x41 = bits.Add64(x35, x8, uint64(uint1(x39))) + var x42 uint64 + var x43 uint64 + x42, x43 = bits.Add64(x37, uint64(0x0), uint64(uint1(x41))) + x44 := (uint64(uint1(x43)) + x10) + var x45 uint64 + var x46 uint64 + x45, x46 = bits.Add64(x30, x15, uint64(0x0)) + var x47 uint64 + var x48 uint64 + x47, x48 = bits.Add64(x38, x16, uint64(uint1(x46))) + var x49 uint64 + var x50 uint64 + x49, x50 = bits.Add64(x40, x11, uint64(uint1(x48))) + var x51 uint64 + var x52 uint64 + x51, x52 = bits.Add64(x42, x3, uint64(uint1(x50))) + var x53 uint64 + var x54 uint64 + x53, x54 = bits.Add64(x44, uint64(0x0), uint64(uint1(x52))) + x55 := (uint64(uint1(x54)) + x2) + var x56 uint64 + var x57 uint64 + x56, x57 = bits.Add64(x45, x21, uint64(0x0)) + var x58 uint64 + var x59 uint64 + x58, x59 = bits.Add64(x47, x19, uint64(uint1(x57))) + var x60 uint64 + var x61 uint64 + x60, x61 = bits.Add64(x49, x14, uint64(uint1(x59))) + var x62 uint64 + var x63 uint64 + x62, x63 = bits.Add64(x51, x6, uint64(uint1(x61))) + var x64 uint64 + var x65 uint64 + x64, x65 = bits.Add64(x53, uint64(0x0), uint64(uint1(x63))) + var x66 uint64 + x66, _ = bits.Add64(x55, uint64(0x0), uint64(uint1(x65))) + var x68 uint64 + var x69 uint64 + x68, x69 = bits.Add64(x32, x23, uint64(0x0)) + var x70 uint64 + var x71 uint64 + x70, x71 = bits.Add64(x56, x24, uint64(uint1(x69))) + var x72 uint64 + var x73 uint64 + x72, x73 = bits.Add64(x58, x22, uint64(uint1(x71))) + var x74 uint64 + var x75 uint64 + x74, x75 = bits.Add64(x60, x17, uint64(uint1(x73))) + var x76 uint64 + var x77 uint64 + x76, x77 = bits.Add64(x62, x9, uint64(uint1(x75))) + var x78 uint64 + var x79 uint64 + x78, x79 = bits.Add64(x64, x1, uint64(uint1(x77))) + var x80 uint64 + x80, _ = bits.Add64(x66, uint64(0x0), uint64(uint1(x79))) + var x82 uint64 + var x83 uint64 + x82, x83 = bits.Add64(x68, x29, uint64(0x0)) + var x84 uint64 + var x85 uint64 + x84, x85 = bits.Add64(x70, x27, uint64(uint1(x83))) + var x86 uint64 + var x87 uint64 + x86, x87 = bits.Add64(x72, x25, uint64(uint1(x85))) + var x88 uint64 + var x89 uint64 + x88, x89 = bits.Add64(x74, x20, uint64(uint1(x87))) + var x90 uint64 + var x91 uint64 + x90, x91 = bits.Add64(x76, x12, uint64(uint1(x89))) + var x92 uint64 + var x93 uint64 + x92, x93 = bits.Add64(x78, x4, uint64(uint1(x91))) + var x94 uint64 + x94, _ = bits.Add64(x80, uint64(0x0), uint64(uint1(x93))) + var x96 uint64 + var x97 uint64 + x97, x96 = bits.Mul64(0x26, x94) + var x98 uint64 + var x99 uint64 + x99, x98 = bits.Mul64(0x26, x92) + var x100 uint64 + var x101 uint64 + x101, x100 = bits.Mul64(0x26, x90) + var x102 uint64 + var x103 uint64 + x103, x102 = bits.Mul64(0x26, x88) + var x104 uint64 + var x105 uint64 + x104, x105 = bits.Add64(x82, x100, uint64(0x0)) + var x106 uint64 + var x107 uint64 + x106, x107 = bits.Add64(x84, x98, uint64(uint1(x105))) + var x108 uint64 + var x109 uint64 + x108, x109 = bits.Add64(x86, x96, uint64(uint1(x107))) + x110 := (uint64(uint1(x109)) + x97) + var x111 uint64 + var x112 uint64 + x111, x112 = bits.Add64(x31, x102, uint64(0x0)) + var x113 uint64 + var x114 uint64 + x113, x114 = bits.Add64(x104, x103, uint64(uint1(x112))) + var x115 uint64 + var x116 uint64 + x115, x116 = bits.Add64(x106, x101, uint64(uint1(x114))) + var x117 uint64 + var x118 uint64 + x117, x118 = bits.Add64(x108, x99, uint64(uint1(x116))) + x119 := (uint64(uint1(x118)) + x110) + var x120 uint64 + _, x120 = bits.Mul64(0x26, x119) + var x122 uint64 + var x123 uint64 + x122, x123 = bits.Add64(x111, x120, uint64(0x0)) + var x124 uint64 + var x125 uint64 + x124, x125 = bits.Add64(x113, uint64(0x0), uint64(uint1(x123))) + var x126 uint64 + var x127 uint64 + x126, x127 = bits.Add64(x115, uint64(0x0), uint64(uint1(x125))) + var x128 uint64 + var x129 uint64 + x128, x129 = bits.Add64(x117, uint64(0x0), uint64(uint1(x127))) + var x130 uint64 + cmovznzU64(&x130, uint1(x129), uint64(0x0), 0x26) + var x131 uint64 + x131, _ = bits.Add64(x130, x122, uint64(0x0)) + out1[0] = x131 + out1[1] = x124 + out1[2] = x126 + out1[3] = x128 +} + +// Square squares a field element. +// +// Postconditions: +// eval out1 mod 57896044618658097711785492504343953926634992332820282019728792003956564819949 = (eval arg1 * eval arg1) mod 57896044618658097711785492504343953926634992332820282019728792003956564819949 +// +// Input Bounds: +// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +// Output Bounds: +// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +func Square(out1 *[4]uint64, arg1 *[4]uint64) { + var x1 uint64 + var x2 uint64 + x2, x1 = bits.Mul64(arg1[0], arg1[3]) + var x3 uint64 + var x4 uint64 + x4, x3 = bits.Mul64(arg1[0], arg1[2]) + var x5 uint64 + var x6 uint64 + x6, x5 = bits.Mul64(arg1[0], arg1[1]) + var x7 uint64 + var x8 uint64 + x8, x7 = bits.Mul64(arg1[3], arg1[2]) + var x9 uint64 + var x10 uint64 + x10, x9 = bits.Mul64(arg1[3], arg1[1]) + var x11 uint64 + var x12 uint64 + x11, x12 = bits.Add64(x6, x3, uint64(0x0)) + var x13 uint64 + var x14 uint64 + x13, x14 = bits.Add64(x4, x1, uint64(uint1(x12))) + var x15 uint64 + var x16 uint64 + x15, x16 = bits.Add64(x2, x9, uint64(uint1(x14))) + var x17 uint64 + var x18 uint64 + x17, x18 = bits.Add64(x10, x7, uint64(uint1(x16))) + x19 := (uint64(uint1(x18)) + x8) + var x20 uint64 + var x21 uint64 + x21, x20 = bits.Mul64(arg1[1], arg1[2]) + var x22 uint64 + var x23 uint64 + x22, x23 = bits.Add64(x13, x20, uint64(0x0)) + var x24 uint64 + var x25 uint64 + x24, x25 = bits.Add64(x15, x21, uint64(uint1(x23))) + var x26 uint64 + var x27 uint64 + x26, x27 = bits.Add64(x17, uint64(0x0), uint64(uint1(x25))) + var x28 uint64 + var x29 uint64 + x28, x29 = bits.Add64(x19, uint64(0x0), uint64(uint1(x27))) + var x30 uint64 + var x31 uint64 + x30, x31 = bits.Add64(x5, x5, uint64(0x0)) + var x32 uint64 + var x33 uint64 + x32, x33 = bits.Add64(x11, x11, uint64(uint1(x31))) + var x34 uint64 + var x35 uint64 + x34, x35 = bits.Add64(x22, x22, uint64(uint1(x33))) + var x36 uint64 + var x37 uint64 + x36, x37 = bits.Add64(x24, x24, uint64(uint1(x35))) + var x38 uint64 + var x39 uint64 + x38, x39 = bits.Add64(x26, x26, uint64(uint1(x37))) + var x40 uint64 + var x41 uint64 + x40, x41 = bits.Add64(x28, x28, uint64(uint1(x39))) + x42 := ((uint64(uint1(x41)) + uint64(uint1(x29))) + uint64(uint1(x29))) + var x43 uint64 + var x44 uint64 + x44, x43 = bits.Mul64(arg1[3], arg1[3]) + var x45 uint64 + var x46 uint64 + x46, x45 = bits.Mul64(arg1[2], arg1[2]) + var x47 uint64 + var x48 uint64 + x48, x47 = bits.Mul64(arg1[1], arg1[1]) + var x49 uint64 + var x50 uint64 + x50, x49 = bits.Mul64(arg1[0], arg1[0]) + var x51 uint64 + var x52 uint64 + x51, x52 = bits.Add64(x30, x50, uint64(0x0)) + var x53 uint64 + var x54 uint64 + x53, x54 = bits.Add64(x32, x47, uint64(uint1(x52))) + var x55 uint64 + var x56 uint64 + x55, x56 = bits.Add64(x34, x48, uint64(uint1(x54))) + var x57 uint64 + var x58 uint64 + x57, x58 = bits.Add64(x36, x45, uint64(uint1(x56))) + var x59 uint64 + var x60 uint64 + x59, x60 = bits.Add64(x38, x46, uint64(uint1(x58))) + var x61 uint64 + var x62 uint64 + x61, x62 = bits.Add64(x40, x43, uint64(uint1(x60))) + var x63 uint64 + x63, _ = bits.Add64(x42, x44, uint64(uint1(x62))) + var x65 uint64 + var x66 uint64 + x66, x65 = bits.Mul64(0x26, x63) + var x67 uint64 + var x68 uint64 + x68, x67 = bits.Mul64(0x26, x61) + var x69 uint64 + var x70 uint64 + x70, x69 = bits.Mul64(0x26, x59) + var x71 uint64 + var x72 uint64 + x72, x71 = bits.Mul64(0x26, x57) + var x73 uint64 + var x74 uint64 + x73, x74 = bits.Add64(x51, x69, uint64(0x0)) + var x75 uint64 + var x76 uint64 + x75, x76 = bits.Add64(x53, x67, uint64(uint1(x74))) + var x77 uint64 + var x78 uint64 + x77, x78 = bits.Add64(x55, x65, uint64(uint1(x76))) + x79 := (uint64(uint1(x78)) + x66) + var x80 uint64 + var x81 uint64 + x80, x81 = bits.Add64(x49, x71, uint64(0x0)) + var x82 uint64 + var x83 uint64 + x82, x83 = bits.Add64(x73, x72, uint64(uint1(x81))) + var x84 uint64 + var x85 uint64 + x84, x85 = bits.Add64(x75, x70, uint64(uint1(x83))) + var x86 uint64 + var x87 uint64 + x86, x87 = bits.Add64(x77, x68, uint64(uint1(x85))) + x88 := (uint64(uint1(x87)) + x79) + var x89 uint64 + _, x89 = bits.Mul64(0x26, x88) + var x91 uint64 + var x92 uint64 + x91, x92 = bits.Add64(x80, x89, uint64(0x0)) + var x93 uint64 + var x94 uint64 + x93, x94 = bits.Add64(x82, uint64(0x0), uint64(uint1(x92))) + var x95 uint64 + var x96 uint64 + x95, x96 = bits.Add64(x84, uint64(0x0), uint64(uint1(x94))) + var x97 uint64 + var x98 uint64 + x97, x98 = bits.Add64(x86, uint64(0x0), uint64(uint1(x96))) + var x99 uint64 + cmovznzU64(&x99, uint1(x98), uint64(0x0), 0x26) + var x100 uint64 + x100, _ = bits.Add64(x99, x91, uint64(0x0)) + out1[0] = x100 + out1[1] = x93 + out1[2] = x95 + out1[3] = x97 +} diff --git a/fiat-json/src/curve25519_solinas_64.json b/fiat-json/src/curve25519_solinas_64.json new file mode 100644 index 0000000000..ca853b7dd8 --- /dev/null +++ b/fiat-json/src/curve25519_solinas_64.json @@ -0,0 +1,6287 @@ +[ + { + "operation": "fiat_curve25519_solinas_addcarryx_u64", + "arguments": [ + { + "datatype": "u1", + "name": "arg1", + "lbound": "0x0", + "ubound": "0x1" + }, + { + "datatype": "u64", + "name": "arg2", + "lbound": "0x0", + "ubound": "0xffffffffffffffff" + }, + { + "datatype": "u64", + "name": "arg3", + "lbound": "0x0", + "ubound": "0xffffffffffffffff" + } + ], + "returns": [ + { + "datatype": "u64", + "name": "out1", + "lbound": "0x0", + "ubound": "0xffffffffffffffff" + }, + { + "datatype": "u1", + "name": "out2", + "lbound": "0x0", + "ubound": "0x1" + } + ], + "body": [ + { + "datatype": "u128", + "name": [ + "x1" + ], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u128", + "name": [], + "operation": "+", + "arguments": [ + { + "datatype": "u128", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u128", + "name": [], + "operation": "+", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1" + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg2" + ] + } + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg3" + ] + } + ] + } + ] + }, + { + "datatype": "u64", + "name": [ + "x2" + ], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "&", + "arguments": [ + { + "datatype": "u128", + "name": [], + "operation": "static_cast", + "arguments": [ + "x1" + ] + }, + "0xffffffffffffffff" + ] + } + ] + }, + { + "datatype": "u1", + "name": [ + "x3" + ], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": ">>", + "arguments": [ + { + "datatype": "u128", + "name": [], + "operation": "static_cast", + "arguments": [ + "x1" + ] + }, + "64" + ] + } + ] + }, + { + "datatype": "u64", + "name": [ + "out1" + ], + "operation": "static_cast", + "arguments": [ + "x2" + ] + }, + { + "datatype": "u1", + "name": [ + "out2" + ], + "operation": "static_cast", + "arguments": [ + "x3" + ] + } + ] + }, + { + "operation": "fiat_curve25519_solinas_subborrowx_u64", + "arguments": [ + { + "datatype": "u1", + "name": "arg1", + "lbound": "0x0", + "ubound": "0x1" + }, + { + "datatype": "u64", + "name": "arg2", + "lbound": "0x0", + "ubound": "0xffffffffffffffff" + }, + { + "datatype": "u64", + "name": "arg3", + "lbound": "0x0", + "ubound": "0xffffffffffffffff" + } + ], + "returns": [ + { + "datatype": "u64", + "name": "out1", + "lbound": "0x0", + "ubound": "0xffffffffffffffff" + }, + { + "datatype": "u1", + "name": "out2", + "lbound": "0x0", + "ubound": "0x1" + } + ], + "body": [ + { + "datatype": "i128", + "name": [ + "x1" + ], + "operation": "static_cast", + "arguments": [ + { + "datatype": "i128", + "name": [], + "operation": "-", + "arguments": [ + { + "datatype": "i128", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "i128", + "name": [], + "operation": "-", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg2" + ] + }, + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1" + ] + } + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg3" + ] + } + ] + } + ] + }, + { + "datatype": "i1", + "name": [ + "x2" + ], + "operation": "static_cast", + "arguments": [ + { + "datatype": "i1", + "name": [], + "operation": ">>", + "arguments": [ + { + "datatype": "i128", + "name": [], + "operation": "static_cast", + "arguments": [ + "x1" + ] + }, + "64" + ] + } + ] + }, + { + "datatype": "u64", + "name": [ + "x3" + ], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "&", + "arguments": [ + { + "datatype": "i128", + "name": [], + "operation": "static_cast", + "arguments": [ + "x1" + ] + }, + "0xffffffffffffffff" + ] + } + ] + }, + { + "datatype": "u64", + "name": [ + "out1" + ], + "operation": "static_cast", + "arguments": [ + "x3" + ] + }, + { + "datatype": "u1", + "name": [ + "out2" + ], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "-", + "arguments": [ + "0x0", + { + "datatype": "i1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x2" + ] + } + ] + } + ] + } + ] + }, + { + "operation": "fiat_curve25519_solinas_mulx_u64", + "arguments": [ + { + "datatype": "u64", + "name": "arg1", + "lbound": "0x0", + "ubound": "0xffffffffffffffff" + }, + { + "datatype": "u64", + "name": "arg2", + "lbound": "0x0", + "ubound": "0xffffffffffffffff" + } + ], + "returns": [ + { + "datatype": "u64", + "name": "out1", + "lbound": "0x0", + "ubound": "0xffffffffffffffff" + }, + { + "datatype": "u64", + "name": "out2", + "lbound": "0x0", + "ubound": "0xffffffffffffffff" + } + ], + "body": [ + { + "datatype": "u128", + "name": [ + "x1" + ], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u128", + "name": [], + "operation": "*", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1" + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg2" + ] + } + ] + } + ] + }, + { + "datatype": "u64", + "name": [ + "x2" + ], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "&", + "arguments": [ + { + "datatype": "u128", + "name": [], + "operation": "static_cast", + "arguments": [ + "x1" + ] + }, + "0xffffffffffffffff" + ] + } + ] + }, + { + "datatype": "u64", + "name": [ + "x3" + ], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": ">>", + "arguments": [ + { + "datatype": "u128", + "name": [], + "operation": "static_cast", + "arguments": [ + "x1" + ] + }, + "64" + ] + } + ] + }, + { + "datatype": "u64", + "name": [ + "out1" + ], + "operation": "static_cast", + "arguments": [ + "x2" + ] + }, + { + "datatype": "u64", + "name": [ + "out2" + ], + "operation": "static_cast", + "arguments": [ + "x3" + ] + } + ] + }, + { + "operation": "fiat_curve25519_solinas_cmovznz_u64", + "arguments": [ + { + "datatype": "u1", + "name": "arg1", + "lbound": "0x0", + "ubound": "0x1" + }, + { + "datatype": "u64", + "name": "arg2", + "lbound": "0x0", + "ubound": "0xffffffffffffffff" + }, + { + "datatype": "u64", + "name": "arg3", + "lbound": "0x0", + "ubound": "0xffffffffffffffff" + } + ], + "returns": [ + { + "datatype": "u64", + "name": "out1", + "lbound": "0x0", + "ubound": "0xffffffffffffffff" + } + ], + "body": [ + { + "datatype": "u1", + "name": [ + "x1" + ], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "!", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "!", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1" + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "datatype": "u64", + "name": [ + "x2" + ], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "&", + "arguments": [ + { + "datatype": "i1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "i1", + "name": [], + "operation": "-", + "arguments": [ + "0x0", + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x1" + ] + } + ] + } + ] + }, + "0xffffffffffffffff" + ] + } + ] + }, + { + "datatype": "u64", + "name": [ + "x3" + ], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "|", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "&", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x2" + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg3" + ] + } + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "&", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "~", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x2" + ] + } + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg2" + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "datatype": "u64", + "name": [ + "out1" + ], + "operation": "static_cast", + "arguments": [ + "x3" + ] + } + ] + }, + { + "operation": "fiat_curve25519_solinas_mul", + "arguments": [ + { + "datatype": "u64[4]", + "name": "arg1", + "lbound": [ + "0x0", + "0x0", + "0x0", + "0x0" + ], + "ubound": [ + "0xffffffffffffffff", + "0xffffffffffffffff", + "0xffffffffffffffff", + "0xffffffffffffffff" + ] + }, + { + "datatype": "u64[4]", + "name": "arg2", + "lbound": [ + "0x0", + "0x0", + "0x0", + "0x0" + ], + "ubound": [ + "0xffffffffffffffff", + "0xffffffffffffffff", + "0xffffffffffffffff", + "0xffffffffffffffff" + ] + } + ], + "returns": [ + { + "datatype": "u64[4]", + "name": "out1", + "lbound": [ + "0x0", + "0x0", + "0x0", + "0x0" + ], + "ubound": [ + "0xffffffffffffffff", + "0xffffffffffffffff", + "0xffffffffffffffff", + "0xffffffffffffffff" + ] + } + ], + "body": [ + { + "datatype": "(auto)", + "name": [ + "x1", + "x2" + ], + "operation": "mulx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1[3]" + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg2[3]" + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x3", + "x4" + ], + "operation": "mulx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1[3]" + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg2[2]" + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x5", + "x6" + ], + "operation": "mulx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1[3]" + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg2[1]" + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x7", + "x8" + ], + "operation": "mulx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1[3]" + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg2[0]" + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x9", + "x10" + ], + "operation": "mulx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1[2]" + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg2[3]" + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x11", + "x12" + ], + "operation": "mulx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1[2]" + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg2[2]" + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x13", + "x14" + ], + "operation": "mulx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1[2]" + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg2[1]" + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x15", + "x16" + ], + "operation": "mulx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1[2]" + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg2[0]" + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x17", + "x18" + ], + "operation": "mulx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1[1]" + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg2[3]" + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x19", + "x20" + ], + "operation": "mulx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1[1]" + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg2[2]" + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x21", + "x22" + ], + "operation": "mulx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1[1]" + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg2[1]" + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x23", + "x24" + ], + "operation": "mulx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1[1]" + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg2[0]" + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x25", + "x26" + ], + "operation": "mulx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1[0]" + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg2[3]" + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x27", + "x28" + ], + "operation": "mulx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1[0]" + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg2[2]" + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x29", + "x30" + ], + "operation": "mulx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1[0]" + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg2[1]" + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x31", + "x32" + ], + "operation": "mulx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1[0]" + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg2[0]" + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x33", + "x34" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + "0x0", + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x28" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x7" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x35", + "x36" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x34" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x26" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x5" + ] + } + ] + } + ] + }, + { + "datatype": "u64", + "name": [ + "x37" + ], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "+", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x36" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x18" + ] + } + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x38", + "x39" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + "0x0", + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x33" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x13" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x40", + "x41" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x39" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x35" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x8" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x42", + "x43" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x41" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x37" + ] + }, + "0x0" + ] + }, + { + "datatype": "u64", + "name": [ + "x44" + ], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "+", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x43" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x10" + ] + } + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x45", + "x46" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + "0x0", + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x30" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x15" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x47", + "x48" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x46" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x38" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x16" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x49", + "x50" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x48" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x40" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x11" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x51", + "x52" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x50" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x42" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x3" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x53", + "x54" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x52" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x44" + ] + }, + "0x0" + ] + }, + { + "datatype": "u64", + "name": [ + "x55" + ], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "+", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x54" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x2" + ] + } + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x56", + "x57" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + "0x0", + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x45" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x21" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x58", + "x59" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x57" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x47" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x19" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x60", + "x61" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x59" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x49" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x14" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x62", + "x63" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x61" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x51" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x6" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x64", + "x65" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x63" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x53" + ] + } + ] + }, + "0x0" + ] + }, + { + "datatype": "(auto)", + "name": [ + "x66", + "_" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x65" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x55" + ] + }, + "0x0" + ] + }, + { + "datatype": "(auto)", + "name": [ + "x68", + "x69" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + "0x0", + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x32" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x23" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x70", + "x71" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x69" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x56" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x24" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x72", + "x73" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x71" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x58" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x22" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x74", + "x75" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x73" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x60" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x17" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x76", + "x77" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x75" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x62" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x9" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x78", + "x79" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x77" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x64" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x1" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x80", + "_" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x79" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x66" + ] + } + ] + }, + "0x0" + ] + }, + { + "datatype": "(auto)", + "name": [ + "x82", + "x83" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + "0x0", + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x68" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x29" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x84", + "x85" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x83" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x70" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x27" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x86", + "x87" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x85" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x72" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x25" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x88", + "x89" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x87" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x74" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x20" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x90", + "x91" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x89" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x76" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x12" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x92", + "x93" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x91" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x78" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x4" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x94", + "_" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x93" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x80" + ] + } + ] + }, + "0x0" + ] + }, + { + "datatype": "(auto)", + "name": [ + "x96", + "x97" + ], + "operation": "mulx", + "parameters": { + "size": 64 + }, + "arguments": [ + "0x26", + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x94" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x98", + "x99" + ], + "operation": "mulx", + "parameters": { + "size": 64 + }, + "arguments": [ + "0x26", + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x92" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x100", + "x101" + ], + "operation": "mulx", + "parameters": { + "size": 64 + }, + "arguments": [ + "0x26", + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x90" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x102", + "x103" + ], + "operation": "mulx", + "parameters": { + "size": 64 + }, + "arguments": [ + "0x26", + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x88" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x104", + "x105" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + "0x0", + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x82" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x100" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x106", + "x107" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x105" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x84" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x98" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x108", + "x109" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x107" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x86" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x96" + ] + } + ] + } + ] + }, + { + "datatype": "u64", + "name": [ + "x110" + ], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "+", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x109" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x97" + ] + } + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x111", + "x112" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + "0x0", + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x31" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x102" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x113", + "x114" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x112" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x104" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x103" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x115", + "x116" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x114" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x106" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x101" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x117", + "x118" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x116" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x108" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x99" + ] + } + ] + } + ] + }, + { + "datatype": "u64", + "name": [ + "x119" + ], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "+", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x118" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x110" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x120", + "_" + ], + "operation": "mulx", + "parameters": { + "size": 64 + }, + "arguments": [ + "0x26", + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x119" + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x122", + "x123" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + "0x0", + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x111" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x120" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x124", + "x125" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x123" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x113" + ] + } + ] + }, + "0x0" + ] + }, + { + "datatype": "(auto)", + "name": [ + "x126", + "x127" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x125" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x115" + ] + } + ] + }, + "0x0" + ] + }, + { + "datatype": "(auto)", + "name": [ + "x128", + "x129" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x127" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x117" + ] + } + ] + }, + "0x0" + ] + }, + { + "datatype": "u64", + "name": [ + "x130" + ], + "operation": "cmovznz", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x129" + ] + } + ] + }, + "0x0", + "0x26" + ] + }, + { + "datatype": "(auto)", + "name": [ + "x131", + "_" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + "0x0", + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x130" + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x122" + ] + } + ] + } + ] + }, + { + "datatype": "u64", + "name": [ + "out1[0]" + ], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x131" + ] + } + ] + }, + { + "datatype": "u64", + "name": [ + "out1[1]" + ], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x124" + ] + } + ] + }, + { + "datatype": "u64", + "name": [ + "out1[2]" + ], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x126" + ] + } + ] + }, + { + "datatype": "u64", + "name": [ + "out1[3]" + ], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x128" + ] + } + ] + } + ] + }, + { + "operation": "fiat_curve25519_solinas_square", + "arguments": [ + { + "datatype": "u64[4]", + "name": "arg1", + "lbound": [ + "0x0", + "0x0", + "0x0", + "0x0" + ], + "ubound": [ + "0xffffffffffffffff", + "0xffffffffffffffff", + "0xffffffffffffffff", + "0xffffffffffffffff" + ] + } + ], + "returns": [ + { + "datatype": "u64[4]", + "name": "out1", + "lbound": [ + "0x0", + "0x0", + "0x0", + "0x0" + ], + "ubound": [ + "0xffffffffffffffff", + "0xffffffffffffffff", + "0xffffffffffffffff", + "0xffffffffffffffff" + ] + } + ], + "body": [ + { + "datatype": "(auto)", + "name": [ + "x1", + "x2" + ], + "operation": "mulx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1[0]" + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1[3]" + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x3", + "x4" + ], + "operation": "mulx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1[0]" + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1[2]" + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x5", + "x6" + ], + "operation": "mulx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1[0]" + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1[1]" + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x7", + "x8" + ], + "operation": "mulx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1[3]" + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1[2]" + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x9", + "x10" + ], + "operation": "mulx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1[3]" + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1[1]" + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x11", + "x12" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + "0x0", + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x6" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x3" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x13", + "x14" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x12" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x4" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x1" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x15", + "x16" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x14" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x2" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x9" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x17", + "x18" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x16" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x10" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x7" + ] + } + ] + } + ] + }, + { + "datatype": "u64", + "name": [ + "x19" + ], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "+", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x18" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x8" + ] + } + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x20", + "x21" + ], + "operation": "mulx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1[1]" + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1[2]" + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x22", + "x23" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + "0x0", + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x13" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x20" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x24", + "x25" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x23" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x15" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x21" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x26", + "x27" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x25" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x17" + ] + } + ] + }, + "0x0" + ] + }, + { + "datatype": "(auto)", + "name": [ + "x28", + "x29" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x27" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x19" + ] + }, + "0x0" + ] + }, + { + "datatype": "(auto)", + "name": [ + "x30", + "x31" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + "0x0", + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x5" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x5" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x32", + "x33" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x31" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x11" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x11" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x34", + "x35" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x33" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x22" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x22" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x36", + "x37" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x35" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x24" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x24" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x38", + "x39" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x37" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x26" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x26" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x40", + "x41" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x39" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x28" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x28" + ] + } + ] + } + ] + }, + { + "datatype": "u64", + "name": [ + "x42" + ], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "+", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "+", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x41" + ] + } + ] + }, + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x29" + ] + } + ] + } + ] + } + ] + }, + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x29" + ] + } + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x43", + "x44" + ], + "operation": "mulx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1[3]" + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1[3]" + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x45", + "x46" + ], + "operation": "mulx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1[2]" + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1[2]" + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x47", + "x48" + ], + "operation": "mulx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1[1]" + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1[1]" + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x49", + "x50" + ], + "operation": "mulx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1[0]" + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "arg1[0]" + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x51", + "x52" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + "0x0", + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x30" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x50" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x53", + "x54" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x52" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x32" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x47" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x55", + "x56" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x54" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x34" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x48" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x57", + "x58" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x56" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x36" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x45" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x59", + "x60" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x58" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x38" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x46" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x61", + "x62" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x60" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x40" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x43" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x63", + "_" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x62" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x42" + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x44" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x65", + "x66" + ], + "operation": "mulx", + "parameters": { + "size": 64 + }, + "arguments": [ + "0x26", + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x63" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x67", + "x68" + ], + "operation": "mulx", + "parameters": { + "size": 64 + }, + "arguments": [ + "0x26", + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x61" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x69", + "x70" + ], + "operation": "mulx", + "parameters": { + "size": 64 + }, + "arguments": [ + "0x26", + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x59" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x71", + "x72" + ], + "operation": "mulx", + "parameters": { + "size": 64 + }, + "arguments": [ + "0x26", + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x57" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x73", + "x74" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + "0x0", + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x51" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x69" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x75", + "x76" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x74" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x53" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x67" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x77", + "x78" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x76" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x55" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x65" + ] + } + ] + } + ] + }, + { + "datatype": "u64", + "name": [ + "x79" + ], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "+", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x78" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x66" + ] + } + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x80", + "x81" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + "0x0", + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x49" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x71" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x82", + "x83" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x81" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x73" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x72" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x84", + "x85" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x83" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x75" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x70" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x86", + "x87" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x85" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x77" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x68" + ] + } + ] + } + ] + }, + { + "datatype": "u64", + "name": [ + "x88" + ], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "+", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x87" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x79" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x89", + "_" + ], + "operation": "mulx", + "parameters": { + "size": 64 + }, + "arguments": [ + "0x26", + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x88" + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x91", + "x92" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + "0x0", + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x80" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x89" + ] + } + ] + } + ] + }, + { + "datatype": "(auto)", + "name": [ + "x93", + "x94" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x92" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x82" + ] + } + ] + }, + "0x0" + ] + }, + { + "datatype": "(auto)", + "name": [ + "x95", + "x96" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x94" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x84" + ] + } + ] + }, + "0x0" + ] + }, + { + "datatype": "(auto)", + "name": [ + "x97", + "x98" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x96" + ] + } + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x86" + ] + } + ] + }, + "0x0" + ] + }, + { + "datatype": "u64", + "name": [ + "x99" + ], + "operation": "cmovznz", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u1", + "name": [], + "operation": "static_cast", + "arguments": [ + "x98" + ] + } + ] + }, + "0x0", + "0x26" + ] + }, + { + "datatype": "(auto)", + "name": [ + "x100", + "_" + ], + "operation": "addcarryx", + "parameters": { + "size": 64 + }, + "arguments": [ + "0x0", + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x99" + ] + }, + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x91" + ] + } + ] + } + ] + }, + { + "datatype": "u64", + "name": [ + "out1[0]" + ], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x100" + ] + } + ] + }, + { + "datatype": "u64", + "name": [ + "out1[1]" + ], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x93" + ] + } + ] + }, + { + "datatype": "u64", + "name": [ + "out1[2]" + ], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x95" + ] + } + ] + }, + { + "datatype": "u64", + "name": [ + "out1[3]" + ], + "operation": "static_cast", + "arguments": [ + { + "datatype": "u64", + "name": [], + "operation": "static_cast", + "arguments": [ + "x97" + ] + } + ] + } + ] + } +] diff --git a/fiat-rust/src/curve25519_solinas_64.rs b/fiat-rust/src/curve25519_solinas_64.rs new file mode 100644 index 0000000000..edda9bb439 --- /dev/null +++ b/fiat-rust/src/curve25519_solinas_64.rs @@ -0,0 +1,482 @@ +//! Autogenerated: 'src/ExtractionOCaml/solinas_reduction' --lang Rust --inline curve25519_solinas 64 '2^255 - 19' mul square +//! curve description: curve25519_solinas +//! machine_wordsize = 64 (from "64") +//! requested operations: mul, square +//! s-c = 2^255 - [(1, 19)] (from "2^255 - 19") +//! +//! Computed values: +//! + +#![allow(unused_parens)] +#![allow(non_camel_case_types)] + +pub type fiat_curve25519_solinas_u1 = u8; +pub type fiat_curve25519_solinas_i1 = i8; +pub type fiat_curve25519_solinas_u2 = u8; +pub type fiat_curve25519_solinas_i2 = i8; + + +/// The function fiat_curve25519_solinas_addcarryx_u64 is an addition with carry. +/// +/// Postconditions: +/// out1 = (arg1 + arg2 + arg3) mod 2^64 +/// out2 = ⌊(arg1 + arg2 + arg3) / 2^64⌋ +/// +/// Input Bounds: +/// arg1: [0x0 ~> 0x1] +/// arg2: [0x0 ~> 0xffffffffffffffff] +/// arg3: [0x0 ~> 0xffffffffffffffff] +/// Output Bounds: +/// out1: [0x0 ~> 0xffffffffffffffff] +/// out2: [0x0 ~> 0x1] +#[inline] +pub fn fiat_curve25519_solinas_addcarryx_u64(out1: &mut u64, out2: &mut fiat_curve25519_solinas_u1, arg1: fiat_curve25519_solinas_u1, arg2: u64, arg3: u64) -> () { + let x1: u128 = (((arg1 as u128) + (arg2 as u128)) + (arg3 as u128)); + let x2: u64 = ((x1 & (0xffffffffffffffff as u128)) as u64); + let x3: fiat_curve25519_solinas_u1 = ((x1 >> 64) as fiat_curve25519_solinas_u1); + *out1 = x2; + *out2 = x3; +} + +/// The function fiat_curve25519_solinas_subborrowx_u64 is a subtraction with borrow. +/// +/// Postconditions: +/// out1 = (-arg1 + arg2 + -arg3) mod 2^64 +/// out2 = -⌊(-arg1 + arg2 + -arg3) / 2^64⌋ +/// +/// Input Bounds: +/// arg1: [0x0 ~> 0x1] +/// arg2: [0x0 ~> 0xffffffffffffffff] +/// arg3: [0x0 ~> 0xffffffffffffffff] +/// Output Bounds: +/// out1: [0x0 ~> 0xffffffffffffffff] +/// out2: [0x0 ~> 0x1] +#[inline] +pub fn fiat_curve25519_solinas_subborrowx_u64(out1: &mut u64, out2: &mut fiat_curve25519_solinas_u1, arg1: fiat_curve25519_solinas_u1, arg2: u64, arg3: u64) -> () { + let x1: i128 = (((arg2 as i128) - (arg1 as i128)) - (arg3 as i128)); + let x2: fiat_curve25519_solinas_i1 = ((x1 >> 64) as fiat_curve25519_solinas_i1); + let x3: u64 = ((x1 & (0xffffffffffffffff as i128)) as u64); + *out1 = x3; + *out2 = (((0x0 as fiat_curve25519_solinas_i2) - (x2 as fiat_curve25519_solinas_i2)) as fiat_curve25519_solinas_u1); +} + +/// The function fiat_curve25519_solinas_mulx_u64 is a multiplication, returning the full double-width result. +/// +/// Postconditions: +/// out1 = (arg1 * arg2) mod 2^64 +/// out2 = ⌊arg1 * arg2 / 2^64⌋ +/// +/// Input Bounds: +/// arg1: [0x0 ~> 0xffffffffffffffff] +/// arg2: [0x0 ~> 0xffffffffffffffff] +/// Output Bounds: +/// out1: [0x0 ~> 0xffffffffffffffff] +/// out2: [0x0 ~> 0xffffffffffffffff] +#[inline] +pub fn fiat_curve25519_solinas_mulx_u64(out1: &mut u64, out2: &mut u64, arg1: u64, arg2: u64) -> () { + let x1: u128 = ((arg1 as u128) * (arg2 as u128)); + let x2: u64 = ((x1 & (0xffffffffffffffff as u128)) as u64); + let x3: u64 = ((x1 >> 64) as u64); + *out1 = x2; + *out2 = x3; +} + +/// The function fiat_curve25519_solinas_cmovznz_u64 is a single-word conditional move. +/// +/// Postconditions: +/// out1 = (if arg1 = 0 then arg2 else arg3) +/// +/// Input Bounds: +/// arg1: [0x0 ~> 0x1] +/// arg2: [0x0 ~> 0xffffffffffffffff] +/// arg3: [0x0 ~> 0xffffffffffffffff] +/// Output Bounds: +/// out1: [0x0 ~> 0xffffffffffffffff] +#[inline] +pub fn fiat_curve25519_solinas_cmovznz_u64(out1: &mut u64, arg1: fiat_curve25519_solinas_u1, arg2: u64, arg3: u64) -> () { + let x1: fiat_curve25519_solinas_u1 = (!(!arg1)); + let x2: u64 = ((((((0x0 as fiat_curve25519_solinas_i2) - (x1 as fiat_curve25519_solinas_i2)) as fiat_curve25519_solinas_i1) as i128) & (0xffffffffffffffff as i128)) as u64); + let x3: u64 = ((x2 & arg3) | ((!x2) & arg2)); + *out1 = x3; +} + +/// The function fiat_curve25519_solinas_mul multiplies two field elements. +/// +/// Postconditions: +/// eval out1 mod 57896044618658097711785492504343953926634992332820282019728792003956564819949 = (eval arg1 * eval arg2) mod 57896044618658097711785492504343953926634992332820282019728792003956564819949 +/// +/// Input Bounds: +/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +/// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +/// Output Bounds: +/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +#[inline] +pub fn fiat_curve25519_solinas_mul(out1: &mut [u64; 4], arg1: &[u64; 4], arg2: &[u64; 4]) -> () { + let mut x1: u64 = 0; + let mut x2: u64 = 0; + fiat_curve25519_solinas_mulx_u64(&mut x1, &mut x2, (arg1[3]), (arg2[3])); + let mut x3: u64 = 0; + let mut x4: u64 = 0; + fiat_curve25519_solinas_mulx_u64(&mut x3, &mut x4, (arg1[3]), (arg2[2])); + let mut x5: u64 = 0; + let mut x6: u64 = 0; + fiat_curve25519_solinas_mulx_u64(&mut x5, &mut x6, (arg1[3]), (arg2[1])); + let mut x7: u64 = 0; + let mut x8: u64 = 0; + fiat_curve25519_solinas_mulx_u64(&mut x7, &mut x8, (arg1[3]), (arg2[0])); + let mut x9: u64 = 0; + let mut x10: u64 = 0; + fiat_curve25519_solinas_mulx_u64(&mut x9, &mut x10, (arg1[2]), (arg2[3])); + let mut x11: u64 = 0; + let mut x12: u64 = 0; + fiat_curve25519_solinas_mulx_u64(&mut x11, &mut x12, (arg1[2]), (arg2[2])); + let mut x13: u64 = 0; + let mut x14: u64 = 0; + fiat_curve25519_solinas_mulx_u64(&mut x13, &mut x14, (arg1[2]), (arg2[1])); + let mut x15: u64 = 0; + let mut x16: u64 = 0; + fiat_curve25519_solinas_mulx_u64(&mut x15, &mut x16, (arg1[2]), (arg2[0])); + let mut x17: u64 = 0; + let mut x18: u64 = 0; + fiat_curve25519_solinas_mulx_u64(&mut x17, &mut x18, (arg1[1]), (arg2[3])); + let mut x19: u64 = 0; + let mut x20: u64 = 0; + fiat_curve25519_solinas_mulx_u64(&mut x19, &mut x20, (arg1[1]), (arg2[2])); + let mut x21: u64 = 0; + let mut x22: u64 = 0; + fiat_curve25519_solinas_mulx_u64(&mut x21, &mut x22, (arg1[1]), (arg2[1])); + let mut x23: u64 = 0; + let mut x24: u64 = 0; + fiat_curve25519_solinas_mulx_u64(&mut x23, &mut x24, (arg1[1]), (arg2[0])); + let mut x25: u64 = 0; + let mut x26: u64 = 0; + fiat_curve25519_solinas_mulx_u64(&mut x25, &mut x26, (arg1[0]), (arg2[3])); + let mut x27: u64 = 0; + let mut x28: u64 = 0; + fiat_curve25519_solinas_mulx_u64(&mut x27, &mut x28, (arg1[0]), (arg2[2])); + let mut x29: u64 = 0; + let mut x30: u64 = 0; + fiat_curve25519_solinas_mulx_u64(&mut x29, &mut x30, (arg1[0]), (arg2[1])); + let mut x31: u64 = 0; + let mut x32: u64 = 0; + fiat_curve25519_solinas_mulx_u64(&mut x31, &mut x32, (arg1[0]), (arg2[0])); + let mut x33: u64 = 0; + let mut x34: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x33, &mut x34, 0x0, x28, x7); + let mut x35: u64 = 0; + let mut x36: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x35, &mut x36, x34, x26, x5); + let x37: u64 = ((x36 as u64) + x18); + let mut x38: u64 = 0; + let mut x39: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x38, &mut x39, 0x0, x33, x13); + let mut x40: u64 = 0; + let mut x41: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x40, &mut x41, x39, x35, x8); + let mut x42: u64 = 0; + let mut x43: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x42, &mut x43, x41, x37, (0x0 as u64)); + let x44: u64 = ((x43 as u64) + x10); + let mut x45: u64 = 0; + let mut x46: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x45, &mut x46, 0x0, x30, x15); + let mut x47: u64 = 0; + let mut x48: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x47, &mut x48, x46, x38, x16); + let mut x49: u64 = 0; + let mut x50: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x49, &mut x50, x48, x40, x11); + let mut x51: u64 = 0; + let mut x52: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x51, &mut x52, x50, x42, x3); + let mut x53: u64 = 0; + let mut x54: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x53, &mut x54, x52, x44, (0x0 as u64)); + let x55: u64 = ((x54 as u64) + x2); + let mut x56: u64 = 0; + let mut x57: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x56, &mut x57, 0x0, x45, x21); + let mut x58: u64 = 0; + let mut x59: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x58, &mut x59, x57, x47, x19); + let mut x60: u64 = 0; + let mut x61: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x60, &mut x61, x59, x49, x14); + let mut x62: u64 = 0; + let mut x63: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x62, &mut x63, x61, x51, x6); + let mut x64: u64 = 0; + let mut x65: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x64, &mut x65, x63, x53, (0x0 as u64)); + let mut x66: u64 = 0; + let mut x67: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x66, &mut x67, x65, x55, (0x0 as u64)); + let mut x68: u64 = 0; + let mut x69: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x68, &mut x69, 0x0, x32, x23); + let mut x70: u64 = 0; + let mut x71: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x70, &mut x71, x69, x56, x24); + let mut x72: u64 = 0; + let mut x73: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x72, &mut x73, x71, x58, x22); + let mut x74: u64 = 0; + let mut x75: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x74, &mut x75, x73, x60, x17); + let mut x76: u64 = 0; + let mut x77: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x76, &mut x77, x75, x62, x9); + let mut x78: u64 = 0; + let mut x79: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x78, &mut x79, x77, x64, x1); + let mut x80: u64 = 0; + let mut x81: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x80, &mut x81, x79, x66, (0x0 as u64)); + let mut x82: u64 = 0; + let mut x83: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x82, &mut x83, 0x0, x68, x29); + let mut x84: u64 = 0; + let mut x85: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x84, &mut x85, x83, x70, x27); + let mut x86: u64 = 0; + let mut x87: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x86, &mut x87, x85, x72, x25); + let mut x88: u64 = 0; + let mut x89: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x88, &mut x89, x87, x74, x20); + let mut x90: u64 = 0; + let mut x91: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x90, &mut x91, x89, x76, x12); + let mut x92: u64 = 0; + let mut x93: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x92, &mut x93, x91, x78, x4); + let mut x94: u64 = 0; + let mut x95: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x94, &mut x95, x93, x80, (0x0 as u64)); + let mut x96: u64 = 0; + let mut x97: u64 = 0; + fiat_curve25519_solinas_mulx_u64(&mut x96, &mut x97, 0x26, x94); + let mut x98: u64 = 0; + let mut x99: u64 = 0; + fiat_curve25519_solinas_mulx_u64(&mut x98, &mut x99, 0x26, x92); + let mut x100: u64 = 0; + let mut x101: u64 = 0; + fiat_curve25519_solinas_mulx_u64(&mut x100, &mut x101, 0x26, x90); + let mut x102: u64 = 0; + let mut x103: u64 = 0; + fiat_curve25519_solinas_mulx_u64(&mut x102, &mut x103, 0x26, x88); + let mut x104: u64 = 0; + let mut x105: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x104, &mut x105, 0x0, x82, x100); + let mut x106: u64 = 0; + let mut x107: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x106, &mut x107, x105, x84, x98); + let mut x108: u64 = 0; + let mut x109: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x108, &mut x109, x107, x86, x96); + let x110: u64 = ((x109 as u64) + x97); + let mut x111: u64 = 0; + let mut x112: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x111, &mut x112, 0x0, x31, x102); + let mut x113: u64 = 0; + let mut x114: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x113, &mut x114, x112, x104, x103); + let mut x115: u64 = 0; + let mut x116: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x115, &mut x116, x114, x106, x101); + let mut x117: u64 = 0; + let mut x118: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x117, &mut x118, x116, x108, x99); + let x119: u64 = ((x118 as u64) + x110); + let mut x120: u64 = 0; + let mut x121: u64 = 0; + fiat_curve25519_solinas_mulx_u64(&mut x120, &mut x121, 0x26, x119); + let mut x122: u64 = 0; + let mut x123: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x122, &mut x123, 0x0, x111, x120); + let mut x124: u64 = 0; + let mut x125: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x124, &mut x125, x123, x113, (0x0 as u64)); + let mut x126: u64 = 0; + let mut x127: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x126, &mut x127, x125, x115, (0x0 as u64)); + let mut x128: u64 = 0; + let mut x129: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x128, &mut x129, x127, x117, (0x0 as u64)); + let mut x130: u64 = 0; + fiat_curve25519_solinas_cmovznz_u64(&mut x130, x129, (0x0 as u64), 0x26); + let mut x131: u64 = 0; + let mut x132: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x131, &mut x132, 0x0, x130, x122); + out1[0] = x131; + out1[1] = x124; + out1[2] = x126; + out1[3] = x128; +} + +/// The function fiat_curve25519_solinas_square squares a field element. +/// +/// Postconditions: +/// eval out1 mod 57896044618658097711785492504343953926634992332820282019728792003956564819949 = (eval arg1 * eval arg1) mod 57896044618658097711785492504343953926634992332820282019728792003956564819949 +/// +/// Input Bounds: +/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +/// Output Bounds: +/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +#[inline] +pub fn fiat_curve25519_solinas_square(out1: &mut [u64; 4], arg1: &[u64; 4]) -> () { + let mut x1: u64 = 0; + let mut x2: u64 = 0; + fiat_curve25519_solinas_mulx_u64(&mut x1, &mut x2, (arg1[0]), (arg1[3])); + let mut x3: u64 = 0; + let mut x4: u64 = 0; + fiat_curve25519_solinas_mulx_u64(&mut x3, &mut x4, (arg1[0]), (arg1[2])); + let mut x5: u64 = 0; + let mut x6: u64 = 0; + fiat_curve25519_solinas_mulx_u64(&mut x5, &mut x6, (arg1[0]), (arg1[1])); + let mut x7: u64 = 0; + let mut x8: u64 = 0; + fiat_curve25519_solinas_mulx_u64(&mut x7, &mut x8, (arg1[3]), (arg1[2])); + let mut x9: u64 = 0; + let mut x10: u64 = 0; + fiat_curve25519_solinas_mulx_u64(&mut x9, &mut x10, (arg1[3]), (arg1[1])); + let mut x11: u64 = 0; + let mut x12: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x11, &mut x12, 0x0, x6, x3); + let mut x13: u64 = 0; + let mut x14: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x13, &mut x14, x12, x4, x1); + let mut x15: u64 = 0; + let mut x16: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x15, &mut x16, x14, x2, x9); + let mut x17: u64 = 0; + let mut x18: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x17, &mut x18, x16, x10, x7); + let x19: u64 = ((x18 as u64) + x8); + let mut x20: u64 = 0; + let mut x21: u64 = 0; + fiat_curve25519_solinas_mulx_u64(&mut x20, &mut x21, (arg1[1]), (arg1[2])); + let mut x22: u64 = 0; + let mut x23: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x22, &mut x23, 0x0, x13, x20); + let mut x24: u64 = 0; + let mut x25: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x24, &mut x25, x23, x15, x21); + let mut x26: u64 = 0; + let mut x27: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x26, &mut x27, x25, x17, (0x0 as u64)); + let mut x28: u64 = 0; + let mut x29: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x28, &mut x29, x27, x19, (0x0 as u64)); + let mut x30: u64 = 0; + let mut x31: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x30, &mut x31, 0x0, x5, x5); + let mut x32: u64 = 0; + let mut x33: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x32, &mut x33, x31, x11, x11); + let mut x34: u64 = 0; + let mut x35: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x34, &mut x35, x33, x22, x22); + let mut x36: u64 = 0; + let mut x37: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x36, &mut x37, x35, x24, x24); + let mut x38: u64 = 0; + let mut x39: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x38, &mut x39, x37, x26, x26); + let mut x40: u64 = 0; + let mut x41: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x40, &mut x41, x39, x28, x28); + let x42: u64 = (((x41 as u64) + (x29 as u64)) + (x29 as u64)); + let mut x43: u64 = 0; + let mut x44: u64 = 0; + fiat_curve25519_solinas_mulx_u64(&mut x43, &mut x44, (arg1[3]), (arg1[3])); + let mut x45: u64 = 0; + let mut x46: u64 = 0; + fiat_curve25519_solinas_mulx_u64(&mut x45, &mut x46, (arg1[2]), (arg1[2])); + let mut x47: u64 = 0; + let mut x48: u64 = 0; + fiat_curve25519_solinas_mulx_u64(&mut x47, &mut x48, (arg1[1]), (arg1[1])); + let mut x49: u64 = 0; + let mut x50: u64 = 0; + fiat_curve25519_solinas_mulx_u64(&mut x49, &mut x50, (arg1[0]), (arg1[0])); + let mut x51: u64 = 0; + let mut x52: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x51, &mut x52, 0x0, x30, x50); + let mut x53: u64 = 0; + let mut x54: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x53, &mut x54, x52, x32, x47); + let mut x55: u64 = 0; + let mut x56: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x55, &mut x56, x54, x34, x48); + let mut x57: u64 = 0; + let mut x58: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x57, &mut x58, x56, x36, x45); + let mut x59: u64 = 0; + let mut x60: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x59, &mut x60, x58, x38, x46); + let mut x61: u64 = 0; + let mut x62: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x61, &mut x62, x60, x40, x43); + let mut x63: u64 = 0; + let mut x64: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x63, &mut x64, x62, x42, x44); + let mut x65: u64 = 0; + let mut x66: u64 = 0; + fiat_curve25519_solinas_mulx_u64(&mut x65, &mut x66, 0x26, x63); + let mut x67: u64 = 0; + let mut x68: u64 = 0; + fiat_curve25519_solinas_mulx_u64(&mut x67, &mut x68, 0x26, x61); + let mut x69: u64 = 0; + let mut x70: u64 = 0; + fiat_curve25519_solinas_mulx_u64(&mut x69, &mut x70, 0x26, x59); + let mut x71: u64 = 0; + let mut x72: u64 = 0; + fiat_curve25519_solinas_mulx_u64(&mut x71, &mut x72, 0x26, x57); + let mut x73: u64 = 0; + let mut x74: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x73, &mut x74, 0x0, x51, x69); + let mut x75: u64 = 0; + let mut x76: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x75, &mut x76, x74, x53, x67); + let mut x77: u64 = 0; + let mut x78: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x77, &mut x78, x76, x55, x65); + let x79: u64 = ((x78 as u64) + x66); + let mut x80: u64 = 0; + let mut x81: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x80, &mut x81, 0x0, x49, x71); + let mut x82: u64 = 0; + let mut x83: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x82, &mut x83, x81, x73, x72); + let mut x84: u64 = 0; + let mut x85: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x84, &mut x85, x83, x75, x70); + let mut x86: u64 = 0; + let mut x87: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x86, &mut x87, x85, x77, x68); + let x88: u64 = ((x87 as u64) + x79); + let mut x89: u64 = 0; + let mut x90: u64 = 0; + fiat_curve25519_solinas_mulx_u64(&mut x89, &mut x90, 0x26, x88); + let mut x91: u64 = 0; + let mut x92: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x91, &mut x92, 0x0, x80, x89); + let mut x93: u64 = 0; + let mut x94: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x93, &mut x94, x92, x82, (0x0 as u64)); + let mut x95: u64 = 0; + let mut x96: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x95, &mut x96, x94, x84, (0x0 as u64)); + let mut x97: u64 = 0; + let mut x98: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x97, &mut x98, x96, x86, (0x0 as u64)); + let mut x99: u64 = 0; + fiat_curve25519_solinas_cmovznz_u64(&mut x99, x98, (0x0 as u64), 0x26); + let mut x100: u64 = 0; + let mut x101: fiat_curve25519_solinas_u1 = 0; + fiat_curve25519_solinas_addcarryx_u64(&mut x100, &mut x101, 0x0, x99, x91); + out1[0] = x100; + out1[1] = x93; + out1[2] = x95; + out1[3] = x97; +} diff --git a/fiat-rust/src/lib.rs b/fiat-rust/src/lib.rs index 3a0d1ca25e..3871b637f0 100644 --- a/fiat-rust/src/lib.rs +++ b/fiat-rust/src/lib.rs @@ -4,6 +4,7 @@ pub mod curve25519_32; pub mod curve25519_64; pub mod curve25519_scalar_32; pub mod curve25519_scalar_64; +pub mod curve25519_solinas_64; pub mod p224_32; pub mod p224_64; pub mod p256_32; diff --git a/fiat-zig/src/curve25519_solinas_64.zig b/fiat-zig/src/curve25519_solinas_64.zig new file mode 100644 index 0000000000..c011a0a857 --- /dev/null +++ b/fiat-zig/src/curve25519_solinas_64.zig @@ -0,0 +1,496 @@ +// Autogenerated: 'src/ExtractionOCaml/solinas_reduction' --lang Zig --internal-static --public-function-case camelCase --private-function-case camelCase --public-type-case UpperCamelCase --private-type-case UpperCamelCase --no-prefix-fiat --package-name curve25519_solinas '' 64 '2^255 - 19' mul square +// curve description (via package name): curve25519_solinas +// machine_wordsize = 64 (from "64") +// requested operations: mul, square +// s-c = 2^255 - [(1, 19)] (from "2^255 - 19") +// +// Computed values: +// + +const std = @import("std"); +const mode = @import("builtin").mode; // Checked arithmetic is disabled in non-debug modes to avoid side channels + +inline fn cast(comptime DestType: type, target: anytype) DestType { + @setEvalBranchQuota(10000); + if (@typeInfo(@TypeOf(target)) == .Int) { + const dest = @typeInfo(DestType).Int; + const source = @typeInfo(@TypeOf(target)).Int; + if (dest.bits < source.bits) { + return @bitCast(DestType, @truncate(std.meta.Int(source.signedness, dest.bits), target)); + } else { + return @bitCast(DestType, @as(std.meta.Int(source.signedness, dest.bits), target)); + } + } + return @as(DestType, target); +} + +/// The function addcarryxU64 is an addition with carry. +/// +/// Postconditions: +/// out1 = (arg1 + arg2 + arg3) mod 2^64 +/// out2 = ⌊(arg1 + arg2 + arg3) / 2^64⌋ +/// +/// Input Bounds: +/// arg1: [0x0 ~> 0x1] +/// arg2: [0x0 ~> 0xffffffffffffffff] +/// arg3: [0x0 ~> 0xffffffffffffffff] +/// Output Bounds: +/// out1: [0x0 ~> 0xffffffffffffffff] +/// out2: [0x0 ~> 0x1] +inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void { + @setRuntimeSafety(mode == .Debug); + + const x1 = ((cast(u128, arg1) + cast(u128, arg2)) + cast(u128, arg3)); + const x2 = cast(u64, (x1 & cast(u128, 0xffffffffffffffff))); + const x3 = cast(u1, (x1 >> 64)); + out1.* = x2; + out2.* = x3; +} + +/// The function subborrowxU64 is a subtraction with borrow. +/// +/// Postconditions: +/// out1 = (-arg1 + arg2 + -arg3) mod 2^64 +/// out2 = -⌊(-arg1 + arg2 + -arg3) / 2^64⌋ +/// +/// Input Bounds: +/// arg1: [0x0 ~> 0x1] +/// arg2: [0x0 ~> 0xffffffffffffffff] +/// arg3: [0x0 ~> 0xffffffffffffffff] +/// Output Bounds: +/// out1: [0x0 ~> 0xffffffffffffffff] +/// out2: [0x0 ~> 0x1] +inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) void { + @setRuntimeSafety(mode == .Debug); + + const x1 = ((cast(i128, arg2) - cast(i128, arg1)) - cast(i128, arg3)); + const x2 = cast(i1, (x1 >> 64)); + const x3 = cast(u64, (x1 & cast(i128, 0xffffffffffffffff))); + out1.* = x3; + out2.* = cast(u1, (cast(i2, 0x0) - cast(i2, x2))); +} + +/// The function mulxU64 is a multiplication, returning the full double-width result. +/// +/// Postconditions: +/// out1 = (arg1 * arg2) mod 2^64 +/// out2 = ⌊arg1 * arg2 / 2^64⌋ +/// +/// Input Bounds: +/// arg1: [0x0 ~> 0xffffffffffffffff] +/// arg2: [0x0 ~> 0xffffffffffffffff] +/// Output Bounds: +/// out1: [0x0 ~> 0xffffffffffffffff] +/// out2: [0x0 ~> 0xffffffffffffffff] +inline fn mulxU64(out1: *u64, out2: *u64, arg1: u64, arg2: u64) void { + @setRuntimeSafety(mode == .Debug); + + const x1 = (cast(u128, arg1) * cast(u128, arg2)); + const x2 = cast(u64, (x1 & cast(u128, 0xffffffffffffffff))); + const x3 = cast(u64, (x1 >> 64)); + out1.* = x2; + out2.* = x3; +} + +/// The function cmovznzU64 is a single-word conditional move. +/// +/// Postconditions: +/// out1 = (if arg1 = 0 then arg2 else arg3) +/// +/// Input Bounds: +/// arg1: [0x0 ~> 0x1] +/// arg2: [0x0 ~> 0xffffffffffffffff] +/// arg3: [0x0 ~> 0xffffffffffffffff] +/// Output Bounds: +/// out1: [0x0 ~> 0xffffffffffffffff] +inline fn cmovznzU64(out1: *u64, arg1: u1, arg2: u64, arg3: u64) void { + @setRuntimeSafety(mode == .Debug); + + const x1 = (~(~arg1)); + const x2 = cast(u64, (cast(i128, cast(i1, (cast(i2, 0x0) - cast(i2, x1)))) & cast(i128, 0xffffffffffffffff))); + const x3 = ((x2 & arg3) | ((~x2) & arg2)); + out1.* = x3; +} + +/// The function mul multiplies two field elements. +/// +/// Postconditions: +/// eval out1 mod 57896044618658097711785492504343953926634992332820282019728792003956564819949 = (eval arg1 * eval arg2) mod 57896044618658097711785492504343953926634992332820282019728792003956564819949 +/// +/// Input Bounds: +/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +/// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +/// Output Bounds: +/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +pub fn mul(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void { + @setRuntimeSafety(mode == .Debug); + + var x1: u64 = undefined; + var x2: u64 = undefined; + mulxU64(&x1, &x2, (arg1[3]), (arg2[3])); + var x3: u64 = undefined; + var x4: u64 = undefined; + mulxU64(&x3, &x4, (arg1[3]), (arg2[2])); + var x5: u64 = undefined; + var x6: u64 = undefined; + mulxU64(&x5, &x6, (arg1[3]), (arg2[1])); + var x7: u64 = undefined; + var x8: u64 = undefined; + mulxU64(&x7, &x8, (arg1[3]), (arg2[0])); + var x9: u64 = undefined; + var x10: u64 = undefined; + mulxU64(&x9, &x10, (arg1[2]), (arg2[3])); + var x11: u64 = undefined; + var x12: u64 = undefined; + mulxU64(&x11, &x12, (arg1[2]), (arg2[2])); + var x13: u64 = undefined; + var x14: u64 = undefined; + mulxU64(&x13, &x14, (arg1[2]), (arg2[1])); + var x15: u64 = undefined; + var x16: u64 = undefined; + mulxU64(&x15, &x16, (arg1[2]), (arg2[0])); + var x17: u64 = undefined; + var x18: u64 = undefined; + mulxU64(&x17, &x18, (arg1[1]), (arg2[3])); + var x19: u64 = undefined; + var x20: u64 = undefined; + mulxU64(&x19, &x20, (arg1[1]), (arg2[2])); + var x21: u64 = undefined; + var x22: u64 = undefined; + mulxU64(&x21, &x22, (arg1[1]), (arg2[1])); + var x23: u64 = undefined; + var x24: u64 = undefined; + mulxU64(&x23, &x24, (arg1[1]), (arg2[0])); + var x25: u64 = undefined; + var x26: u64 = undefined; + mulxU64(&x25, &x26, (arg1[0]), (arg2[3])); + var x27: u64 = undefined; + var x28: u64 = undefined; + mulxU64(&x27, &x28, (arg1[0]), (arg2[2])); + var x29: u64 = undefined; + var x30: u64 = undefined; + mulxU64(&x29, &x30, (arg1[0]), (arg2[1])); + var x31: u64 = undefined; + var x32: u64 = undefined; + mulxU64(&x31, &x32, (arg1[0]), (arg2[0])); + var x33: u64 = undefined; + var x34: u1 = undefined; + addcarryxU64(&x33, &x34, 0x0, x28, x7); + var x35: u64 = undefined; + var x36: u1 = undefined; + addcarryxU64(&x35, &x36, x34, x26, x5); + const x37 = (cast(u64, x36) + x18); + var x38: u64 = undefined; + var x39: u1 = undefined; + addcarryxU64(&x38, &x39, 0x0, x33, x13); + var x40: u64 = undefined; + var x41: u1 = undefined; + addcarryxU64(&x40, &x41, x39, x35, x8); + var x42: u64 = undefined; + var x43: u1 = undefined; + addcarryxU64(&x42, &x43, x41, x37, cast(u64, 0x0)); + const x44 = (cast(u64, x43) + x10); + var x45: u64 = undefined; + var x46: u1 = undefined; + addcarryxU64(&x45, &x46, 0x0, x30, x15); + var x47: u64 = undefined; + var x48: u1 = undefined; + addcarryxU64(&x47, &x48, x46, x38, x16); + var x49: u64 = undefined; + var x50: u1 = undefined; + addcarryxU64(&x49, &x50, x48, x40, x11); + var x51: u64 = undefined; + var x52: u1 = undefined; + addcarryxU64(&x51, &x52, x50, x42, x3); + var x53: u64 = undefined; + var x54: u1 = undefined; + addcarryxU64(&x53, &x54, x52, x44, cast(u64, 0x0)); + const x55 = (cast(u64, x54) + x2); + var x56: u64 = undefined; + var x57: u1 = undefined; + addcarryxU64(&x56, &x57, 0x0, x45, x21); + var x58: u64 = undefined; + var x59: u1 = undefined; + addcarryxU64(&x58, &x59, x57, x47, x19); + var x60: u64 = undefined; + var x61: u1 = undefined; + addcarryxU64(&x60, &x61, x59, x49, x14); + var x62: u64 = undefined; + var x63: u1 = undefined; + addcarryxU64(&x62, &x63, x61, x51, x6); + var x64: u64 = undefined; + var x65: u1 = undefined; + addcarryxU64(&x64, &x65, x63, x53, cast(u64, 0x0)); + var x66: u64 = undefined; + var x67: u1 = undefined; + addcarryxU64(&x66, &x67, x65, x55, cast(u64, 0x0)); + var x68: u64 = undefined; + var x69: u1 = undefined; + addcarryxU64(&x68, &x69, 0x0, x32, x23); + var x70: u64 = undefined; + var x71: u1 = undefined; + addcarryxU64(&x70, &x71, x69, x56, x24); + var x72: u64 = undefined; + var x73: u1 = undefined; + addcarryxU64(&x72, &x73, x71, x58, x22); + var x74: u64 = undefined; + var x75: u1 = undefined; + addcarryxU64(&x74, &x75, x73, x60, x17); + var x76: u64 = undefined; + var x77: u1 = undefined; + addcarryxU64(&x76, &x77, x75, x62, x9); + var x78: u64 = undefined; + var x79: u1 = undefined; + addcarryxU64(&x78, &x79, x77, x64, x1); + var x80: u64 = undefined; + var x81: u1 = undefined; + addcarryxU64(&x80, &x81, x79, x66, cast(u64, 0x0)); + var x82: u64 = undefined; + var x83: u1 = undefined; + addcarryxU64(&x82, &x83, 0x0, x68, x29); + var x84: u64 = undefined; + var x85: u1 = undefined; + addcarryxU64(&x84, &x85, x83, x70, x27); + var x86: u64 = undefined; + var x87: u1 = undefined; + addcarryxU64(&x86, &x87, x85, x72, x25); + var x88: u64 = undefined; + var x89: u1 = undefined; + addcarryxU64(&x88, &x89, x87, x74, x20); + var x90: u64 = undefined; + var x91: u1 = undefined; + addcarryxU64(&x90, &x91, x89, x76, x12); + var x92: u64 = undefined; + var x93: u1 = undefined; + addcarryxU64(&x92, &x93, x91, x78, x4); + var x94: u64 = undefined; + var x95: u1 = undefined; + addcarryxU64(&x94, &x95, x93, x80, cast(u64, 0x0)); + var x96: u64 = undefined; + var x97: u64 = undefined; + mulxU64(&x96, &x97, 0x26, x94); + var x98: u64 = undefined; + var x99: u64 = undefined; + mulxU64(&x98, &x99, 0x26, x92); + var x100: u64 = undefined; + var x101: u64 = undefined; + mulxU64(&x100, &x101, 0x26, x90); + var x102: u64 = undefined; + var x103: u64 = undefined; + mulxU64(&x102, &x103, 0x26, x88); + var x104: u64 = undefined; + var x105: u1 = undefined; + addcarryxU64(&x104, &x105, 0x0, x82, x100); + var x106: u64 = undefined; + var x107: u1 = undefined; + addcarryxU64(&x106, &x107, x105, x84, x98); + var x108: u64 = undefined; + var x109: u1 = undefined; + addcarryxU64(&x108, &x109, x107, x86, x96); + const x110 = (cast(u64, x109) + x97); + var x111: u64 = undefined; + var x112: u1 = undefined; + addcarryxU64(&x111, &x112, 0x0, x31, x102); + var x113: u64 = undefined; + var x114: u1 = undefined; + addcarryxU64(&x113, &x114, x112, x104, x103); + var x115: u64 = undefined; + var x116: u1 = undefined; + addcarryxU64(&x115, &x116, x114, x106, x101); + var x117: u64 = undefined; + var x118: u1 = undefined; + addcarryxU64(&x117, &x118, x116, x108, x99); + const x119 = (cast(u64, x118) + x110); + var x120: u64 = undefined; + var x121: u64 = undefined; + mulxU64(&x120, &x121, 0x26, x119); + var x122: u64 = undefined; + var x123: u1 = undefined; + addcarryxU64(&x122, &x123, 0x0, x111, x120); + var x124: u64 = undefined; + var x125: u1 = undefined; + addcarryxU64(&x124, &x125, x123, x113, cast(u64, 0x0)); + var x126: u64 = undefined; + var x127: u1 = undefined; + addcarryxU64(&x126, &x127, x125, x115, cast(u64, 0x0)); + var x128: u64 = undefined; + var x129: u1 = undefined; + addcarryxU64(&x128, &x129, x127, x117, cast(u64, 0x0)); + var x130: u64 = undefined; + cmovznzU64(&x130, x129, cast(u64, 0x0), 0x26); + var x131: u64 = undefined; + var x132: u1 = undefined; + addcarryxU64(&x131, &x132, 0x0, x130, x122); + out1[0] = x131; + out1[1] = x124; + out1[2] = x126; + out1[3] = x128; +} + +/// The function square squares a field element. +/// +/// Postconditions: +/// eval out1 mod 57896044618658097711785492504343953926634992332820282019728792003956564819949 = (eval arg1 * eval arg1) mod 57896044618658097711785492504343953926634992332820282019728792003956564819949 +/// +/// Input Bounds: +/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +/// Output Bounds: +/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]] +pub fn square(out1: *[4]u64, arg1: [4]u64) void { + @setRuntimeSafety(mode == .Debug); + + var x1: u64 = undefined; + var x2: u64 = undefined; + mulxU64(&x1, &x2, (arg1[0]), (arg1[3])); + var x3: u64 = undefined; + var x4: u64 = undefined; + mulxU64(&x3, &x4, (arg1[0]), (arg1[2])); + var x5: u64 = undefined; + var x6: u64 = undefined; + mulxU64(&x5, &x6, (arg1[0]), (arg1[1])); + var x7: u64 = undefined; + var x8: u64 = undefined; + mulxU64(&x7, &x8, (arg1[3]), (arg1[2])); + var x9: u64 = undefined; + var x10: u64 = undefined; + mulxU64(&x9, &x10, (arg1[3]), (arg1[1])); + var x11: u64 = undefined; + var x12: u1 = undefined; + addcarryxU64(&x11, &x12, 0x0, x6, x3); + var x13: u64 = undefined; + var x14: u1 = undefined; + addcarryxU64(&x13, &x14, x12, x4, x1); + var x15: u64 = undefined; + var x16: u1 = undefined; + addcarryxU64(&x15, &x16, x14, x2, x9); + var x17: u64 = undefined; + var x18: u1 = undefined; + addcarryxU64(&x17, &x18, x16, x10, x7); + const x19 = (cast(u64, x18) + x8); + var x20: u64 = undefined; + var x21: u64 = undefined; + mulxU64(&x20, &x21, (arg1[1]), (arg1[2])); + var x22: u64 = undefined; + var x23: u1 = undefined; + addcarryxU64(&x22, &x23, 0x0, x13, x20); + var x24: u64 = undefined; + var x25: u1 = undefined; + addcarryxU64(&x24, &x25, x23, x15, x21); + var x26: u64 = undefined; + var x27: u1 = undefined; + addcarryxU64(&x26, &x27, x25, x17, cast(u64, 0x0)); + var x28: u64 = undefined; + var x29: u1 = undefined; + addcarryxU64(&x28, &x29, x27, x19, cast(u64, 0x0)); + var x30: u64 = undefined; + var x31: u1 = undefined; + addcarryxU64(&x30, &x31, 0x0, x5, x5); + var x32: u64 = undefined; + var x33: u1 = undefined; + addcarryxU64(&x32, &x33, x31, x11, x11); + var x34: u64 = undefined; + var x35: u1 = undefined; + addcarryxU64(&x34, &x35, x33, x22, x22); + var x36: u64 = undefined; + var x37: u1 = undefined; + addcarryxU64(&x36, &x37, x35, x24, x24); + var x38: u64 = undefined; + var x39: u1 = undefined; + addcarryxU64(&x38, &x39, x37, x26, x26); + var x40: u64 = undefined; + var x41: u1 = undefined; + addcarryxU64(&x40, &x41, x39, x28, x28); + const x42 = ((cast(u64, x41) + cast(u64, x29)) + cast(u64, x29)); + var x43: u64 = undefined; + var x44: u64 = undefined; + mulxU64(&x43, &x44, (arg1[3]), (arg1[3])); + var x45: u64 = undefined; + var x46: u64 = undefined; + mulxU64(&x45, &x46, (arg1[2]), (arg1[2])); + var x47: u64 = undefined; + var x48: u64 = undefined; + mulxU64(&x47, &x48, (arg1[1]), (arg1[1])); + var x49: u64 = undefined; + var x50: u64 = undefined; + mulxU64(&x49, &x50, (arg1[0]), (arg1[0])); + var x51: u64 = undefined; + var x52: u1 = undefined; + addcarryxU64(&x51, &x52, 0x0, x30, x50); + var x53: u64 = undefined; + var x54: u1 = undefined; + addcarryxU64(&x53, &x54, x52, x32, x47); + var x55: u64 = undefined; + var x56: u1 = undefined; + addcarryxU64(&x55, &x56, x54, x34, x48); + var x57: u64 = undefined; + var x58: u1 = undefined; + addcarryxU64(&x57, &x58, x56, x36, x45); + var x59: u64 = undefined; + var x60: u1 = undefined; + addcarryxU64(&x59, &x60, x58, x38, x46); + var x61: u64 = undefined; + var x62: u1 = undefined; + addcarryxU64(&x61, &x62, x60, x40, x43); + var x63: u64 = undefined; + var x64: u1 = undefined; + addcarryxU64(&x63, &x64, x62, x42, x44); + var x65: u64 = undefined; + var x66: u64 = undefined; + mulxU64(&x65, &x66, 0x26, x63); + var x67: u64 = undefined; + var x68: u64 = undefined; + mulxU64(&x67, &x68, 0x26, x61); + var x69: u64 = undefined; + var x70: u64 = undefined; + mulxU64(&x69, &x70, 0x26, x59); + var x71: u64 = undefined; + var x72: u64 = undefined; + mulxU64(&x71, &x72, 0x26, x57); + var x73: u64 = undefined; + var x74: u1 = undefined; + addcarryxU64(&x73, &x74, 0x0, x51, x69); + var x75: u64 = undefined; + var x76: u1 = undefined; + addcarryxU64(&x75, &x76, x74, x53, x67); + var x77: u64 = undefined; + var x78: u1 = undefined; + addcarryxU64(&x77, &x78, x76, x55, x65); + const x79 = (cast(u64, x78) + x66); + var x80: u64 = undefined; + var x81: u1 = undefined; + addcarryxU64(&x80, &x81, 0x0, x49, x71); + var x82: u64 = undefined; + var x83: u1 = undefined; + addcarryxU64(&x82, &x83, x81, x73, x72); + var x84: u64 = undefined; + var x85: u1 = undefined; + addcarryxU64(&x84, &x85, x83, x75, x70); + var x86: u64 = undefined; + var x87: u1 = undefined; + addcarryxU64(&x86, &x87, x85, x77, x68); + const x88 = (cast(u64, x87) + x79); + var x89: u64 = undefined; + var x90: u64 = undefined; + mulxU64(&x89, &x90, 0x26, x88); + var x91: u64 = undefined; + var x92: u1 = undefined; + addcarryxU64(&x91, &x92, 0x0, x80, x89); + var x93: u64 = undefined; + var x94: u1 = undefined; + addcarryxU64(&x93, &x94, x92, x82, cast(u64, 0x0)); + var x95: u64 = undefined; + var x96: u1 = undefined; + addcarryxU64(&x95, &x96, x94, x84, cast(u64, 0x0)); + var x97: u64 = undefined; + var x98: u1 = undefined; + addcarryxU64(&x97, &x98, x96, x86, cast(u64, 0x0)); + var x99: u64 = undefined; + cmovznzU64(&x99, x98, cast(u64, 0x0), 0x26); + var x100: u64 = undefined; + var x101: u1 = undefined; + addcarryxU64(&x100, &x101, 0x0, x99, x91); + out1[0] = x100; + out1[1] = x93; + out1[2] = x95; + out1[3] = x97; +} diff --git a/src/Arithmetic/SolinasReduction.v b/src/Arithmetic/SolinasReduction.v new file mode 100644 index 0000000000..993dd8125e --- /dev/null +++ b/src/Arithmetic/SolinasReduction.v @@ -0,0 +1,2802 @@ +Require Import Coq.ZArith.ZArith. +Require Import Coq.QArith.QArith. +Require Import Coq.QArith.Qround. +Require Import Coq.Strings.String. +Require Import Coq.derive.Derive. +Require Import Coq.Lists.List. +Require Import Crypto.Util.ZRange. +Require Import Crypto.Arithmetic.Core. +Require Import Crypto.Arithmetic.ModOps. +Require Import Crypto.Arithmetic.Partition. +Require Import Crypto.Arithmetic.UniformWeight. +Require Import Crypto.Arithmetic.Saturated. +Require Coq.btauto.Btauto. +Require Coq.Structures.OrdersEx. +Require Import Crypto.Util.ListUtil.StdlibCompat. +Require Import Crypto.Util.ZUtil.ModInv. + +Require Import Coq.micromega.Lia. +Require Import Crypto.Algebra.Ring. +Require Import Crypto.Util.Decidable. +Require Import Crypto.Util.LetIn. +Require Import Crypto.Util.ListUtil. +Require Import Crypto.Util.ListUtil.FoldBool. +Require Import Crypto.Util.NatUtil. +Require Import Crypto.Util.Prod. +Require Import Crypto.Util.Tactics.BreakMatch. +Require Import Crypto.Util.Tactics.UniquePose. +Require Import Crypto.Util.ZUtil.Definitions. +Require Import Crypto.Util.ZUtil.AddGetCarry Crypto.Util.ZUtil.MulSplit. +Require Import Crypto.Util.ZUtil.Modulo Crypto.Util.ZUtil.Div. +Require Import Crypto.Util.ZUtil.Hints.Core. +Require Import Crypto.Util.ZUtil.Tactics.LtbToLt. +Require Import Crypto.Util.ZUtil.Tactics.RewriteModSmall. +Require Import Crypto.Util.ZUtil.Tactics.PullPush.Modulo. +Require Import Coq.ZArith.Znat. + +Require Import Crypto.Util.CPSUtil. +Require Import Crypto.Util.CPSNotations. +Local Open Scope cps_scope. +Notation "x' <- v ; C" := (v (fun x' => C)) (only parsing). + +Require Import Crypto.Util.Notations. +Local Open Scope string_scope. +Local Open Scope list_scope. +Import ListNotations. Local Open Scope Z_scope. + +Import Associational Positional. + +Local Coercion Z.of_nat : nat >-> Z. +Local Coercion QArith_base.inject_Z : Z >-> Q. +Local Coercion Z.pos : positive >-> Z. + +Module SolinasReduction. + + Import Core.Associational. + Import Core.Positional. + + Section __. + + Context (machine_wordsize := 64) + (weight := uweight machine_wordsize) + (up_bound := 2 ^ (machine_wordsize / 4)) + {wprops : @weight_properties weight}. + + Ltac weight_comp := + unfold weight, uweight, ModOps.weight, machine_wordsize; + try rewrite !Z.div_1_r; + try rewrite !Z.opp_involutive; + try rewrite !Nat2Z.inj_succ; + try rewrite !OrdersEx.Z_as_OT.mul_succ_r; + try rewrite !OrdersEx.Z_as_OT.pow_add_r; + autorewrite with zsimplify_const; + ring_simplify. + + Ltac solve_ineq := + repeat + match goal with + | |- 0 <= _ + _ => apply OrdersEx.Z_as_OT.add_nonneg_nonneg + | |- 0 < _ * _ => apply OrdersEx.Z_as_OT.mul_pos_pos + | |- 0 <= _ * _ => apply OrdersEx.Z_as_OT.mul_nonneg_nonneg + | |- 0 <= _ / _ => apply OrdersEx.Z_as_OT.div_pos + | |- _ / _ < _ => apply OrdersEx.Z_as_OT.div_lt_upper_bound + + | |- _ + ?x < _ + ?x => apply OrdersEx.Z_as_OT.add_lt_mono_r + | |- _ + _ < _ => apply OrdersEx.Z_as_OT.add_lt_mono + | |- _ + _ <= _ => apply OrdersEx.Z_as_OT.add_le_mono + | |- _ - ?x < _ - ?x => rewrite <-OrdersEx.Z_as_OT.sub_lt_mono_r + | |- _ - ?x <= _ - ?x => rewrite <-OrdersEx.Z_as_OT.sub_le_mono_r + + | _ => apply Z.mod_small + | |- _ mod (?x * ?y) < (?y * ?x) => rewrite Z.mul_comm with (n:=x) + | _ => apply OrdersEx.Z_as_OT.mod_pos_bound + (* | [ |- 0 <= _ mod _ ] => apply Z_mod_nonneg_nonneg *) + | [ |- 0 <= weight _ ] => apply OrdersEx.Z_as_OT.lt_le_incl; auto + + | _ => split + | _ => lia + end. + + Ltac le_lt := + (rewrite Le.Z.le_sub_1_iff || rewrite <-Le.Z.le_sub_1_iff). + + Hint Rewrite Nat.add_0_l : const_simpl. + Hint Rewrite Nat.add_0_r : const_simpl. + Hint Rewrite Z.add_0_l : const_simpl. + Hint Rewrite Z.add_0_r : const_simpl. + Lemma S_sub_1 : forall (n : nat), + (n > 0)%nat -> + S (n - 1)%nat = n. + Proof using Type. lia. Qed. + Hint Rewrite S_sub_1 using lia : const_simpl. + Lemma Sn_sub_n : forall (n : nat), + (S n - n)%nat = 1%nat. + Proof using Type. lia. Qed. + Hint Rewrite Sn_sub_n : const_simpl. + Lemma n2_sub : forall (n : nat), + (2 * n - n)%nat = n. + Proof using Type. lia. Qed. + Hint Rewrite n2_sub : const_simpl. + Ltac const_simpl := + autorewrite with const_simpl in *. + + Hint Rewrite eval_cons using auto : push_eval. + Hint Rewrite eval_sat_mul using lia : push_eval. + Hint Rewrite eval_sat_mul_const using lia : push_eval. + Hint Rewrite eval_split using auto : push_eval. + Hint Rewrite Rows.eval_from_associational using (auto || lia) : push_eval. + Hint Rewrite Rows.flatten_mod using (eauto using Rows.length_from_associational) : push_eval. + Hint Rewrite Rows.flatten_correct using (eauto using Rows.length_from_associational) : push_eval. + Hint Rewrite eval_add_to_nth using auto : push_eval. + + Hint Rewrite @nil_length0 cons_length app_length seq_length map_length firstn_length @skipn_length length_partition length_add_to_nth : push_length. + Hint Rewrite (@ListUtil.length_snoc) : push_length. + Hint Rewrite Rows.length_flatten using (eauto using Rows.length_from_associational) : push_length. + + Hint Rewrite map_nil map_cons map_app map_map in_map_iff : push_misc. + Hint Rewrite @combine_app_samelength : push_misc. + Hint Rewrite @combine_nil_r @combine_cons : push_misc. + Hint Rewrite @fold_right_cons fold_right_app : push_misc. + Hint Rewrite seq_add : push_misc. + Hint Rewrite split_app : push_misc. + Hint Rewrite @nth_default_cons_S : push_misc. + Hint Rewrite @firstn_map firstn_seq firstn_app : push_misc. + Hint Rewrite @skipn_app @skipn_0 : push_misc. + Hint Rewrite @fst_pair @snd_pair : push_misc. + Hint Rewrite app_nil_r app_nil_l : push_misc. + Hint Rewrite Nat.sub_diag : push_misc. + + Hint Resolve in_or_app : core. + Hint Resolve in_eq : core. + Hint Resolve in_cons : core. + + Hint Unfold eval : unfold_eval. + Hint Unfold Associational.eval : unfold_eval. + Hint Unfold to_associational : unfold_eval. + + Ltac push := + autorewrite with push_eval push_length push_misc zsimplify_const; + auto. + + Ltac push' H := + autorewrite with push_eval push_length push_misc zsimplify_const in H; + auto. + + Lemma seq_double : forall n, + seq 0 (2 * n) = seq 0 n ++ seq n n. + Proof using Type. + intros n; replace (2*n)%nat with (n+n)%nat; push; lia. + Qed. + Hint Rewrite seq_double : push_misc. + + Lemma map_weight_seq : forall m p, + map weight (seq 0 p) = map (fun t => t / (weight m)) (map weight (seq m p)). + Proof using wprops. + induction m as [| m IHm]; intros; push. + erewrite map_ext. + eauto. + intros. + cbn. + rewrite Z.div_1_r. + lia. + + rewrite IHm. + rewrite <-seq_shift. + push. + apply map_ext_in. + intros a H. + rewrite in_seq in H. + weight_comp; try lia. + rewrite <-!Z.pow_add_r; try lia. + rewrite <-!Z.pow_sub_r; try lia. + f_equal. + lia. + Qed. + Hint Rewrite <-map_weight_seq : push_misc. + + Lemma seq_shift_1 : forall len, + map S (seq 0 len) = seq 1 len. + Proof using Type. + intros. + apply seq_shift. + Qed. + Hint Rewrite <-seq_shift_1 : push_misc. + + (* SECTION CANONICAL_REPR *) + + Definition canonical_repr n (p : list Z) : Prop := + length p = n /\ + p = Partition.partition weight n (Positional.eval weight n p). + + Lemma canonical_pos n : forall (p : list Z), + canonical_repr n p -> + 0 <= eval weight n p. + Proof using wprops. + intros; + repeat match goal with + | H : canonical_repr _ _ |- _ => + unfold canonical_repr in H; + destruct H as [ _ H ]; + rewrite H; + rewrite Partition.eval_partition + | _ => apply Z.mod_pos_bound + | _ => auto + end. + Qed. + + Lemma canonical_bounded n : forall (p : list Z), + canonical_repr n p -> + forall x, In x p -> 0 <= x < 2 ^ machine_wordsize. + Proof using wprops. + intros; + repeat multimatch goal with + | H : canonical_repr ?n ?p |- _ => + pose proof (canonical_pos n p H); + cbv [canonical_repr Partition.partition] in H; + destruct H as [ Hlen Hpart ] + | H1 : In _ ?p, H2 : ?p = _ |- _ => + rewrite H2 in H1; + autorewrite with push_misc in H1 + | H : context[exists _, _] |- _ => destruct H + | H : _ = ?x |- 0 <= ?x => rewrite <-H + | H : _ = ?x |- ?x < _ => rewrite <-H + | _ => unfold weight; rewrite uweight_S; fold weight + | _ => solve_ineq + | _ => progress intuition + | _ => auto || lia + end. + Qed. + + Lemma canonical_iff p n : + canonical_repr n p <-> + length p = n /\ + forall x, In x p -> 0 <= x < 2 ^ machine_wordsize. + Proof using wprops. + split; intros; + repeat multimatch goal with + | H : length _ = _ |- _ => rewrite H + | |- length _ = _ => unfold canonical_repr in * + | |- _ = Partition.partition _ _ _ => unfold canonical_repr in * + | |- canonical_repr _ _ => unfold canonical_repr + | _ => eapply canonical_bounded + | _ => progress intuition + | _ => eauto || lia + end. + apply uweight_partition_unique. + lia. + lia. + intros. + rewrite Le.Z.le_sub_1_iff. + auto. + Qed. + + Lemma canonical_cons n a p: + canonical_repr (S n) (a :: p) -> + canonical_repr n p. + Proof using wprops. + intros. + rewrite canonical_iff in *. + intuition; + repeat multimatch goal with + | H : context[_ <= _ < _] |- _ => apply H + | _ => cbn + | _ => auto + end. + Qed. + + Lemma canonical_app_l n n1 n2 l l1 l2 : + canonical_repr n l -> + length l1 = n1 -> + length l2 = n2 -> + n = (n1 + n2)%nat -> + l = l1 ++ l2 -> + canonical_repr n1 l1. + Proof using wprops. + intros. + rewrite canonical_iff in *; intuition; + repeat multimatch goal with + | H : context[_ <= _ < _] |- _ => apply H + | H : ?x = _ ++ _ |- In _ ?x => rewrite H + | _ => cbn + | _ => auto + end. + Qed. + + Lemma canonical_app_r n n1 n2 l l1 l2 : + canonical_repr n l -> + length l1 = n1 -> + length l2 = n2 -> + n = (n1 + n2)%nat -> + l = l1 ++ l2 -> + canonical_repr n2 l2. + Proof using wprops. + intros. + rewrite canonical_iff in *; intuition; + repeat multimatch goal with + | H : context[_ <= _ < _] |- _ => apply H + | H : ?x = _ ++ _ |- In _ ?x => rewrite H + | _ => cbn + | _ => auto + end. + Qed. + + Lemma fold_right_add : forall l x, + fold_right Z.add x l = x + fold_right Z.add 0 l. + Proof using Type. + intros l x. + induction l as [ | l' IHl ]; cbn; try rewrite IHl; lia. + Qed. + + Definition eval_weight_P p := forall a b, + Associational.eval (combine (map (fun x0 : nat => weight (S x0)) (seq a b)) p) = + weight 1 * Associational.eval (combine (map weight (seq a b)) p). + + Lemma eval_weight_S' : forall p, + eval_weight_P p. + Proof using Type. + apply (ListAux.list_length_induction Z). + unfold eval_weight_P. + intros l1 H n b. + pose proof (@break_list_last Z l1). + cbv [eval_weight_P eval Associational.eval to_associational] in *. + intuition; + repeat multimatch goal with + | H : context[exists _, _] |- _ => destruct H + | _ => autorewrite with push_eval push_misc + | _ => progress subst + | _ => lia || auto + end. + + destruct (b <=? length x)%nat eqn:E. + rewrite Nat.leb_le in E. + rewrite combine_truncate_r. + rewrite combine_truncate_r with (xs:=map weight (seq n b)). + push. + apply H. + push. + rewrite Nat.min_l; lia. + + rewrite Nat.leb_gt in E. + rewrite combine_truncate_l. + rewrite combine_truncate_l with (xs:=map weight (seq n b)). + autorewrite with push_length push_misc. + rewrite Nat.min_l; [|lia]. + rewrite seq_snoc. + autorewrite with push_misc. + push. + rewrite fold_right_add. + symmetry. + rewrite fold_right_add. + symmetry. + rewrite fold_right_add. + rewrite H. + ring_simplify. + unfold weight, machine_wordsize. + rewrite uweight_S; [|lia]. + cbn; break_match; lia. + push. + push. + push. + Qed. + + Lemma eval_weight_S p n: + eval (fun i : nat => weight (S i)) n p = + (eval weight n p) * weight 1. + Proof using Type. + cbv [eval to_associational]. + rewrite eval_weight_S'. + lia. + Qed. + Hint Rewrite eval_weight_S : push_eval. + + Lemma eval_weight_S_gen p a b : + Associational.eval (combine (map (fun x0 : nat => weight (S x0)) (seq a b)) p) = + weight 1 * Associational.eval (combine (map weight (seq a b)) p). + Proof using Type. + apply eval_weight_S'. + Qed. + Hint Rewrite eval_weight_S_gen : push_eval. + + Lemma canonical_eval_bounded n : forall (p : list Z), + canonical_repr n p -> + eval weight n p < weight n. + Proof using wprops. + intros p. + generalize dependent n. + induction p as [| a p IHp]; intros n H; destruct n; push; try lia; + assert (H' := H); unfold canonical_repr in H'; push' H'. + lia. + le_lt. + etransitivity. + solve_ineq. + le_lt. + eapply canonical_bounded; eauto. + rewrite <-OrdersEx.Z_as_OT.mul_le_mono_pos_r; eauto. + le_lt. + apply IHp. + eapply canonical_app_r with (l1:=[a]); eauto. + all: try lia. + weight_comp; lia. + Qed. + + Definition dual_map {A B : Type} (f : A -> B -> bool) (l1 : list A) (l2 : list B) := + map (fun x => (f (fst x) (snd x))) (combine l1 l2). + Definition fold_andb_map' {A B : Type} (f : A -> B -> bool) (ls1 : list A) (ls2 : list B) := + fold_right andb true (dual_map f ls1 ls2). + Definition is_bounded_by bounds ls := + fold_andb_map' (fun r v'' => (fst r <=? v'') && (v'' <=? snd r)) bounds ls. + Hint Unfold is_bounded_by : core. + Hint Unfold fold_andb_map' : core. + Hint Unfold dual_map : core. + + Lemma canonical_is_bounded_by : forall n p, + canonical_repr n p <-> + length p = n /\ + is_bounded_by (repeat (0, 2^machine_wordsize-1) n) p = true. + Proof using wprops. + intros n p. + rewrite canonical_iff. + repeat autounfold. + split. + intros H. + destruct H as [H H1]. + intuition. + generalize dependent n. + induction p as [| a p IHp]; intros; + repeat multimatch goal with + | H : length _ = ?x |- _ => progress cbn in H; subst x + | _ => apply andb_true_intro + | _ => rewrite Z.leb_le + | _ => rewrite Le.Z.le_sub_1_iff + | _ => apply H1 + | _ => eapply IHp + | _ => progress cbn || intuition + | _ => progress intuition + | _ => reflexivity || lia || auto + | [ |- _ <= 18446744073709551615] => replace 18446744073709551615 with (18446744073709551616 - 1) by lia + end. + split. + intuition. + generalize dependent n. + induction p; intros; + repeat multimatch goal with + | H : length _ = ?x |- _ => cbn in H; rewrite <-H in * + | H : In _ _ |- _ => cbn in H + | H : context[S _] |- _ => cbn in H + | H : context[_ && _] |- _ => rewrite andb_true_iff in H + | H : context[_ <=? _] |- _ => rewrite <-Zle_is_le_bool in H + | _ => progress cbn || intuition || subst + | _ => lia + | _ => eapply IHp + end. + Qed. + + Lemma eval_is_bounded_by_pos n : forall p, + is_bounded_by (repeat (0, 2 ^ machine_wordsize - 1) n) p = true -> + 0 <= eval weight n p. + Proof. + intros p. + pose proof eval_weight_S as Heval. + repeat autounfold with * in *. + generalize dependent n; induction p; intros n; destruct n; + repeat multimatch goal with + | H : context[fold_right _ _ _] |- _ => cbn in H + | H : context[_ && _] |- _ => rewrite andb_true_iff in H + | H : context[_ <=? _] |- _ => rewrite <-Zle_is_le_bool in H + | _ => solve_ineq + | _ => rewrite Heval + | _ => push + | _ => cbn + | _ => intuition + | _ => break_match + | _ => lia + end. + Qed. + + Lemma eval_is_bounded_by n : forall p, + is_bounded_by (repeat (0, 2 ^ machine_wordsize - 1) n) p = true -> + 0 <= eval weight n p < weight n. + Proof using wprops. + intros p. + split. + apply eval_is_bounded_by_pos; auto. + pose proof eval_weight_S as Heval. + repeat autounfold with * in *. + generalize dependent n; induction p; intros n; destruct n; + repeat multimatch goal with + | H : context[fold_right _ _ _] |- _ => progress cbn in H + | H : context[_ && _] |- _ => rewrite andb_true_iff in H + | H : context[_ <=? _] |- _ => rewrite Z.leb_le in H + | _ => solve_ineq + | _ => push + | _ => rewrite Heval + | _ => progress cbn || intuition + | _ => lia || auto || reflexivity || discriminate + end. + le_lt. + etransitivity. + solve_ineq. + break_match; eauto. + apply Z.mul_le_mono_nonneg_r; try lia. + le_lt. + apply IHp; auto. + weight_comp; lia. + Qed. + Hint Resolve eval_is_bounded_by : ibb. + + Lemma is_bounded_by_cons1 : forall b bounds p' p, + is_bounded_by (b :: bounds) (p' :: p) = true -> + is_bounded_by bounds p = true. + Proof using Type. + intros; repeat autounfold in *; match goal with | H : _ |- _ => push' H end. + Qed. + Hint Resolve is_bounded_by_cons1 : ibb. + + Lemma is_bounded_by_cons2 : forall b bounds p' p, + is_bounded_by (b :: bounds) (p' :: p) = true -> + fst b <= p' <= snd b. + Proof using Type. + intros; repeat autounfold in *; match goal with | H : _ |- _ => push' H end. + Qed. + Hint Resolve is_bounded_by_cons2 : ibb. + + Lemma is_bounded_by_cons : forall b bounds p' p, + is_bounded_by (b :: bounds) (p' :: p) = true -> + is_bounded_by bounds p = true /\ + fst b <= p' <= snd b. + Proof using Type. + intros; repeat autounfold in *; match goal with | H : _ |- _ => push' H end. + Qed. + Hint Resolve is_bounded_by_cons : ibb. + + Lemma is_bounded_by_nth n : forall p bounds, + is_bounded_by bounds p = true -> + (n < length p)%nat -> + (n < length bounds)%nat -> + fst (nth_default (0,0) bounds n) <= nth_default 0 p n <= snd (nth_default (0,0) bounds n). + Proof using Type. + intros p bounds H H0 H1. + generalize dependent n. + generalize dependent p. + induction bounds as [ | b bounds IHbounds ]; + intros p ? n; destruct n; destruct p; intros; + repeat multimatch goal with + | H : _ |- _ => autorewrite with push_length in H + | _ => apply IHbounds + | _ => autorewrite with push_misc + | _ => cbn + | _ => eauto with ibb + | _ => lia + end. + Qed. + Hint Resolve is_bounded_by_nth : ibb. + + Lemma is_bounded_by_app_l : forall bound1 bound2 l1 l2, + is_bounded_by (bound1 ++ bound2) (l1 ++ l2) = true -> + length bound1 = length l1 -> + is_bounded_by bound1 l1 = true. + Proof using Type. + intros b1 b2 l1 l2 H H1. + generalize dependent b1. + generalize dependent b2. + generalize dependent l2. + induction l1 as [ | ? ? IHl1 ]; intros; destruct b1; + repeat multimatch goal with + | _ => autounfold in * + | _ => eapply IHl1 + | _ => rewrite Z.leb_le + | H : _ |- _ => rewrite <-!app_comm_cons in H; push' H + | H : _ |- _ => rewrite andb_true_iff in H + | _ => rewrite andb_true_iff + | _ => intuition + | _ => push + | _ => lia + | _ => eauto + end. + Qed. + Hint Resolve is_bounded_by_app_l : ibb. + + Lemma fold_right_andb_default : forall d l, + fold_right andb d l = true -> d = true. + Proof using Type. + intros; induction l; + repeat multimatch goal with + | H : context[fold_right _ _ _] |- _ => push' H + end. + Qed. + Hint Resolve fold_right_andb_default : core. + + Lemma is_bounded_by_app_r : forall bound1 bound2 l1 l2, + is_bounded_by (bound1 ++ bound2) (l1 ++ l2) = true -> + length bound1 = length l1 -> + is_bounded_by bound2 l2 = true. + Proof using Type. + intros b1 b2 l1 l2 H H1. + generalize dependent b1. + generalize dependent b2. + generalize dependent l2. + induction l1 as [ | ? ? IHl1 ]; + intros l2 b2 b1; [ | specialize (IHl1 l2 b2 b1)]; destruct b1; + repeat multimatch goal with + | _ => autounfold in * + | _ => rewrite Z.leb_le + | H : context[length _] |- _ => autorewrite with push_length in H + | H : context[(_ :: _) ++ _] |- _ => rewrite <-!app_comm_cons in H; push' H + | H : _ |- _ => rewrite andb_true_iff in H + | _ => rewrite andb_true_iff + | _ => intuition + | _ => eauto + | _ => discriminate + end. + Qed. + + Lemma is_bounded_by_loosen : forall l bound1 bound2, + length bound1 = length bound2 -> + is_bounded_by bound1 l = true -> + fold_andb_map' (fun x y => (fst y <=? fst x) && (snd x <=? snd y)) bound1 bound2 = true -> + is_bounded_by bound2 l = true. + Proof using Type. + intros l bound1 bound2 H H0 H1. + generalize dependent bound1. + generalize dependent bound2. + repeat autounfold. + induction l as [ | ? ? IHl]; intros; destruct bound1; destruct bound2; + repeat match goal with + | H : context[length _] |- _ => progress autorewrite with push_length in H + | H : context[_ :: _] |- _ => progress autorewrite with push_misc in H + | _ => apply IHl + | _ => rewrite Z.leb_le + | H : _ |- _ => rewrite Z.leb_le in H + | _ => rewrite andb_true_iff + | H : _ |- _ => rewrite andb_true_iff in H + | _ => progress intuition + | _ => progress push + | _ => lia + | _ => eauto + end. + Qed. + + Lemma bounds_same : forall b, + fold_andb_map' (fun x y => (fst y <=? fst x) && (snd x <=? snd y)) b b = true. + Proof using Type. + intros b. + repeat autounfold. + induction b; + repeat match goal with + | _ => progress push + | _ => rewrite andb_true_iff + | _ => rewrite Z.leb_le + | _ => progress intuition + | _ => lia + end. + Qed. + + (* END SECTION CANONICAL_REPR *) + + Ltac solve_length q := + try match goal with + | [ H : canonical_repr _ q |- _ ] => + unfold canonical_repr in H; intuition + end; + try match goal with + | [ H : length q = _ |- _] => + rewrite !app_length in H; + try rewrite !app_length; + cbn [length] in H; cbn [length]; lia + end; + match goal with + | [ H : q = _ |- _ ] => + apply f_equal with (f:=fun l => length l) in H; + rewrite !app_length in H; + try rewrite !app_length; + cbn [length] in H; cbn [length]; lia + end. + + Ltac solve_in := + repeat + match goal with + | [ |- In ?hi ?p ] => + match goal with + | [ H : p = _ ++ _ |- _ ] => + rewrite H; apply in_or_app; simpl; auto + | [ H : p = _ ++ _ ++ _ |- _ ] => + rewrite app_assoc in H + end + end. + + Ltac apply_iff p := + match goal with + | [ H : canonical_repr _ p |- _ ] => + rewrite canonical_iff in H; + destruct H as [ _ Htmp ]; + apply Htmp; + solve_in + end. + Ltac solve_hi := + match goal with + | [ |- 0 <= ?hi ] => + match goal with + | [ H : ?p = _ ++ [hi] |- _ ] => apply_iff p + | [ H : ?p = _ ++ [hi] ++ _ |- _ ] => apply_iff p + | [ H : ?p = _ ++ _ ++ [hi] |- _ ] => apply_iff p + end + end. + + Ltac adjust_ineq_lt H := + match type of H with + | context[ ?x < ?y ] => + match goal with + | [ |- context[ x * ?z ] ] => + apply Zmult_lt_compat_r with (p:=z) in H; eauto + end + end. + Ltac adjust_ineq_le H := + match type of H with + | context[ ?x <= ?y ] => + match goal with + | [ |- context[ x * ?z ] ] => + apply Zmult_le_compat_r with (p:=z) in H; eauto + end + end. + Ltac adjust_ineq H := adjust_ineq_le H || adjust_ineq_lt H. + + Ltac canonical_app p := + let H' := fresh "TEMP" in + pose proof (eq_refl p) as H'; + match goal with + | [ H : p = ?lo ++ ?hi |- _ ] => + let H1 := fresh "Hcanon_l" in + let H2 := fresh "Hcanon_r" in + match goal with + | [ H' : canonical_repr _ p |- _ ] => + eapply canonical_app_l with (l1:=lo) (n1:=length lo) (l2:=hi) (n2:=length hi) in H' as H1; + eapply canonical_app_r with (l1:=lo) (n1:=length lo) (l2:=hi) (n2:=length hi) in H' as H2; + try (solve_length p) + end + end; + clear H'. + + Ltac subst_canon q := + match goal with + | [ H : canonical_repr ?n1 ?p |- canonical_repr ?n2 ?p ] => + replace n2 with n1 by (solve_length q); + auto + end. + + Definition sat_reduce base s c n (p : list (Z * Z)) := + let s' := fst (Saturated.Rows.adjust_s weight (S (S n)) s) in + let lo_hi := Associational.split s' p in + let coef := Saturated.Associational.sat_mul_const base [(1, s'/s)] c in + let hi := Saturated.Associational.sat_mul_const base coef (snd lo_hi) in + let r := (fst lo_hi) ++ hi in + r. + + Lemma value_sat_reduce base s c n (p : list (Z * Z)) (basenz:base<>0): + let s' := fst (Saturated.Rows.adjust_s weight (S (S n)) s) in + let coef := Saturated.Associational.sat_mul_const base [(1, s'/s)] c in + let lo_hi := Associational.split s' p in + Associational.eval (sat_reduce base s c n p) = + Associational.eval coef * Associational.eval (snd lo_hi) + Associational.eval (fst lo_hi). + Proof. + intros; cbv [sat_reduce] in *; cbv [s' lo_hi coef]. + autorewrite with push_eval; lia. + Qed. + Hint Rewrite value_sat_reduce : push_eval. + + Lemma adjust_s_invariant fuel s (s_nz:s<>0) : + fst (Saturated.Rows.adjust_s weight fuel s) mod s = 0 + /\ fst (Saturated.Rows.adjust_s weight fuel s) <> 0. + Proof using wprops. + cbv [Saturated.Rows.adjust_s]; rewrite fold_right_map; generalize (List.rev (seq 0 fuel)); intro ls; induction ls as [|l ls IHls]; + cbn. + { rewrite Z.mod_same by assumption; auto. } + { break_match; cbn in *; auto with zarith. } + Qed. + + Lemma adjust_s_finished' fuel s w (s_nz:s<>0) : + Rows.adjust_s weight fuel s = (w, true) -> + Rows.adjust_s weight (S fuel) s = (w, true). + Proof using Type. + cbv [Rows.adjust_s]. + rewrite !fold_right_map. + replace (rev (seq 0 (S fuel))) with (fuel :: rev (seq 0 fuel)). + generalize (rev (seq 0 fuel)). + cbn in *. + intros l. + induction l; + break_match; auto; discriminate. + rewrite seq_snoc. + rewrite rev_app_distr. + reflexivity. + Qed. + + Lemma adjust_s_finished fuel fuel' s w (s_nz:s<>0) : + (fuel' > fuel)%nat -> + Saturated.Rows.adjust_s weight fuel s = (w, true) -> + Saturated.Rows.adjust_s weight fuel' s = (w, true). + Proof using Type. + induction 1; intros; apply adjust_s_finished'; auto. + Qed. + + Lemma eval_sat_reduce base s c fuel p : + base <> 0 + -> s - Associational.eval c <> 0 + -> s <> 0 + -> Associational.eval (sat_reduce base s c fuel p) mod (s - Associational.eval c) + = Associational.eval p mod (s - Associational.eval c). + Proof using wprops. + intros; cbv [sat_reduce]. + lazymatch goal with + | |- context[Saturated.Rows.adjust_s ?weight ?fuel ?s] => + destruct (adjust_s_invariant fuel s ltac:(assumption)) as [Hmod ?] + end. + eta_expand; autorewrite with push_eval zsimplify_const; cbn [fst snd]. + rewrite <- (Z.mul_comm (Associational.eval c)), <- !Z.mul_assoc, <-Associational.reduction_rule by auto. + autorewrite with zsimplify_const; rewrite !Z.mul_assoc, Z.mul_div_eq_full, Hmod by auto. + autorewrite with zsimplify_const push_eval; trivial. + Qed. + Hint Rewrite eval_sat_reduce using auto : push_eval. + + Definition mul_no_reduce base n (p q : list Z) := + let p_a := Positional.to_associational weight n p in + let q_a := Positional.to_associational weight n q in + let pq_a := Saturated.Associational.sat_mul base p_a q_a in + let pq_rows := Saturated.Rows.from_associational weight (2*n) pq_a in + let pq := Saturated.Rows.flatten weight (2*n) pq_rows in + let bound := (0, 2^machine_wordsize - 1) in + if (is_bounded_by (repeat bound n) p) then + if (is_bounded_by (repeat bound n) q) then + fst pq + else + add_to_nth 0 (weight (2 * n) * snd pq) (fst pq) + else + add_to_nth 0 (weight (2 * n) * snd pq) (fst pq). + + Definition reduce1 base s c n m (p : list Z) := + let bound := (0, 2^machine_wordsize - 1) in + if (is_bounded_by (repeat bound n) p) then + let p_a := Positional.to_associational weight n p in + let r_a := sat_reduce base s c n p_a in + let r_rows := Saturated.Rows.from_associational weight m r_a in + let r_flat := Saturated.Rows.flatten weight m r_rows in + fst r_flat + else + let p_a := Positional.to_associational weight n p in + let r_a := sat_reduce base s c n p_a in + let r_rows := Saturated.Rows.from_associational weight m r_a in + let r_flat := Saturated.Rows.flatten weight m r_rows in + add_to_nth 0 (weight (m) * snd r_flat) (fst r_flat). + + (* S n -> n limbs *) + Definition reduce3 base s c n (p : list Z) := + let bound := (0, 2^machine_wordsize-1) in + let bounds := (repeat bound n) ++ [(0, 1)] in + let s' := fst (Saturated.Rows.adjust_s weight (S (S n)) s) in + let coef_a := Saturated.Associational.sat_mul_const base [(1, s'/s)] c in + let coef := Associational.eval coef_a in + dlet_nd hi := Z.zselect (nth_default 0 p n) 0 coef in + let lo := Saturated.Rows.flatten weight 1 [ [hi]; [nth_default 0 p 0] ] in + if (is_bounded_by bounds p) then + (fst lo) ++ (skipn 1 (firstn n p)) + else + let hi' := coef * (nth_default 0 p n) in + add_to_nth 0 hi' (firstn n p). + + Definition reduce_full base s c n (p : list Z) := + let r1 := reduce1 base s c (2*n) (S n) p in + let bound := (0, 2^machine_wordsize - 1) in + let bounds := repeat bound n ++ [(0, up_bound-1)] in + let r2 := reduce1 base s c (S n) (S n) r1 in + let r3 := reduce3 base s c n r2 in + if (is_bounded_by bounds r1) then r3 + else add_to_nth 0 (weight n * nth_default 0 r1 n) (firstn n r1). + + Definition mulmod' base s c n (p q : list Z) := + let prod := mul_no_reduce base n p q in + let red := reduce_full base s c n prod in + red. + + Definition reduce1_cps {T} base s c n m (p : list Z) (f : list Z -> T) := + let bound := (0, 2^machine_wordsize - 1) in + if (is_bounded_by (repeat bound n) p) then + let p_a := Positional.to_associational weight n p in + let r_a := sat_reduce base s c n p_a in + let r_rows := Saturated.Rows.from_associational weight m r_a in + let r_flat := Saturated.Rows.flatten weight m r_rows in + f (fst r_flat) + else + let p_a := Positional.to_associational weight n p in + let r_a := sat_reduce base s c n p_a in + let r_rows := Saturated.Rows.from_associational weight m r_a in + let r_flat := Saturated.Rows.flatten weight m r_rows in + f (add_to_nth 0 (weight (m) * snd r_flat) (fst r_flat)). + + Lemma reduce1_cps_ok {T} base s c n m (f : list Z -> T) : forall p, + reduce1_cps base s c n m p f = f (reduce1 base s c n m p). + Proof using Type. + intros. + cbv [reduce1 reduce1_cps]. + break_match; reflexivity. + Qed. + + Definition reduce3_cps {T} base s c n (p : list Z) (f : list Z -> T) := + let bound := (0, 2^machine_wordsize-1) in + let bounds := (repeat bound n) ++ [(0, 1)] in + let s' := fst (Saturated.Rows.adjust_s weight (S (S n)) s) in + let coef_a := Saturated.Associational.sat_mul_const base [(1, s'/s)] c in + let coef := Associational.eval coef_a in + dlet_nd hi := Z.zselect (nth_default 0 p n) 0 coef in + let lo := Saturated.Rows.flatten weight 1 [ [hi]; [nth_default 0 p 0] ] in + if (is_bounded_by bounds p) then + f ((fst lo) ++ (skipn 1 (firstn n p))) + else + let hi' := coef * (nth_default 0 p n) in + f (add_to_nth 0 hi' (firstn n p)). + + Lemma reduce3_cps_ok {T} base s c n (f : list Z -> T) : forall p, + reduce3_cps base s c n p f = f (reduce3 base s c n p). + Proof. + intros. + cbv [reduce3 reduce3_cps]. + break_match; reflexivity. + Qed. + + Definition reduce_full_cps {T} base s c n (p : list Z) (f : list Z -> T):= + (r1 <- reduce1_cps base s c (2*n) (S n) p; + (let bound := (0, 2^machine_wordsize - 1) in + let bounds := repeat bound n ++ [(0, up_bound-1)] in + r2 <- reduce1_cps base s c (S n) (S n) r1; + (if (is_bounded_by bounds r1) then + reduce3_cps base s c n r2 f + else + f (add_to_nth 0 (weight n * nth_default 0 r1 n) (firstn n r1))))). + + Definition reduce_full' base s c n p := + ltac:(let x := (eval cbv beta delta [reduce_full_cps reduce1_cps reduce3_cps id] in (@reduce_full_cps (list Z) base s c n p id)) in + exact x). + + Lemma reduce_full_cps_ok {T} base s c n (f : list Z -> T) : forall p, + reduce_full_cps base s c n p f = f (reduce_full base s c n p). + Proof using Type. + intros. + cbv [reduce_full reduce_full_cps]. + repeat (rewrite reduce1_cps_ok || + rewrite reduce3_cps_ok || + reflexivity || + break_match). + Qed. + + Definition mul_no_reduce_cps {T} base n (p q : list Z) (f : list Z -> T):= + let p_a := Positional.to_associational weight n p in + let q_a := Positional.to_associational weight n q in + let pq_a := Saturated.Associational.sat_mul base p_a q_a in + let pq_rows := Saturated.Rows.from_associational weight (2*n) pq_a in + let pq := Saturated.Rows.flatten weight (2*n) pq_rows in + let bound := (0, 2^machine_wordsize - 1) in + if (is_bounded_by (repeat bound n) p) then + if (is_bounded_by (repeat bound n) q) then + f (fst pq) + else + f (add_to_nth 0 (weight (2 * n) * snd pq) (fst pq)) + else + f (add_to_nth 0 (weight (2 * n) * snd pq) (fst pq)). + + Lemma mul_no_reduce_cps_ok {T} base n (f : list Z -> T) : forall p q, + mul_no_reduce_cps base n p q f = f (mul_no_reduce base n p q). + Proof using Type. + intros. + cbv [mul_no_reduce mul_no_reduce_cps]. + break_match; reflexivity. + Qed. + + Definition mulmod_cps {T} base s c n (p q : list Z) (f : list Z -> T) := + (mul <- mul_no_reduce_cps base n p q; + reduce_full_cps base s c n mul f). + + Lemma mulmod_cps_ok {T} base s c n (f : list Z -> T) : forall p q, + mulmod_cps base s c n p q f = f (mulmod' base s c n p q). + Proof using Type. + intros. + cbv [mulmod' mulmod_cps]. + rewrite mul_no_reduce_cps_ok, reduce_full_cps_ok. + reflexivity. + Qed. + + Definition mulmod base s c n (p q : list Z) := + ltac:(let x := (eval cbv beta delta [mulmod_cps mul_no_reduce_cps reduce_full_cps reduce1_cps reduce3_cps id] in (@mulmod_cps (list Z) base s c n p q id)) in + exact x). + + Lemma mulmod_unfold base s c n : forall p q, + mulmod' base s c n p q = mulmod_cps base s c n p q id. + Proof using Type. + intros. + rewrite mulmod_cps_ok. + reflexivity. + Qed. + + Lemma mulmod_cps_conv base s c n : forall p q, + mulmod base s c n p q = mulmod' base s c n p q. + Proof using Type. + intros. + rewrite mulmod_unfold. + reflexivity. + Qed. + + Hint Resolve length_partition : push_length. + Hint Resolve Rows.length_from_associational : push_length. + + Lemma split_lt w l1 l2: + (forall x, In x l1 -> 0 < x < w) -> + split w (combine l1 l2) = (combine l1 l2, []). + Proof using Type. + intros H. + generalize dependent l2. + induction l1 as [| ? ? IHl1]; intros l2; destruct l2; push; + match goal with + | [ |- context[ ?x :: ?y ] ] => replace (x :: y) with ([x] ++ y) by auto + end; + specialize (IHl1 ltac:(auto)); + specialize (H _ ltac:(auto)); + repeat multimatch goal with + | |- context[_ mod _] => rewrite Z.mod_small + | _ => rewrite IHl1 + | _ => push + | _ => cbn + | _ => lia + | _ => auto + | _ => break_match + end. + Qed. + + Lemma split_gt w l1 l2: + (forall x, In x l1 -> x mod w = 0) -> + split w (combine l1 l2) = ([], combine (map (fun t => t / w) l1) l2). + Proof using Type. + intros H. + generalize dependent l2. + induction l1 as [| ? ? IHl1]; intros l2; destruct l2; push; + match goal with + | [ |- context[ ?x :: ?y ] ] => replace (x :: y) with ([x] ++ y) by eauto + end; + specialize (IHl1 ltac:(auto)); + specialize (H _ ltac:(auto)); + repeat multimatch goal with + | H : ?x = 0, H1 : (?x =? 0) = false |- _ => rewrite H in H1 + | _ => rewrite IHl1 + | _ => push + | _ => cbn + | _ => lia + | _ => auto + | _ => break_match + | _ => discriminate + end. + Qed. + + Lemma weight_mono' x : + weight x < weight (S x). + Proof using Type. + weight_comp. + rewrite Zred_factor0 at 1. + rewrite Z.mul_comm. + apply Zmult_lt_compat_r. + apply Z.pow_pos_nonneg. + all: lia. + Qed. + + Lemma weight_mono'' x1 x2 : + (x2 > 0)%nat + -> weight x1 < weight (x2 + x1). + Proof using Type. + intros H. + induction H as [| ? ? IHle]; + repeat match goal with + | _ => apply IHle + | _ => apply weight_mono' + | _ => etransitivity + end. + Qed. + + Lemma weight_mono x1 x2 : + (x1 < x2)%nat -> + weight x1 < weight x2. + Proof using Type. + intros. + replace x2%nat with ((x2 - x1) + x1)%nat by lia. + apply weight_mono''; lia. + Qed. + + Lemma weight_mono_le x1 x2 : + (x1 <= x2)%nat -> + weight x1 <= weight x2. + Proof using Type. + intros H. + apply le_lt_or_eq in H. + intuition. + pose proof (weight_mono x1 x2 ltac:(auto)); lia. + subst; lia. + Qed. + + Lemma map_seq_start : forall a b, + map weight (seq a b) = + map (fun t => t * weight a) (map weight (seq 0 b)). + Proof using Type. + intros a b. + induction b as [| ? IHb]; + repeat multimatch goal with + | _ => rewrite IHb + | _ => rewrite seq_snoc + | _ => f_equal + | _ => push + | _ => cbn + end. + weight_comp. + rewrite Nat2Z.inj_add. + rewrite Z.mul_add_distr_l. + rewrite Z.pow_add_r; lia. + Qed. + + Lemma eval_seq_start : forall a b p, + Associational.eval (combine (map weight (seq a b)) p) = + weight a * Associational.eval (combine (map weight (seq 0 b)) p). + Proof using wprops. + intros a b p. + generalize dependent a. + generalize dependent b. + induction p as [ | x p IHp ]; intros. + push. + destruct b. + push. + cbn [seq]. + rewrite <-seq_shift. + push. + rewrite IHp. + lia. + Qed. + + Lemma weight_dif_mono' : forall n, + weight (S n) - weight n < weight (S (S n)) - weight (S n). + Proof using Type. + intros n. + induction n. + weight_comp; lia. + cbv [weight]. + rewrite uweight_S; [ | lia]. + rewrite uweight_S with (n:=n) at 2; [ | lia]. + rewrite uweight_S with (n:=S (S n)); [ | lia]. + fold weight. + rewrite <-!Z.mul_sub_distr_l. + apply Zmult_lt_compat_l; unfold machine_wordsize; lia. + Qed. + + Lemma weight_dif_mono : forall n m, + (n < m)%nat -> + weight (S n) - weight n < weight (S m) - weight m. + Proof using Type. + intros n m H. + induction H; + repeat multimatch goal with + | _ => apply IHle + | _ => apply weight_dif_mono' + | _ => etransitivity + end. + Qed. + + Lemma weight_dif_lt : forall n m a, + (n < m)%nat -> + a < weight (S n) - weight n -> + a < weight (S m) - weight m. + Proof. + intros n m a H H0. + induction H. + etransitivity; [| apply weight_dif_mono']. + auto. + etransitivity; [| apply weight_dif_mono']. + auto. + Qed. + + Section mulmod. + + Context (base : Z) + (s : Z) + (c : list (Z * Z)) + (n : nat). + + Context (n_gt_1 : (n > 1)%nat) + (s_pos : s > 0) + (c_pos : Associational.eval c > 0) + (mod_nz : s - Associational.eval c <> 0) + (base_nz : base <> 0) + (solinas_property : Rows.adjust_s weight (S (S n)) s = (weight n, true)) + (coef_small : weight n / s * Associational.eval c < up_bound). + + (* SECTION MUL_NO_REDUCE *) + + Theorem eval_mul_no_reduce : forall p q, + eval weight (2 * n) (mul_no_reduce base n p q) = + eval weight n p * Positional.eval weight n q. + Proof using base_nz n_gt_1 wprops. + intros p q. + cbv [mul_no_reduce]. + break_match. + (* properly bounded *) + push. + apply Z.mod_small. + repeat match goal with + | H : context[_ && _] |- _ => rewrite andb_true_iff in Heqb + | H : is_bounded_by _ _ = true |- _ => apply eval_is_bounded_by in H + | _ => progress intuition + | _ => solve_ineq + end. + le_lt. + etransitivity. + apply OrdersEx.Z_as_OT.mul_le_mono_nonneg; eauto; rewrite Le.Z.le_sub_1_iff; eauto. + le_lt. + replace (weight (2 * n)) with (weight n * weight n). + solve_ineq. + weight_comp. + rewrite <-OrdersEx.Z_as_OT.pow_mul_r. + f_equal. + lia. + lia. + lia. + + (* not bounded *) + push. + rewrite <-Z_div_mod_eq. + auto. + rewrite Z.gt_lt_iff. + auto. + push. + lia. + push. + + push. + rewrite <-Z_div_mod_eq. + auto. + rewrite Z.gt_lt_iff. + auto. + push. + lia. + push. + Qed. + Hint Rewrite eval_mul_no_reduce : push_eval. + + Theorem length_mul_no_reduce : forall p q, + length (mul_no_reduce base n p q) = (2 * n)%nat. + Proof using base_nz n_gt_1 wprops. + intros; unfold mul_no_reduce; break_match; push. + Qed. + Hint Rewrite length_mul_no_reduce : push_length. + + (* END SECTION MUL_NO_REDUCE *) + + (* SECTION REDUCE1 *) + + Lemma reduce1_length : forall p m1 m2, + length (reduce1 base s c m1 m2 p) = m2. + Proof using wprops. + intros; cbv [reduce1]; break_match; push. + Qed. + Hint Rewrite reduce1_length : push_length. + + Lemma split_p_firstn : forall p, + n <= length p -> + split (weight n) (combine (map weight (seq 0 n)) (firstn n p)) = + (combine (map weight (seq 0 n)) (firstn n p), []). + Proof using wprops. + intros. + rewrite split_lt; + repeat multimatch goal with + | H : _ |- _ => autorewrite with push_misc in H + | H : _ |- _ => rewrite in_seq in H + | _ => rewrite min_l + | H : context[exists _, _] |- _ => destruct H + | H : _ = ?x |- context[?x] => rewrite <-H + | _ => push + | _ => apply weight_mono + | _ => intuition + | _ => auto || lia + end. + Qed. + Hint Rewrite split_p_firstn : push_misc. + + Lemma split_p_skipn : forall p m1, + n <= length p -> + split (weight n) (combine (map weight (seq n (m1 - n))) (skipn n p)) = + ([], combine (map weight (seq 0 (m1 - n))) (skipn n p)). + Proof using wprops. + intros. + rewrite split_gt; + repeat multimatch goal with + | H : _ |- _ => autorewrite with push_misc in H + | H : _ |- _ => rewrite in_seq in H + | _ => apply Weight.weight_multiples_full + | H : context[exists _, _] |- _ => destruct H + | H : _ = ?x |- context[?x] => rewrite <-H + | _ => push + | _ => intuition + end. + Qed. + Hint Rewrite split_p_skipn : push_misc. + + Lemma split_p : forall m1 p, + (m1 >= n)%nat -> + n <= length p -> + split (weight n) (combine (map weight (seq 0 m1)) p) = + (combine (map weight (seq 0 n)) (firstn n p), + (combine (map weight (seq 0 (m1 - n))) (skipn n p))). + Proof using n_gt_1 wprops. + intros m1 p ? ?. + replace m1 with (n + (m1 - n))%nat at 1 by lia. + rewrite <-(firstn_skipn n p) at 1. + push. + push. + lia. + Qed. + Hint Rewrite split_p : push_misc. + + Hint Rewrite repeat_length : push_length. + + Ltac solve_ibb := + apply eval_is_bounded_by; + match goal with + | |- context [firstn _ _] => eapply is_bounded_by_app_l + | |- context [skipn _ _] => eapply is_bounded_by_app_r + end; eauto; push; try lia. + + Lemma value_reduce1 : forall p m1 m2, + (m1 >= n)%nat -> + (m2 > 0)%nat -> + n <= length p -> + up_bound * weight (m1 - n) + weight n < weight m2 -> + let s' := fst (Saturated.Rows.adjust_s weight (S (S n)) s) in + let coef := Associational.sat_mul_const base [(1, s'/s)] c in + eval weight m2 (reduce1 base s c m1 m2 p) = + Associational.eval coef * eval weight (m1 - n) (skipn n p) + eval weight n (firstn n p). + Proof using base_nz c_pos coef_small n_gt_1 s_pos solinas_property wprops. + intros p m1 m2 H. + intros. + assert (Rows.adjust_s weight (S (S m1)) s = + Rows.adjust_s weight (S (S n)) s) as Hadjust. + { destruct H. + auto. + rewrite solinas_property. + eapply adjust_s_finished; try apply solinas_property. + lia. + lia. } + cbv [s' coef reduce1]. + destruct (is_bounded_by (repeat (0, 2 ^ machine_wordsize - 1) m1) p) eqn:Heqb; push. + rewrite Hadjust. + rewrite solinas_property. + cbv [to_associational]. + push. + rewrite <-(firstn_skipn n p) in Heqb. + replace m1 with (n + (m1 - n))%nat in Heqb by lia. + rewrite repeat_app in Heqb. + solve_ineq. + solve_ibb. + solve_ibb. + etransitivity. + solve_ineq. + apply Z.mul_lt_mono_nonneg. + solve_ineq. + eauto. + solve_ibb. + solve_ibb. + solve_ibb. + lia. + + rewrite Hadjust. + rewrite solinas_property. + cbv [to_associational]. + push. + rewrite <-Z_div_mod_eq_full. + reflexivity. + all: push. + Qed. + + Lemma eval_reduce1 : forall p m1 m2, + (m1 >= n)%nat -> + (m2 > 0)%nat -> + n <= length p -> + up_bound * weight (m1 - n) + weight n < weight m2 -> + let q := reduce1 base s c m1 m2 p in + (Positional.eval weight m1 p) mod (s - Associational.eval c) + = (Positional.eval weight m2 q) mod (s - Associational.eval c). + Proof using base_nz c_pos coef_small mod_nz n_gt_1 s_pos solinas_property wprops. + intros p m1 m2; intros. + cbv [q]. + rewrite value_reduce1; try lia. + push. + rewrite solinas_property. + cbn [fst snd]. + match goal with + | |- context[_ mod (_ - ?c)] => + lazymatch goal with + | |- context[?x * ?c * ?y] => replace (x * c * y) with (c * (x * y)) by lia + end + end. + rewrite Z.add_comm. + rewrite <-reduction_rule. + apply Z.elim_mod. + rewrite <-(firstn_skipn n p) at 1. + replace m1 with (n + (m1 - n))%nat by lia. + cbv [eval to_associational]. + push. + rewrite Z.mul_assoc. + rewrite <-Z_div_exact_2. + rewrite Z.add_cancel_l. + cbn. + replace (n + (m1 - n) - n)%nat with (m1 - n)%nat by lia. + rewrite eval_seq_start. + lia. + lia. + pose proof (adjust_s_invariant (S (S n)) s ltac:(lia)) as Hadj. + rewrite solinas_property in Hadj. + intuition. + push. + lia. + lia. + Qed. + + (* END SECTION REDUCE1 *) + + (* SECTION REDUCE3 *) + + Lemma value_reduce1' : forall p m, + m = n -> + length p = S m -> + nth_default 0 p n <= 1 -> + (weight n / s * Associational.eval c) * (nth_default 0 p n) + eval weight n (firstn n p) < weight n -> + let s' := fst (Saturated.Rows.adjust_s weight (S (S n)) s) in + let coef := Associational.sat_mul_const base [(1, s'/s)] c in + eval weight m (reduce1 base s c (S m) m p) = + Associational.eval coef * nth_default 0 p n + eval weight n (firstn n p). + Proof. + intros p m H H1 H2 H3. + cbv [reduce1]. + rewrite H. + push. + erewrite adjust_s_finished'; try apply solinas_property. + rewrite solinas_property. + cbv [to_associational]. + push. + const_simpl. + rewrite skipn_nth_default with (d:=0) by lia. + rewrite skipn_all. + cbn [seq map]. + push. + + break_match. + assert (0 <= nth_default 0 p n). + apply is_bounded_by_nth with (n:=n) in Heqb. + etransitivity. + 2: apply Heqb. + rewrite nth_default_repeat. + break_match; try lia. + reflexivity. + lia. + push. + + push. + rewrite Z.mod_small. + reflexivity. + solve_ineq. + rewrite <-firstn_skipn with (l:=p) (n:=n) in Heqb. + replace (S n) with (n + 1)%nat in Heqb by lia. + rewrite repeat_app in Heqb. + solve_ibb. + auto. + push. + rewrite <-Z_div_mod_eq_full. + all: push; lia. + Qed. + + Lemma eval_reduce1' : forall p m, + m = n -> + length p = S m -> + nth_default 0 p n <= 1 -> + (weight n / s * Associational.eval c) * (nth_default 0 p n) + eval weight n (firstn n p) < weight n -> + let s' := fst (Saturated.Rows.adjust_s weight (S (S n)) s) in + let coef := Associational.sat_mul_const base [(1, s'/s)] c in + let q := reduce1 base s c (S m) m p in + (Positional.eval weight (S m) p) mod (s - Associational.eval c) + = (Positional.eval weight m q) mod (s - Associational.eval c). + Proof using base_nz c_pos coef_small mod_nz n_gt_1 s_pos solinas_property wprops. + intros p m H H1 H2 H3 s' coef q. + cbv [q]. + rewrite value_reduce1'; try lia. + push. + rewrite solinas_property. + cbn [fst snd]. + match goal with + | |- context[_ mod (_ - ?c)] => + lazymatch goal with + | |- context[?x * ?c * ?y] => replace (x * c * y) with (c * (x * y)) by lia + end + end. + rewrite Z.add_comm. + rewrite <-reduction_rule. + apply Z.elim_mod. + rewrite <-(firstn_skipn n p) at 1. + replace (S m) with (m+1)%nat by lia. + cbv [eval to_associational]. + push. + rewrite Z.mul_assoc. + rewrite <-Z_div_exact_2. + rewrite H. + rewrite Z.add_cancel_l. + const_simpl. + rewrite eval_seq_start. + f_equal. + rewrite skipn_nth_default with (d:=0). + rewrite skipn_all. + cbn. + break_match; lia. + + lia. + lia. + lia. + pose proof (adjust_s_invariant (S (S n)) s ltac:(lia)) as Hadj. + rewrite solinas_property in Hadj. + intuition. + push; lia. + lia. + Qed. + + Lemma firstn_nth_default_0 : forall p, + length p > 0 -> + firstn 1 p = [nth_default 0 p 0]. + Proof. + intros p H. + induction p as [| a p IHp]. + push' H. + lia. + push. + Qed. + + Lemma eval_smaller m p : + (length p <= m)%nat -> + eval weight m p = eval weight (length p) p. + Proof. + intros H. + destruct p using rev_ind. + push. + unfold eval at 1. + cbv [to_associational]. + replace m with ((length (p ++ [x])) + (m - length (p ++ [x])))%nat. + rewrite seq_app. + rewrite map_app. + rewrite combine_truncate_l. + rewrite firstn_app_inleft. + rewrite firstn_all. + reflexivity. + push. + push. + lia. + Qed. + + Lemma eval_reduce3 : forall p, + canonical_repr (S n) p -> + (nth_default 0 p (n-1) = 0 /\ nth_default 0 p n = 1 /\ nth_default 0 p 0 < up_bound * up_bound + 1) \/ nth_default 0 p n = 0 -> + let q := reduce3 base s c n p in + (Positional.eval weight (S n) p) mod (s - Associational.eval c) + = (Positional.eval weight n q) mod (s - Associational.eval c). + Proof. + intros. + rewrite eval_reduce1'. + rewrite value_reduce1'. + rewrite solinas_property. + push. + const_simpl. + cbv [q reduce3 Let_In]. + assert (Hcanon := H). + unfold canonical_repr in Hcanon. + destruct Hcanon. + break_match. + + (* bounded *) + pose proof (is_bounded_by_nth 0 _ _ Heqb ltac:(lia)) . + specialize (H3 ltac:(push; try lia)). + rewrite nth_default_app in H3. + destruct (lt_dec 0 (Datatypes.length (repeat (0, 2 ^ machine_wordsize - 1) n))). + rewrite nth_default_repeat in H3. + destruct (dec (0 < n)%nat). + push' H3. + + match goal with + | |- context[fst (Rows.flatten weight 1 [ [?x]; [?y] ])] => + assert (fst (Rows.flatten weight 1 [ [x]; [y] ]) = + [fst (Z.add_get_carry machine_wordsize x y)]) + end. + { cbv [Z.add_get_carry Z.add_with_get_carry Z.add_with_carry Z.get_carry Let_In]. + rewrite solinas_property. + push. + rewrite !Rows.eval_cons. + rewrite Rows.eval_nil. + push. + rewrite Partition.partition_step. + push. + intros. + cbn in H4. + intuition. + rewrite <-H7; push. + rewrite <-H4; push. + rewrite <-H0; push. + rewrite <-H4; push. } + rewrite H4. + + cbv [Z.add_get_carry Z.add_with_get_carry Z.add_with_carry Z.get_carry Let_In Z.zselect]. + rewrite solinas_property. + push. + rewrite <-firstn_skipn with (l:=(firstn n p)) (n:=1%nat) at 1. + rewrite firstn_firstn. + rewrite firstn_nth_default_0. + intuition. + (* nth_default 0 p n = 1 *) + rewrite H3. + break_match; [lia|]. + push. + + f_equal. + rewrite Z.mod_small. + cbv [eval to_associational]. + destruct n eqn:E1. + lia. + cbn [seq map]. + replace (weight 0 :: map weight (seq 1 n0)) with ([weight 0] ++ map weight (seq 1 n0)) by auto. + rewrite !combine_app_samelength. + cbn [combine]. + rewrite !eval_app. + push. + lia. + cbn; lia. + cbn; lia. + solve_ineq. + etransitivity. + apply Z.add_lt_mono. + eauto. + eauto. + cbv [up_bound]; weight_comp; simpl; lia. + + (* nth_default 0 p n = 0 *) + rewrite H3. + break_match; [| lia]. + push. + f_equal. + rewrite Z.mod_small. + lia. + solve_ineq. + lia. + lia. + lia. + intuition. + push' n0. + lia. + push' n0. + lia. + + (* not bounded *) + rewrite solinas_property. + push. + push; lia. + push; lia. + lia. + solve_length p. + lia. + + intuition. + { rewrite H1. + rewrite <-firstn_skipn with (n:=(n-1)%nat) (l:=firstn n p). + rewrite firstn_firstn by lia. + rewrite skipn_nth_default with (d:=0). + rewrite skipn_all. + rewrite nth_default_firstn. + destruct le_dec. + destruct lt_dec; [| lia]. + rewrite H0. + cbv [eval to_associational]. + destruct n eqn:E; [lia|]. + rewrite seq_snoc. + rewrite map_app, combine_app_samelength. + rewrite eval_app. + push. + pose proof (firstn_skipn n0 p). + symmetry in H2. + canonical_app p. + push' Hcanon_l. + rewrite min_l in Hcanon_l by lia. + pose proof (canonical_eval_bounded n0 (firstn n0 p) ltac:(auto)). + etransitivity. + cbv [eval to_associational] in H4. + replace (S n0 - 1)%nat with (n0) by lia. + apply Z.add_lt_le_mono. + eauto. + le_lt; eauto. + cbv [up_bound]. + rewrite Z.add_sub_assoc. + rewrite Z.add_sub_swap. + rewrite Z.lt_add_lt_sub_r. + apply weight_dif_lt with (n:=0%nat). + lia. + weight_comp; simpl; lia. + push. + lia. + push. + intuition. + exfalso. + apply n0. + unfold canonical_repr in H. + lia. + push. + lia. + push. + unfold canonical_repr in H. + lia. } + rewrite H1. + ring_simplify. + pose proof (firstn_skipn n p). + symmetry in H0. + canonical_app p. + push' Hcanon_l. + rewrite min_l in Hcanon_l; [|solve_length p]. + apply canonical_eval_bounded; auto. + lia. + solve_length p. + lia. + intuition. + { rewrite H1. + rewrite <-firstn_skipn with (n:=(n-1)%nat) (l:=firstn n p). + rewrite firstn_firstn by lia. + rewrite skipn_nth_default with (d:=0). + rewrite skipn_all. + rewrite nth_default_firstn. + destruct le_dec. + destruct lt_dec; [| lia]. + rewrite H0. + cbv [eval to_associational]. + destruct n eqn:E; [lia|]. + rewrite seq_snoc. + rewrite map_app, combine_app_samelength. + rewrite eval_app. + push. + pose proof (firstn_skipn n0 p). + symmetry in H2. + canonical_app p. + push' Hcanon_l. + rewrite min_l in Hcanon_l by lia. + pose proof (canonical_eval_bounded n0 (firstn n0 p) ltac:(auto)). + etransitivity. + cbv [eval to_associational] in H4. + replace (S n0 - 1)%nat with (n0) by lia. + apply Z.add_lt_le_mono. + eauto. + le_lt; eauto. + cbv [up_bound]. + rewrite Z.add_sub_assoc. + rewrite Z.add_sub_swap. + rewrite Z.lt_add_lt_sub_r. + apply weight_dif_lt with (n:=0%nat). + lia. + weight_comp; simpl; lia. + push. + lia. + push. + intuition. + exfalso. + apply n0. + unfold canonical_repr in H. + lia. + push. + lia. + push. + unfold canonical_repr in H. + lia. } + rewrite H1. + ring_simplify. + pose proof (firstn_skipn n p). + symmetry in H0. + canonical_app p. + push' Hcanon_l. + rewrite min_l in Hcanon_l; [|solve_length p]. + apply canonical_eval_bounded; auto. + Qed. + + (* END SECTION REDUCE3 *) + + (* SECTION REDUCE_FIRST *) + + Lemma reduce_first_canonical : forall p, + length p = (2 * n)%nat -> + is_bounded_by (repeat (0, 2 ^ machine_wordsize - 1) (2 * n)) p = true-> + canonical_repr (S n) (reduce1 base s c (2*n) (S n) p). + Proof using base_nz c_pos coef_small n_gt_1 s_pos solinas_property wprops. + intros p Hlen H. + cbv [reduce1 canonical_repr]. + rewrite H. + push. + intuition. + erewrite adjust_s_finished; try apply solinas_property; try lia. + push. + f_equal. + rewrite Z.mod_small. + reflexivity. + cbv [to_associational]. + push. + rewrite <-(firstn_skipn n p) in H. + replace (2*n-n)%nat with n by lia. + replace (2 * n)%nat with (n + n)%nat in H by lia. + rewrite repeat_app in H. + solve_ineq. + + solve_ibb. + solve_ibb. + etransitivity. + solve_ineq. + apply Z.mul_lt_mono_nonneg. + solve_ineq. + eauto. + solve_ibb. + solve_ibb. + solve_ibb. + cbv [up_bound machine_wordsize]. + weight_comp. + rewrite <-Z.mul_succ_l. + apply Zmult_lt_compat_r. + apply Z.pow_pos_nonneg; lia. + all: cbn; break_match; lia. + Qed. + + (* END SECTION REDUCE_FIRST *) + + (* SECTION REDUCE_SECOND *) + + Lemma reduce_second_canonical : forall p, + canonical_repr (S n) p -> + canonical_repr (S n) (reduce1 base s c (S n) (S n) p). + Proof using base_nz c_pos coef_small n_gt_1 s_pos solinas_property wprops. + intros p H. + cbv [canonical_repr]. + push. + assert (Hcanon := H). + cbv [canonical_repr] in H. + intuition. + rewrite value_reduce1. + rewrite solinas_property. + push. + cbv [reduce1]. + break_match. + push. + erewrite adjust_s_finished'; try eapply solinas_property. + cbv [to_associational]. + rewrite split_p. + push. + lia. + lia. + lia. + + rewrite canonical_is_bounded_by in Hcanon. + intuition. + match goal with + | H : ?x = true, H1 : ?x = false |- _ => rewrite H in H1; discriminate + end. + lia. + lia. + lia. + replace (S n - n)%nat with 1%nat by lia. + cbv [up_bound machine_wordsize]. + rewrite Z.lt_add_lt_sub_r. + etransitivity; [ | apply weight_dif_mono with (n:=1%nat); lia ]. + weight_comp; cbn; lia. + Qed. + + Lemma up_bound_weight1 : forall m, + (m > 1)%nat -> + up_bound * weight 1 < weight (S m) - weight m. + Proof. + intros m H. + induction H. + cbv [up_bound]. + weight_comp; try lia. + simpl; break_match; lia. + etransitivity. + 2: apply weight_dif_mono'. + auto. + Qed. + + Hint Rewrite nth_default_partition : push_misc. + Lemma reduce_second_bounds : forall p, + canonical_repr (S n) p -> + (nth_default 0 p n) < up_bound -> + let q := reduce1 base s c (S n) (S n) p in + (nth_default 0 q (n-1) = 0 /\ nth_default 0 q n = 1 /\ nth_default 0 q 0 < up_bound * up_bound + 1) \/ + nth_default 0 q n = 0. + Proof using base_nz c_pos coef_small n_gt_1 s_pos solinas_property wprops. + intros p ? ? q. + pose proof (reduce_second_canonical p ltac:(auto)) as Hcanonq. + fold q in Hcanonq. + pose proof (firstn_skipn n p) as Hp; symmetry in Hp. + pose proof (firstn_skipn n q) as Hq; symmetry in Hq. + canonical_app p. + push' Hcanon_l. + push' Hcanon_r. + canonical_app q; push' Hcanon_l0; push' Hcanon_r0. + replace (length p) with (S n) in * by (solve_length p). + replace (length q) with (S n) in * by (solve_length q). + rewrite min_l in *; [| lia | solve_length q]. + const_simpl. + + assert (0 <= nth_default 0 q n < 2). + assert (Hcanonq' := Hcanonq). + cbv [canonical_repr] in Hcanonq'. + destruct Hcanonq as [ _ Hpartq ]. + rewrite Hpartq. + push. + solve_ineq; auto. + rewrite Z.mod_small. + cbv [q]. + rewrite value_reduce1. + const_simpl. + rewrite solinas_property. + push. + rewrite <-Zplus_diag_eq_mult_2. + solve_ineq. + etransitivity. + apply Z.mul_lt_mono_nonneg. + solve_ineq. + eauto. + apply canonical_pos; auto. + rewrite skipn_nth_default with (d:=0). + rewrite skipn_all. + push; eauto. + solve_length p. + solve_length p. + cbv [up_bound machine_wordsize]. + weight_comp. + rewrite <-OrdersEx.Z_as_OT.pow_mul_r. + apply Z.pow_lt_mono_r; cbn; break_match; lia. + cbn; lia. + lia. + apply canonical_eval_bounded; auto. + lia. + lia. + solve_length p. + const_simpl. + cbv [up_bound machine_wordsize]. + rewrite Z.lt_add_lt_sub_r. + etransitivity; [ | apply weight_dif_mono with (n:=1%nat); lia ]. + weight_comp; cbn; lia. + solve_ineq; [apply canonical_pos | apply canonical_eval_bounded]; auto. + + assert (Hnth : nth_default 0 q n = 0 \/ nth_default 0 q n = 1) by lia. + destruct Hnth as [Hnth1 | Hnth2]. + intuition. + left. + + intuition. + assert (Hcanonq' := Hcanonq). + destruct Hcanonq' as [_ Hpart]. + rewrite Hpart. + push. + assert (H' : Associational.eval (combine (map weight (seq 0 n)) (firstn n q)) = eval weight (S n) q - weight n). + rewrite Hq at 2. + cbv [eval to_associational]. + rewrite seq_snoc. + push. + rewrite skipn_nth_default with (d:=0). + rewrite skipn_all. + const_simpl. + cbn [seq]. + push. + lia. + solve_length q. + solve_length q. + push. + rewrite min_l; [lia | solve_length q]. + rewrite <-Z.add_move_l in H'. + rewrite <-H'. + const_simpl. + rewrite Zplus_mod, Z.mod_same, Z.add_0_l, Z.mod_mod. + rewrite Z.add_move_l in H'. + apply Z.div_small. + rewrite Z.mod_small. + solve_ineq. + apply canonical_pos; auto. + rewrite H'. + rewrite Z.lt_sub_lt_add_l. + cbv [q]. + rewrite value_reduce1. + rewrite solinas_property. + push. + const_simpl. + rewrite Z.add_comm. + solve_ineq. + apply canonical_eval_bounded; auto. + rewrite skipn_nth_default with (d:=0). + rewrite skipn_all. + push. + etransitivity. + apply Z.mul_lt_mono_nonneg. + solve_ineq. + eauto. + apply (canonical_bounded (S n) p). + auto. + rewrite Hp at 2. + apply in_or_app. + right. + rewrite skipn_nth_default with (d:=0). + rewrite skipn_all. + push. + solve_length p. + solve_length p. + eauto. + cbv [up_bound machine_wordsize]. + rewrite <-Le.Z.le_sub_1_iff. + etransitivity; [| rewrite <-Z.sub_le_mono_r; apply (weight_mono_le 1)]. + weight_comp; cbn; lia. + lia. + solve_length p. + solve_length p. + lia. + lia. + solve_length p. + const_simpl. + cbv [up_bound machine_wordsize]. + rewrite Z.lt_add_lt_sub_r. + etransitivity; [| apply (weight_dif_mono 1)]. + weight_comp; cbn; lia. + lia. + solve_ineq. + apply canonical_pos; auto. + apply canonical_eval_bounded; auto. + auto. + auto. + lia. + + assert (Hcanonq' := Hcanonq). + destruct Hcanonq as [ _ Hpartq]. + rewrite Hpartq. + rewrite nth_default_partition. + rewrite weight_0. + rewrite Z.div_1_r. + assert (eval weight (S n) q = eval weight n (firstn n q) + weight n). + { rewrite Hq at 1. + rewrite skipn_nth_default with (d:=0). + rewrite skipn_all. + rewrite eval_snoc_S. + lia. + push. + rewrite min_l. + lia. + solve_length q. + solve_length q. + solve_length q. } + assert (eval weight (S n) q = weight n / s * Associational.eval c * nth_default 0 p n + eval weight n (firstn n p)). + { unfold q at 1. + rewrite value_reduce1. + rewrite solinas_property. + push. + const_simpl. + unfold eval at 1. + unfold to_associational at 1. + rewrite skipn_nth_default with (d:=0). + rewrite skipn_all. + cbn [seq map combine]. + push. + solve_length p. + solve_length p. + lia. + lia. + solve_length p. + const_simpl. + rewrite Z.lt_add_lt_sub_r. + apply up_bound_weight1; lia. } + rewrite H1 in H4. + apply LinearSubstitute.Z.move_R_pX in H4. + rewrite H1. + rewrite PullPush.Z.add_mod_r. + rewrite Weight.weight_multiples_full. + const_simpl. + rewrite Z.mod_small. + rewrite H4. + etransitivity. + apply Z.add_lt_mono_r. + apply Z.add_lt_mono. + apply Z.mul_lt_mono_nonneg. + solve_ineq. + eauto. + eapply canonical_bounded with (n:=S n) (p:=p). + auto. + rewrite Hp. + rewrite nth_default_app. + break_match. + push' H5. + rewrite min_l in H5. + lia. + lia. + push. + rewrite min_l. + rewrite Nat.sub_diag. + rewrite skipn_nth_default with (d:=0). + rewrite skipn_all. + apply in_or_app. + right. + push. + solve_length p. + solve_length p. + solve_length p. + eauto. + apply canonical_eval_bounded. + eauto. + lia. + solve_ineq. + apply canonical_pos; auto. + rewrite H4. + etransitivity. + apply Z.add_lt_mono_r. + apply Z.add_lt_mono. + apply Z.mul_lt_mono_nonneg. + solve_ineq. + eauto. + eapply canonical_bounded with (n:=S n) (p:=p). + auto. + rewrite Hp. + rewrite nth_default_app. + break_match. + push' H5. + rewrite min_l in H5. + lia. + lia. + push. + rewrite min_l. + rewrite Nat.sub_diag. + rewrite skipn_nth_default with (d:=0). + rewrite skipn_all. + apply in_or_app. + right. + push. + solve_length p. + solve_length p. + solve_length p. + eauto. + apply canonical_eval_bounded. + eauto. + rewrite <-Z.add_assoc. + rewrite Z.add_opp_diag_r. + const_simpl. + cbv [up_bound]. + weight_comp. + simpl; break_match; lia. + lia. + lia. + auto. + auto. + lia. + auto. + lia. + Qed. + + (* END SECTION REDUCE_SECOND *) + + (* (* SECTION REDUCE_THIRD *) *) + + (* Lemma eval_reduce_third' : forall p, *) + (* (canonical_repr (S n) p) -> *) + (* let q := reduce3 base s c n p in *) + (* ((nth_default 0 p (n-1) = 0 /\ nth_default 0 q n = 1 /\ nth_default 0 q 0 < up_bound * up_bound + 1) \/ nth_default 0 q n = 0) -> *) + (* (Positional.eval weight (S n) p) mod (s - Associational.eval c) *) + (* = (Positional.eval weight n q) mod (s - Associational.eval c). *) + (* Proof. *) + (* intros p ? q ?. *) + (* cbv [q]. *) + (* rewrite eval_reduce3. *) + (* lia. *) + (* lia. *) + (* solve_length p. *) + (* Qed. *) + + (* (* END SECTION REDUCE_THIRD *) *) + + (* SECTION REDUCE_FULL] *) + Theorem reduce_full_correct : forall (p : list Z), + n <= length p -> + let r := reduce_full base s c n p in + (Positional.eval weight (2 * n) p) mod (s - Associational.eval c) + = (Positional.eval weight n r) mod (s - Associational.eval c). + Proof. + intros p ? r; cbv [r reduce_full]; break_match. + pose proof (is_bounded_by_nth n _ _ Heqb ltac:(push) ltac:(push)) as Hnth. + repeat match goal with + | H : context[nth_default _ (_ ++ _) _] |- _ => rewrite nth_default_app in H + | H : context[snd (nth_default _ _ _)] |- _ => progress cbn in H + | H : _ |- _ => progress push' H + | _ => progress destruct lt_dec + | _ => progress intuition + | _ => lia + end. + apply is_bounded_by_loosen with (bound2:=repeat (0, 2^machine_wordsize-1) (S n)) in Heqb. + assert (canonical_repr (S n) (reduce1 base s c (2*n) (S n) p)). + rewrite canonical_is_bounded_by. + intuition; push. + rewrite <-eval_reduce3. + rewrite <-eval_reduce1. + rewrite <-eval_reduce1. + auto. + pose proof (firstn_skipn n p) as Hp; symmetry in Hp. + + all: + repeat multimatch goal with + | _ => apply reduce_second_canonical + | _ => apply reduce_second_bounds + | _ => solve_length p + | _ => const_simpl + | _ => cbv [up_bound] + | _ => push + | _ => auto + | _ => lia + end. + weight_comp; try lia. + rewrite <-Z.mul_succ_l. + apply Zmult_lt_compat_r. + apply Z.pow_pos_nonneg; cbn; break_match; lia. + cbn; lia. + rewrite Z.lt_add_lt_sub_r. + etransitivity; [| apply (weight_dif_mono 1); lia]. + weight_comp; cbn; break_match; lia. + autounfold. + replace (S n) with (n+1)%nat. + cbn. + const_simpl. + replace (n+1)%nat with (S n) by lia. + lia. + lia. + cbv [fold_andb_map' dual_map]. + cbn [repeat]. + rewrite repeat_cons. + rewrite combine_app_samelength. + rewrite map_app. + rewrite fold_right_app. + cbn. + pose proof (bounds_same (repeat (0, 18446744073709551615) n)). + auto. + auto. + + (* not canonical *) + rewrite eval_reduce1 with (m2:=S n). + rewrite <-(firstn_skipn n (reduce1 base s c (2 * n) (S n) p)) at 1. + unfold eval at 1. + unfold to_associational. + rewrite seq_snoc. + rewrite skipn_nth_default with (d:=0). + rewrite skipn_all. + push. + apply Z.elim_mod. + const_simpl. + rewrite Z.add_comm at 1. + auto. + all: + repeat multimatch goal with + | _ => push + | _ => lia + end. + const_simpl. + cbv [up_bound]. + weight_comp; try lia. + rewrite <-Z.mul_succ_l. + apply Zmult_lt_compat_r. + apply Z.pow_pos_nonneg; cbn; break_match; lia. + cbn; lia. + Qed. + + (* END SECTION REDUCE_FULL *) + + (* SECTION MULMOD *) + Theorem mulmod'_correct : forall p q, + Positional.eval weight n (mulmod' base s c n p q) mod (s - Associational.eval c) = + (Positional.eval weight n p * Positional.eval weight n q) mod (s - Associational.eval c). + Proof using base_nz c_pos coef_small mod_nz n_gt_1 s_pos solinas_property wprops. + intros. + cbv [mulmod']. + rewrite <-reduce_full_correct; push; lia. + Qed. + + Theorem mulmod_correct : forall p q, + Positional.eval weight n (mulmod base s c n p q) mod (s - Associational.eval c) = + (Positional.eval weight n p * Positional.eval weight n q) mod (s - Associational.eval c). + Proof using base_nz c_pos coef_small mod_nz n_gt_1 s_pos solinas_property wprops. + intros. + rewrite mulmod_cps_conv. + apply mulmod'_correct. + Qed. + (* END SECTION MULMOD *) + + End mulmod. + + Section squaremod. + + Definition sqr_indiv' base (state : list (Z * Z)) (p : list (Z * Z)) := + fold_right (fun a b => b ++ Associational.sat_mul base [a] [a]) state p. + + Definition sqr_indiv base (p : list (Z * Z)) := + sqr_indiv' base [] p. + + Definition square1 base (p : list (Z * Z)) := + let prod0 := Saturated.Associational.sat_mul base (firstn 1 p) (skipn 1 p) in + let prod1 := Saturated.Associational.sat_mul base (skipn 3 p) (firstn 2 (skipn 1 p)) in + let carry1_a := prod0 ++ prod1 in + let carry1_rows := Saturated.Rows.from_associational weight 7 carry1_a in + let carry1 := Saturated.Rows.flatten weight 7 carry1_rows in + let prod2 := Saturated.Associational.sat_mul base (firstn 1 (skipn 1 p)) (firstn 1 (skipn 2 p)) in + let carry2_rows := Saturated.Rows.from_associational weight 7 prod2 in + let carry2 := Saturated.Rows.flatten' weight carry1 carry2_rows in + let carry2 := (fst carry2) ++ [snd carry2] in + carry2. + + Definition square_no_reduce base n (p : list Z) := + let p_a := Positional.to_associational weight 4 p in + let carry2 := square1 base p_a in + let double := Saturated.Rows.flatten weight 8 [carry2; carry2] in + let square_a := sqr_indiv base p_a in + let square_rows := Saturated.Rows.from_associational weight 8 square_a in + let square := Saturated.Rows.flatten' weight double square_rows in + let bound := (0, 2^machine_wordsize-1) in + if ((n =? 4)%nat) then + if ((length p =? 4)%nat) then + if (is_bounded_by (repeat bound 4) p) then + fst square + else + mul_no_reduce base n p p + else + mul_no_reduce base n p p + else + mul_no_reduce base n p p. + + Definition square_no_reduce_cps {T} base n (p : list Z) (f : list Z -> T) := + let p_a := Positional.to_associational weight 4 p in + let carry2 := square1 base p_a in + let double := Saturated.Rows.flatten weight 8 [carry2; carry2] in + let square_a := sqr_indiv base p_a in + let square_rows := Saturated.Rows.from_associational weight 8 square_a in + let square := Saturated.Rows.flatten' weight double square_rows in + let bound := (0, 2^machine_wordsize-1) in + if ((n =? 4)%nat) then + if ((length p =? 4)%nat) then + if (is_bounded_by (repeat bound 4) p) then + f (fst square) + else + mul_no_reduce_cps base n p p f + else + mul_no_reduce_cps base n p p f + else + mul_no_reduce_cps base n p p f. + + Definition squaremod' base s c n (p : list Z) := + let sqr := square_no_reduce base n p in + let r := reduce_full base s c n sqr in + r. + + Definition squaremod_cps {T} base s c n (p : list Z) (f : list Z -> T) := + (sqr <- square_no_reduce_cps base n p; + reduce_full_cps base s c n sqr f). + + Definition squaremod base s c n (p : list Z) := + ltac:(let x := (eval cbv beta delta [squaremod_cps square_no_reduce_cps mul_no_reduce_cps reduce_full_cps reduce1_cps reduce3_cps id] in (@squaremod_cps (list Z) base s c n p id)) in + exact x). + + Context (base : Z) + (s : Z) + (c : list (Z * Z)) + (n : nat). + + Context (n_gt_1 : (n > 1)%nat) + (s_pos : s > 0) + (c_pos : Associational.eval c > 0) + (mod_nz : s - Associational.eval c <> 0) + (base_nz : base <> 0) + (solinas_property : Rows.adjust_s weight (S (S n)) s = (weight n, true)) + (coef_small : weight n / s * Associational.eval c < up_bound). + + Lemma square_no_reduce_cps_ok {T} (f : list Z -> T) : forall p, + square_no_reduce_cps base n p f = f (square_no_reduce base n p). + Proof. + intros. + cbv [square_no_reduce square_no_reduce_cps]. + break_match. + reflexivity. + apply mul_no_reduce_cps_ok. + apply mul_no_reduce_cps_ok. + apply mul_no_reduce_cps_ok. + Qed. + + Lemma squaremod_cps_ok : forall {T} p (f : list Z -> T), + squaremod_cps base s c n p f = f (squaremod' base s c n p). + Proof. + intros. + cbv [squaremod' squaremod_cps]. + rewrite square_no_reduce_cps_ok, reduce_full_cps_ok. + reflexivity. + Qed. + + Lemma squaremod_unfold : forall p, + squaremod' base s c n p = squaremod_cps base s c n p id. + Proof. + intros. + rewrite squaremod_cps_ok. + reflexivity. + Qed. + + Lemma squaremod_cps_conv : forall p, + squaremod base s c n p = squaremod' base s c n p. + Proof. + intros. + rewrite squaremod_unfold. + reflexivity. + Qed. + + Lemma sat_mul_comm (p q : list (Z * Z)) : + Associational.eval (Associational.sat_mul base p q) = + Associational.eval (Associational.sat_mul base q p). + Proof using base_nz n_gt_1. push; lia. Qed. + + Lemma sat_mul_distr (p q1 q2 : list (Z * Z)) : + Associational.eval (Associational.sat_mul base p (q1 ++ q2)) = + Associational.eval (Associational.sat_mul base p q1) + + Associational.eval (Associational.sat_mul base p q2). + Proof using base_nz n_gt_1. push; lia. Qed. + + Lemma cons_to_app {A} a (p : list A) : + a :: p = [a] ++ p. + Proof. reflexivity. Qed. + + Lemma flatten'_mod state (inp : list (list Z)) (m : nat) : + inp <> [] -> + Datatypes.length (fst state) = m -> + (forall row : list Z, In row inp -> Datatypes.length row = m) -> + eval weight m (fst (Rows.flatten' weight state inp)) = + (Rows.eval weight m inp + eval weight m (fst state) + weight m * snd state) mod weight m. + Proof using n_gt_1 wprops. + intros. + rewrite Rows.flatten'_correct with (n:=m) by auto. + push. + f_equal. + lia. + Qed. + + Hint Rewrite Nat.sub_diag : const_simpl. + Hint Rewrite Z.sub_diag : const_simpl. + + Lemma sum_one x : + sum [x] = x. + Proof. cbn; lia. Qed. + + Lemma square_indiv_cons (p : list (Z * Z)) (a : Z * Z) : + Associational.eval (sqr_indiv base (a :: p)) = + Associational.eval (sqr_indiv base [a]) + + Associational.eval (sqr_indiv base p). + Proof using base_nz n_gt_1. + cbv [sqr_indiv sqr_indiv']. + cbn [fold_right]. + push. + lia. + Qed. + + Lemma square_indiv_app (p q : list (Z * Z)) : + Associational.eval (sqr_indiv base (p ++ q)) = + Associational.eval (sqr_indiv base p) + Associational.eval (sqr_indiv base q). + Proof using base_nz n_gt_1. + generalize dependent q. + induction p as [| a p IHp] using rev_ind; intros q. + push. + rewrite <-app_assoc. + rewrite !IHp. + rewrite <-cons_to_app. + rewrite square_indiv_cons. + lia. + Qed. + + Lemma eval_square_indiv (p : list Z) : forall x x0 x1 x2 q, + p = x :: x0 :: x1 :: x2 :: q -> + Associational.eval (sqr_indiv base (to_associational weight 4 p)) = (Associational.eval (sat_mul base [(weight 0, x)] [(weight 0, x)]) + + (Associational.eval (sat_mul base [(weight 1, x0)] [(weight 1, x0)]) + + (Associational.eval (sat_mul base [(weight 2, x1)] [(weight 2, x1)]) + + Associational.eval (sat_mul base [(weight 3, x2)] [(weight 3, x2)])))). + Proof using base_nz wprops n_gt_1. + intros x x0 x1 x2 q H. + rewrite H. + cbv [to_associational]. + cbn [seq map weight combine]. + repeat multimatch goal with + | |- _ => rewrite app_comm_cons + | |- context[?x :: ?y :: ?z] => + rewrite cons_to_app with (a:=x) (p:=y::z) + | |- context[?x ++ ?y :: ?z] => + rewrite cons_to_app with (a:=y) (p:=z); + rewrite app_nil_r + end. + rewrite !square_indiv_app. + cbv [sqr_indiv sqr_indiv']. + cbn [fold_right]. + push. + Qed. + + Lemma length_square1 (p : list Z) : forall x x0 x1 x2 q, + p = x :: x0 :: x1 :: x2 :: q -> + length (square1 base (to_associational weight 4 p)) = 8%nat. + Proof using base_nz wprops n_gt_1. + intros x x0 x1 x2 q H. + cbv [square1]. + push. + rewrite Rows.flatten'_correct with (n:=7%nat). + push. + auto. + push. + intros. + eapply Rows.length_from_associational. + eauto. + apply Rows.from_associational_nonnil. + lia. + rewrite H. + discriminate. + Qed. + + Lemma eval_square1 (p : list Z) : forall x x0 x1 x2 q, + let bound := (0, 2^machine_wordsize-1) in + is_bounded_by (repeat bound 4) p = true -> + p = x :: x0 :: x1 :: x2 :: q -> + eval weight 8 (square1 base (Positional.to_associational weight 4 p)) = + Associational.eval (sat_mul base [(weight 1, x0)] [(weight 2, x1)]) + + (Associational.eval (sat_mul base [(weight 0, x)] [(weight 1, x0)]) + + (Associational.eval (sat_mul base [(weight 0, x)] [(weight 2, x1)]) + + Associational.eval (sat_mul base [(weight 0, x)] [(weight 3, x2)])) + + (Associational.eval (sat_mul base [(weight 3, x2)] [(weight 1, x0)]) + + Associational.eval (sat_mul base [(weight 3, x2)] [(weight 2, x1)]))). + Proof using base_nz wprops n_gt_1. + intros x x0 x1 x2 q bound H H1. + rewrite H1. + cbv [to_associational]. + cbn [seq map combine]. + cbv [square1]. + cbn [firstn skipn]. + + rewrite H1 in H. + cbv [is_bounded_by fold_andb_map' dual_map bound] in H. + cbn [repeat combine map fold_right fst snd] in H. + repeat match goal with + | H : _ && _ = true |- _ => apply andb_prop in H + | H : _ /\ _ |- _ => destruct H + | H : _ <=? _ = true |- _ => rewrite Z.leb_le in H + end. + + repeat multimatch goal with + | |- _ => rewrite app_comm_cons + | |- context[?x :: ?y :: ?z] => + rewrite cons_to_app with (a:=x) (p:=y::z) by discriminate + end. + repeat multimatch goal with + | _ => rewrite eval_snoc_S + | _ => rewrite Rows.flatten_mod + | _ => rewrite flatten'_mod + | _ => rewrite Rows.flatten'_correct with (n:=7%nat); cbn [snd] + | _ => rewrite Rows.flatten_correct; cbn [snd] + | _ => rewrite Rows.eval_from_associational + | _ => rewrite eval_app + | _ => rewrite sat_mul_distr + | _ => cbn [fst] + end. + all: repeat match goal with + | _ => assumption + | _ => lia + | |- Rows.from_associational _ _ _ <> [] => + apply Rows.from_associational_nonnil + | |- context[length (Partition.partition _ _ _)] => + autorewrite with push_length + | |- forall _ : _, In _ _ -> _ => + intros; eapply Rows.length_from_associational; eassumption + | _ => discriminate + end. + + repeat rewrite Z.div_small. + all: repeat match goal with + | |- context[_ mod _] => rewrite Z.mod_small + end. + all: const_simpl; try lia. + all: push; solve_ineq; le_lt; replace x with (weight 0 * x) by (weight_comp; lia); etransitivity; [ + repeat match goal with + | |- _ + _ <= _ => apply OrdersEx.Z_as_DT.add_le_mono + | |- _ * _ * _ <= _ => apply Z.mul_le_mono_nonneg + | |- _ * _ <= _ => apply OrdersEx.Z_as_DT.mul_le_mono_nonneg_l + | |- 0 <= _ => solve_ineq + | H : ?x <= _ |- ?x <= _ => eassumption + end | (weight_comp; lia) ]. + Qed. + + Lemma eval_square1_bounded (p : list Z) : forall x x0 x1 x2 q, + let bound := (0, 2^machine_wordsize-1) in + is_bounded_by (repeat bound 4) p = true -> + p = x :: x0 :: x1 :: x2 :: q -> + 0 <= eval weight 8 (square1 base (to_associational weight 4 p)) < weight 7. + Proof using base_nz wprops n_gt_1. + intros x x0 x1 x2 q bound H H0. + erewrite eval_square1; [| eauto | eauto]. + rewrite H0 in H. + cbv [is_bounded_by fold_andb_map' dual_map bound] in H. + cbn [repeat combine map fold_right fst snd] in H. + repeat match goal with + | H : _ && _ = true |- _ => apply andb_prop in H + | H : _ /\ _ |- _ => destruct H + | H : _ <=? _ = true |- _ => rewrite Z.leb_le in H + end. + push; solve_ineq; le_lt; replace x with (weight 0 * x) by (weight_comp; lia); etransitivity; + [repeat match goal with + | |- _ + _ <= _ => apply OrdersEx.Z_as_DT.add_le_mono + | |- _ * _ * _ <= _ => apply Z.mul_le_mono_nonneg + | |- _ * _ <= _ => apply OrdersEx.Z_as_DT.mul_le_mono_nonneg_l + | |- 0 <= _ => solve_ineq + | H : ?x <= _ |- ?x <= _ => eassumption + end | (weight_comp; lia) ]. + Qed. + + Theorem eval_square_no_reduce (p : list Z) : + eval weight (2 * n) (square_no_reduce base n p) = (eval weight n p) * (eval weight n p). + Proof using base_nz wprops n_gt_1. + rewrite <-eval_mul_no_reduce with (base:=base) by lia. + cbv [square_no_reduce]. + break_match. + + rewrite Nat.eqb_eq in Heqb. + rewrite Heqb. + assert (exists p1 p2 p3 p4, p = p1 :: p2 :: p3 :: p4 :: nil). + { repeat (destruct p; [cbn in Heqb0; lia|]). + destruct p; [| cbn in Heqb0; lia]. + eauto. } + destruct H; destruct H; destruct H; destruct H. + + pose proof (eval_square1_bounded p x x0 x1 x2 nil ltac:(auto) ltac:(auto)). + + rewrite flatten'_mod. + rewrite Rows.flatten_mod. + rewrite Rows.eval_from_associational. + + rewrite Zplus_mod. + rewrite PullPush.Z.mul_mod_full. + rewrite Z.mod_same. + const_simpl. + rewrite Zmod_mod. + rewrite Zplus_mod. + rewrite Zmod_mod. + rewrite <-Zplus_mod. + + rewrite Rows.eval_cons. + cbv [Rows.eval map]. + rewrite sum_one. + erewrite eval_square1; try eapply H. + erewrite eval_square_indiv; try eapply H. + + rewrite H. + cbv [mul_no_reduce]. + break_match. + replace (2*4)%nat with 8%nat by lia. + cbv [to_associational]. + rewrite combine_firstn_l. + cbn [seq map length]. + cbn [firstn seq map combine]. + repeat multimatch goal with + | |- _ => rewrite app_comm_cons + | |- context[?x :: ?y :: ?z] => + rewrite cons_to_app with (a:=x) (p:=y::z) + end. + rewrite Rows.flatten_mod. + rewrite Rows.eval_from_associational. + rewrite !sat_mul_distr. + repeat multimatch goal with + | |- context[sat_mul _ (?y ++ ?z) ?x] => rewrite sat_mul_comm with (p:=(y ++ z)) (q:=x) + end. + rewrite !sat_mul_distr. + push. + f_equal. + lia. + auto. + lia. + auto. + + all: repeat match goal with + | |- forall _ : _, In _ _ -> _ => + intros; eapply Rows.length_from_associational; eassumption + | _ => auto + end. + rewrite H in Heqb1. + rewrite Heqb1 in Heqb2. + lia. + repeat match goal with + | H : In _ (_ :: _) |- _ => + apply in_inv in H + | H : In _ [] |- _ => apply in_nil in H; lia + | H : _ = ?x |- length ?x = _ => rewrite <-H + | _ => eapply length_square1; eauto + | _ => intuition + end. + apply Rows.from_associational_nonnil. + lia. + rewrite H. + discriminate. + push. + repeat match goal with + | H : In _ (_ :: _) |- _ => + apply in_inv in H + | H : In _ [] |- _ => apply in_nil in H; lia + | H : _ = ?x |- length ?x = _ => rewrite <-H + | _ => eapply length_square1; eauto + | _ => intuition + end. + Qed. + + Theorem length_square_no_reduce (p : list Z): + length (square_no_reduce base n p) = (2 * n)%nat. + Proof using base_nz wprops n_gt_1. + cbv [square_no_reduce]. + break_match. + rewrite Nat.eqb_eq in Heqb. + assert (exists p1 p2 p3 p4, p = p1 :: p2 :: p3 :: p4 :: nil). + { repeat (destruct p; [cbn in Heqb0; lia|]). + destruct p; [| cbn in Heqb0; lia]. + eauto. } + destruct H; destruct H; destruct H; destruct H. + rewrite Rows.flatten'_correct with (n:=8%nat). + push. + lia. + repeat match goal with + | H : In _ (_ :: _) |- _ => + apply in_inv in H + | H : In _ [] |- _ => apply in_nil in H; lia + | H : _ = ?x |- length ?x = _ => rewrite <-H + | _ => eapply length_square1; eauto + | _ => intuition + end. + auto. + push. + repeat match goal with + | H : In _ (_ :: _) |- _ => + apply in_inv in H + | H : In _ [] |- _ => apply in_nil in H; lia + | H : _ = ?x |- length ?x = _ => rewrite <-H + | _ => eapply length_square1; eauto + | _ => intuition + end. + intros; eapply Rows.length_from_associational; eauto. + apply Rows.from_associational_nonnil. + lia. + rewrite H. + discriminate. + apply length_mul_no_reduce; auto. + apply length_mul_no_reduce; auto. + apply length_mul_no_reduce; auto. + Qed. + + Lemma squaremod'_correct : forall p, + Positional.eval weight n (squaremod' base s c n p) mod (s - Associational.eval c) = + (Positional.eval weight n p * Positional.eval weight n p) mod (s - Associational.eval c). + Proof using base_nz c_pos coef_small mod_nz n_gt_1 s_pos solinas_property wprops. + intros. + cbv [squaremod']. + rewrite <-reduce_full_correct. + rewrite eval_square_no_reduce. + all: try lia. + assumption. + rewrite length_square_no_reduce. + lia. + Qed. + + Theorem squaremod_correct : forall p , + Positional.eval weight n (squaremod base s c n p) mod (s - Associational.eval c) = + (Positional.eval weight n p * Positional.eval weight n p) mod (s - Associational.eval c). + Proof using base_nz c_pos coef_small mod_nz n_gt_1 s_pos solinas_property wprops. + intros. + rewrite squaremod_cps_conv. + apply squaremod'_correct. + Qed. + + End squaremod. + + End __. + +End SolinasReduction. diff --git a/src/Assembly/Symbolic.v b/src/Assembly/Symbolic.v index 0bd56d6687..69517a9cb7 100644 --- a/src/Assembly/Symbolic.v +++ b/src/Assembly/Symbolic.v @@ -3659,8 +3659,10 @@ Definition SymexNormalInstruction {descr:description} (instr : NormalInstruction SetOperand a vb | cmovc, [dst; src] | cmovb, [dst; src] + | cmovo, [dst; src] => - v <- Symeval (selectznz@(CF, dst, src)); + let flag := match instr.(Syntax.op) with cmovo => OF | _ => CF end in + v <- Symeval (selectznz@(flag, dst, src)); SetOperand dst v | cmovnz, [dst; src] => v <- Symeval (selectznz@(ZF, src, dst)); diff --git a/src/Assembly/WithBedrock/SymbolicProofs.v b/src/Assembly/WithBedrock/SymbolicProofs.v index 941f0312c7..7f467dd4a3 100644 --- a/src/Assembly/WithBedrock/SymbolicProofs.v +++ b/src/Assembly/WithBedrock/SymbolicProofs.v @@ -1267,7 +1267,7 @@ Proof using Type. Unshelve. all : match goal with H : context[Syntax.cmovc] |- _ => idtac | H : context[Syntax.cmovb] |- _ => idtac | H : context[Syntax.cmovo] |- _=> idtac | _ => shelve end. (* cmovc / cmovb / cmovo *) - all: destruct vCF; cbn [negb Z.b2z Z.eqb] in *; eauto 9; []. + all: (destruct vCF||destruct vOF); cbn [negb Z.b2z Z.eqb] in *; eauto 9; []. all: enough (m = m0) by (subst; eauto 9). all: clear -Hm0 Hv frame G ; eauto using SetOperand_same. all: fail. diff --git a/src/Bedrock/Standalone/StandaloneHaskellMain.v b/src/Bedrock/Standalone/StandaloneHaskellMain.v index c37260bf22..778459df42 100644 --- a/src/Bedrock/Standalone/StandaloneHaskellMain.v +++ b/src/Bedrock/Standalone/StandaloneHaskellMain.v @@ -29,6 +29,11 @@ Module Bedrock2First. := main_gen ForExtraction.SaturatedSolinas.PipelineMain. End SaturatedSolinas. + Module SolinasReduction. + Definition main : IO_unit + := main_gen ForExtraction.SolinasReduction.PipelineMain. + End SolinasReduction. + Module BaseConversion. Definition main : IO_unit := main_gen ForExtraction.BaseConversion.PipelineMain. @@ -58,6 +63,11 @@ Module Bedrock2Later. := main_gen ForExtraction.SaturatedSolinas.PipelineMain. End SaturatedSolinas. + Module SolinasReduction. + Definition main : IO_unit + := main_gen ForExtraction.SolinasReduction.PipelineMain. + End SolinasReduction. + Module BaseConversion. Definition main : IO_unit := main_gen ForExtraction.BaseConversion.PipelineMain. diff --git a/src/Bedrock/Standalone/StandaloneOCamlMain.v b/src/Bedrock/Standalone/StandaloneOCamlMain.v index 346a0f1208..456bf504e4 100644 --- a/src/Bedrock/Standalone/StandaloneOCamlMain.v +++ b/src/Bedrock/Standalone/StandaloneOCamlMain.v @@ -32,6 +32,11 @@ Module Bedrock2First. := main_gen ForExtraction.SaturatedSolinas.PipelineMain. End SaturatedSolinas. + Module SolinasReduction. + Definition main : unit + := main_gen ForExtraction.SolinasReduction.PipelineMain. + End SolinasReduction. + Module BaseConversion. Definition main : unit := main_gen ForExtraction.BaseConversion.PipelineMain. @@ -61,6 +66,11 @@ Module Bedrock2Later. := main_gen ForExtraction.SaturatedSolinas.PipelineMain. End SaturatedSolinas. + Module SolinasReduction. + Definition main : unit + := main_gen ForExtraction.SolinasReduction.PipelineMain. + End SolinasReduction. + Module BaseConversion. Definition main : unit := main_gen ForExtraction.BaseConversion.PipelineMain. diff --git a/src/CLI.v b/src/CLI.v index db4edf335d..b27fa25076 100644 --- a/src/CLI.v +++ b/src/CLI.v @@ -22,6 +22,7 @@ Require Crypto.PushButtonSynthesis.SaturatedSolinas. Require Crypto.PushButtonSynthesis.UnsaturatedSolinas. Require Crypto.PushButtonSynthesis.WordByWordMontgomery. Require Crypto.PushButtonSynthesis.BaseConversion. +Require Crypto.PushButtonSynthesis.SolinasReduction. Require Import Crypto.UnsaturatedSolinasHeuristics. Require Import Crypto.Stringification.Language. Require Import Crypto.Stringification.C. @@ -1114,6 +1115,41 @@ Module ForExtraction. := Parameterized.PipelineMain argv. End SaturatedSolinas. + Module SolinasReduction. + Local Instance api : PipelineAPI + := { + spec := + {| Arg.named_args := [] + ; Arg.anon_args := [sc_spec] + ; Arg.anon_opt_args := [] + ; Arg.anon_opt_repeated_arg := Some (function_to_synthesize_spec SolinasReduction.valid_names) |}; + + parse_args opts args + := let '(tt, (str_sc, (s, c)), tt, requests) := args in + let show_requests := match requests with nil => "(all)" | _ => String.concat ", " requests end in + inl ((str_sc, show_requests), + (s, c, requests)); + + show_lines_args := + fun '((str_sc, show_requests), + (s, c, requests)) + => ["requested operations: " ++ show_requests; + "s-c = " ++ PowersOfTwo.show_Z s ++ " - " ++ show_c c ++ " (from """ ++ str_sc ++ """)"]; + + Synthesize + := fun _ opts '(s, c, requests) comment_header prefix + => SolinasReduction.Synthesize s c machine_wordsize comment_header prefix requests + }. + + Definition PipelineMain + {supported_languages : supported_languagesT} + {A} + {io_driver : IODriverAPI A} + (argv : list string) + : A + := Parameterized.PipelineMain argv. + End SolinasReduction. + Module BaseConversion. Local Instance api : PipelineAPI := { diff --git a/src/COperationSpecifications.v b/src/COperationSpecifications.v index fc755b09f8..fb8223ef12 100644 --- a/src/COperationSpecifications.v +++ b/src/COperationSpecifications.v @@ -494,6 +494,33 @@ Module SaturatedSolinas. End __. End SaturatedSolinas. +Module SolinasReduction. + Section __. + Context (wt : nat -> Z) + (n : nat) + (m : Z) + (saturated_bounds : list (option zrange)) + (length_saturated_bounds : length saturated_bounds = n). + Local Notation eval := (Positional.eval wt n). + + Definition mul_correct + (mul : list Z -> list Z -> list Z) := + forall x y, + list_Z_bounded_by saturated_bounds x -> + list_Z_bounded_by saturated_bounds y -> + ((eval (mul x y)) mod m = (eval x * eval y) mod m) /\ + (list_Z_bounded_by saturated_bounds (mul x y)). + + Definition sqr_correct + (sqr : list Z -> list Z) := + forall x, + list_Z_bounded_by saturated_bounds x -> + ((eval (sqr x)) mod m = (eval x * eval x) mod m) /\ + (list_Z_bounded_by saturated_bounds (sqr x)). + + End __. +End SolinasReduction. + Module WordByWordMontgomery. Import Arithmetic.WordByWordMontgomery. Local Coercion Z.of_nat : nat >-> Z. diff --git a/src/ExtractionHaskell/bedrock2_solinas_reduction.v b/src/ExtractionHaskell/bedrock2_solinas_reduction.v new file mode 100644 index 0000000000..74f4d1c319 --- /dev/null +++ b/src/ExtractionHaskell/bedrock2_solinas_reduction.v @@ -0,0 +1,5 @@ +Require Import Crypto.Bedrock.Standalone.StandaloneHaskellMain. +Import Bedrock2First. + +(*Redirect "/tmp/bedrock2_solinas_reduction.hs"*) Recursive Extraction SolinasReduction.main. +(* cat /tmp/bedrock2_solinas_reduction.hs.out | sed -f haskell.sed > ../../bedrock2_solinas_reduction.hs *) diff --git a/src/ExtractionHaskell/solinas_reduction.v b/src/ExtractionHaskell/solinas_reduction.v new file mode 100644 index 0000000000..7339d92067 --- /dev/null +++ b/src/ExtractionHaskell/solinas_reduction.v @@ -0,0 +1,3 @@ +Require Import Crypto.StandaloneHaskellMain. + +Recursive Extraction SolinasReduction.main. diff --git a/src/ExtractionHaskell/with_bedrock2_solinas_reduction.v b/src/ExtractionHaskell/with_bedrock2_solinas_reduction.v new file mode 100644 index 0000000000..4bb3d3b585 --- /dev/null +++ b/src/ExtractionHaskell/with_bedrock2_solinas_reduction.v @@ -0,0 +1,5 @@ +Require Import Crypto.Bedrock.Standalone.StandaloneHaskellMain. +Import Bedrock2Later. + +(*Redirect "/tmp/bedrock2_solinas_reduction.hs"*) Recursive Extraction SolinasReduction.main. +(* cat /tmp/bedrock2_solinas_reduction.hs.out | sed -f haskell.sed > ../../bedrock2_solinas_reduction.hs *) diff --git a/src/ExtractionOCaml/bedrock2_solinas_reduction.v b/src/ExtractionOCaml/bedrock2_solinas_reduction.v new file mode 100644 index 0000000000..2ca765d0fb --- /dev/null +++ b/src/ExtractionOCaml/bedrock2_solinas_reduction.v @@ -0,0 +1,4 @@ +Require Import Crypto.Bedrock.Standalone.StandaloneOCamlMain. +Import Bedrock2First. + +Extraction "src/ExtractionOCaml/bedrock2_solinas_reduction.tmp" SolinasReduction.main. diff --git a/src/ExtractionOCaml/solinas_reduction.v b/src/ExtractionOCaml/solinas_reduction.v new file mode 100644 index 0000000000..6686bf841a --- /dev/null +++ b/src/ExtractionOCaml/solinas_reduction.v @@ -0,0 +1,3 @@ +Require Import Crypto.StandaloneOCamlMain. + +Extraction "src/ExtractionOCaml/solinas_reduction.tmp" SolinasReduction.main. diff --git a/src/ExtractionOCaml/with_bedrock2_solinas_reduction.v b/src/ExtractionOCaml/with_bedrock2_solinas_reduction.v new file mode 100644 index 0000000000..44c660ff92 --- /dev/null +++ b/src/ExtractionOCaml/with_bedrock2_solinas_reduction.v @@ -0,0 +1,4 @@ +Require Import Crypto.Bedrock.Standalone.StandaloneOCamlMain. +Import Bedrock2Later. + +Extraction "src/ExtractionOCaml/with_bedrock2_solinas_reduction.tmp" SaturatedSolinas.main. diff --git a/src/PushButtonSynthesis/SolinasReduction.v b/src/PushButtonSynthesis/SolinasReduction.v new file mode 100644 index 0000000000..3066dbe357 --- /dev/null +++ b/src/PushButtonSynthesis/SolinasReduction.v @@ -0,0 +1,288 @@ +(** * Push-Button Synthesis of Saturated Reduction *) +Require Import Coq.Strings.String. +Require Import Coq.micromega.Lia. +Require Import Coq.ZArith.ZArith. +Require Import Coq.MSets.MSetPositive. +Require Import Coq.Lists.List. +Require Import Coq.QArith.QArith_base Coq.QArith.Qround. +Require Import Coq.derive.Derive. +Require Import Crypto.Util.ErrorT. +Require Import Crypto.Util.ListUtil. +Require Import Crypto.Util.ListUtil.FoldBool. +Require Import Crypto.Util.Strings.Decimal. +Require Import Crypto.Util.Strings.Show. +Require Import Crypto.Util.ZRange. +Require Import Crypto.Util.ZUtil.Definitions. +Require Import Crypto.Util.ZUtil.Zselect. +Require Import Crypto.Util.ZUtil.Tactics.LtbToLt. +Require Import Crypto.Util.Tactics.HasBody. +Require Import Crypto.Util.Tactics.Head. +Require Import Crypto.Util.Tactics.SpecializeBy. +Require Import Rewriter.Language.Wf. +Require Import Rewriter.Language.Language. +Require Import Crypto.Language.API. +Require Import Crypto.AbstractInterpretation.AbstractInterpretation. +Require Import Crypto.Stringification.Language. +Require Import Crypto.Arithmetic.Core. +Require Import Crypto.Arithmetic.ModOps. +Require Import Crypto.Arithmetic.Saturated. +Require Import Crypto.Arithmetic.SolinasReduction. +Require Import Crypto.BoundsPipeline. +Require Import Crypto.COperationSpecifications. +Require Import Crypto.PushButtonSynthesis.ReificationCache. +Require Import Crypto.PushButtonSynthesis.Primitives. +Require Import Crypto.PushButtonSynthesis.SaturatedSolinasReificationCache. +Require Import Crypto.PushButtonSynthesis.SolinasReductionReificationCache. +Require Import Crypto.Assembly.Equivalence. +Import ListNotations. +Local Open Scope string_scope. Local Open Scope Z_scope. Local Open Scope list_scope. Local Open Scope bool_scope. + +Import + Language.Wf.Compilers + Language.Compilers + AbstractInterpretation.Compilers + Stringification.Language.Compilers. +Import Compilers.API. + +Import COperationSpecifications.Primitives. +Import COperationSpecifications.Solinas. +Import COperationSpecifications.SolinasReduction. + +Import Associational Positional. +Import SolinasReduction. + +Local Coercion Z.of_nat : nat >-> Z. +Local Coercion QArith_base.inject_Z : Z >-> Q. +Local Coercion Z.pos : positive >-> Z. + +Local Set Keyed Unification. (* needed for making [autorewrite] fast, c.f. COQBUG(https://github.com/coq/coq/issues/9283) *) + +Local Opaque reified_mul_gen. (* needed for making [autorewrite] not take a very long time *) +Local Opaque reified_square_gen. +(* needed for making [autorewrite] with [Set Keyed Unification] fast *) +Local Opaque expr.Interp. + +Section __. + Context {output_language_api : ToString.OutputLanguageAPI} + {pipeline_opts : PipelineOptions} + {pipeline_to_string_opts : PipelineToStringOptions} + {synthesis_opts : SynthesisOptions} + (s : Z) + (c : list (Z * Z)). + Context (machine_wordsize : machine_wordsize_opt). + + Local Instance override_pipeline_opts : PipelineOptions + := {| widen_bytes := true (* true, because we don't allow byte-sized things anyway, so we should not expect carries to be widened to byte-size when emitting C code *) + |}. + + (* We include [0], so that even after bounds relaxation, we can + notice where the constant 0s are, and remove them. *) + Definition possible_values_of_machine_wordsize + := prefix_with_carry [machine_wordsize]. + + Definition n : nat := Z.to_nat (Qceiling (Z.log2_up s / machine_wordsize)). + Definition m := s - Associational.eval c. + Definition weight := UniformWeight.uweight machine_wordsize. + Definition up_bound := 2 ^ (machine_wordsize / 4). + Definition base : Z := 2 ^ machine_wordsize. + + Local Notation possible_values := possible_values_of_machine_wordsize. + Local Notation boundsn := (saturated_bounds n machine_wordsize). + Local Notation bounds4 := (saturated_bounds 4 machine_wordsize). + + Local Existing Instance default_translate_to_fancy. + Local Instance no_select_size : no_select_size_opt := no_select_size_of_no_select machine_wordsize. + Local Instance split_mul_to : split_mul_to_opt := split_mul_to_of_should_split_mul machine_wordsize possible_values. + Local Instance split_multiret_to : split_multiret_to_opt := split_multiret_to_of_should_split_multiret machine_wordsize possible_values. + + (** Note: If you change the name or type signature of this + function, you will need to update the code in CLI.v *) + Definition check_args {T} (requests : list string) (res : Pipeline.ErrorT T) + : Pipeline.ErrorT T + := check_args_of_list + (List.map + (fun v => (true, v)) + [((0 1)%nat /\ + s > 0 /\ + Associational.eval c > 0 /\ + s - Associational.eval c <> 0 /\ + machine_wordsize = 64 /\ + base <> 0 /\ + Rows.adjust_s weight (S (S n)) s = (weight n, true) /\ + weight n / s * Associational.eval c < up_bound. + Proof using curve_good. + prepare_use_curve_good (). + { use_curve_good_t. } + { use_curve_good_t. } + { use_curve_good_t. } + { unfold base. + apply Z.pow_nonzero; use_curve_good_t. } + { lazymatch goal with + | |- ?x = _ => rewrite surjective_pairing with (p:=x) + end. + congruence. } + Qed. + + Local Notation evalf := (eval weight n). + Local Notation weightf := weight. + Local Notation notations_for_docstring + := (CorrectnessStringification.dyn_context.cons + weightf "weight" + (CorrectnessStringification.dyn_context.cons + evalf "eval" + CorrectnessStringification.dyn_context.nil))%string. + Local Notation "'docstring_with_summary_from_lemma!' summary correctness" + := (docstring_with_summary_from_lemma_with_ctx! + notations_for_docstring + summary + correctness) + (only parsing, at level 10, summary at next level, correctness at next level). + + Definition mul + := Pipeline.BoundsPipeline + false (* subst01 *) + possible_values + (reified_mul_gen + @ GallinaReify.Reify base + @ GallinaReify.Reify s + @ GallinaReify.Reify c + @ GallinaReify.Reify n) + (Some boundsn, (Some boundsn, tt)) + (Some boundsn). + + Definition square + := Pipeline.BoundsPipeline + false (* subst01 *) + possible_values + (reified_square_gen + @ GallinaReify.Reify base + @ GallinaReify.Reify s + @ GallinaReify.Reify c + @ GallinaReify.Reify n) + (Some boundsn, tt) + (Some boundsn). + + Definition smul (prefix : string) + : string * (Pipeline.M (Pipeline.ExtendedSynthesisResult _)) + := Eval cbv beta in + FromPipelineToString! + machine_wordsize prefix "mul" mul + (docstring_with_summary_from_lemma! + (fun fname : string => [text_before_function_name ++ fname ++ " multiplies two field elements."]%string) + (mul_correct weightf n m boundsn)). + + Definition ssquare (prefix : string) + : string * (Pipeline.M (Pipeline.ExtendedSynthesisResult _)) + := Eval cbv beta in + FromPipelineToString! + machine_wordsize prefix "square" square + (docstring_with_summary_from_lemma! + (fun fname : string => [text_before_function_name ++ fname ++ " squares a field element."]%string) + (sqr_correct weightf n m boundsn)). + + Local Ltac solve_extra_bounds_side_conditions := + cbn [lower upper fst snd] in *; Bool.split_andb; Z.ltb_to_lt; lia. + + Local Ltac prove_correctness _ := Primitives.prove_correctness use_curve_good. + + Lemma mul_correct res + (Hres : mul = Success res) + : mul_correct weight n m boundsn (Interp res). + Proof using curve_good. + prove_correctness (). + cbv [evalf weightf weight up_bound] in *. + match goal with + | H : machine_wordsize = _ |- _ => rewrite H in * + end. + apply (fun pf => @SolinasReduction.SolinasReduction.mulmod_correct (@wprops _ _ pf)); auto; lia. + Qed. + + Lemma Wf_mul res (Hres : mul = Success res) : Wf res. + Proof using Type. prove_pipeline_wf (). Qed. + + Lemma square_correct res + (Hres : square = Success res) + : sqr_correct weight n m boundsn (Interp res). + Proof using curve_good. + + prove_correctness (). + cbv [evalf weightf weight up_bound] in *. + match goal with + | H : machine_wordsize = _ |- _ => rewrite H in * + end. + apply (fun pf => @SolinasReduction.SolinasReduction.squaremod_correct (@wprops _ _ pf)); auto; lia. + Qed. + + Lemma Wf_square res (Hres : square = Success res) : Wf res. + Proof using Type. prove_pipeline_wf (). Qed. + + Section for_stringification. + Local Open Scope string_scope. + Local Open Scope list_scope. + + Definition known_functions + := [("mul", wrap_s smul); ("square", wrap_s ssquare)]. + + Definition valid_names : string := Eval compute in String.concat ", " (List.map (@fst _ _) known_functions). + + (** Note: If you change the name or type signature of this + function, you will need to update the code in CLI.v *) + Definition Synthesize (comment_header : list string) (function_name_prefix : string) (requests : list string) + : list (synthesis_output_kind * string * Pipeline.M (list string)) + := Primitives.Synthesize + machine_wordsize valid_names known_functions (fun _ => nil) all_typedefs! + check_args + ((ToString.comment_file_header_block + (comment_header + ++ [""; + "Computed values:"; + ""]%string))) + function_name_prefix requests. + End for_stringification. +End __. + +Module Export Hints. +#[global] + Hint Opaque + mul + : wf_op_cache. +#[global] + Hint Immediate + Wf_mul + : wf_op_cache. + +#[global] + Hint Opaque + square + : wf_op_cache. +#[global] + Hint Immediate + Wf_square + : wf_op_cache. +End Hints. diff --git a/src/PushButtonSynthesis/SolinasReductionReificationCache.v b/src/PushButtonSynthesis/SolinasReductionReificationCache.v new file mode 100644 index 0000000000..f956c54381 --- /dev/null +++ b/src/PushButtonSynthesis/SolinasReductionReificationCache.v @@ -0,0 +1,58 @@ +(** * Push-Button Synthesis of Solinas Reduction: Reification Cache *) +Require Import Coq.QArith.QArith_base Coq.QArith.Qround. +Require Import Coq.Init.Nat. +Require Import Coq.ZArith.ZArith. +Require Import Coq.ZArith.BinInt. +Require Import Coq.derive.Derive. +Require Import Crypto.Arithmetic.Core. +Require Import Crypto.Arithmetic.ModOps. +Require Import Crypto.Arithmetic.Saturated. +Require Import Crypto.Arithmetic.SolinasReduction. +Require Import Crypto.PushButtonSynthesis.ReificationCache. + +Require Import Crypto.Language.IdentifierParameters. +Require Import Coq.Strings.String. +Require Import Coq.ZArith.ZArith. +Require Import Crypto.Util.ListUtil Coq.Lists.List. +Require Import Crypto.Util.ZRange. +Require Import Crypto.Util.ZUtil.Definitions. +Require Import Crypto.Language.PreExtra. + +Local Open Scope Z_scope. + +Local Set Keyed Unification. (* needed for making [autorewrite] fast, c.f. COQBUG(https://github.com/coq/coq/issues/9283) *) + +Import + Language.API.Compilers + Language.Wf.Compilers. +Import SolinasReduction.SolinasReduction. + +Module Export SolinasReduction. + + Derive reified_mul_gen + SuchThat (is_reification_of reified_mul_gen mulmod) + As reified_mul_gen_correct. + Proof. Time cache_reify (). Time Qed. + + Derive reified_square_gen + SuchThat (is_reification_of reified_square_gen squaremod) + As reified_square_gen_correct. + Proof. Time cache_reify (). Time Qed. + + #[global] + Hint Extern 1 (_ = _) => apply_cached_reification mulmod (proj1 reified_mul_gen) : reify_cache_gen. + #[global] + Hint Immediate (proj2 reified_mul_gen_correct) : wf_gen_cache. + #[global] + Hint Rewrite (proj1 reified_mul_gen_correct) : interp_gen_cache. + Local Opaque reified_mul_gen. (* needed for making [autorewrite] not take a very long time *) + + #[global] + Hint Extern 1 (_ = _) => apply_cached_reification squaremod (proj1 reified_square_gen) : reify_cache_gen. + #[global] + Hint Immediate (proj2 reified_square_gen_correct) : wf_gen_cache. + #[global] + Hint Rewrite (proj1 reified_square_gen_correct) : interp_gen_cache. + Local Opaque reified_square_gen. (* needed for making [autorewrite] not take a very long time *) + +End SolinasReduction. diff --git a/src/SlowPrimeSynthesisExamples.v b/src/SlowPrimeSynthesisExamples.v index e4da917536..a38603e14f 100644 --- a/src/SlowPrimeSynthesisExamples.v +++ b/src/SlowPrimeSynthesisExamples.v @@ -4,8 +4,12 @@ Require Import Coq.QArith.Qround. Require Import Coq.Strings.String. Require Import Coq.derive.Derive. Require Import Coq.Lists.List. +Require Import Crypto.Util.LetIn. Require Import Crypto.Util.ZRange. +Require Import Crypto.Util.ZUtil.Zselect. +Require Import Crypto.Util.ZUtil.Definitions. Require Import Crypto.Arithmetic.Core. +Require Import Crypto.Arithmetic.SolinasReduction. Require Import Crypto.Arithmetic.ModOps. Require Import Crypto.Arithmetic.Partition. Require Import Crypto.PushButtonSynthesis.UnsaturatedSolinas. diff --git a/src/StandaloneHaskellMain.v b/src/StandaloneHaskellMain.v index ac32bfa168..d5f2a6f30a 100644 --- a/src/StandaloneHaskellMain.v +++ b/src/StandaloneHaskellMain.v @@ -130,6 +130,11 @@ Module SaturatedSolinas. := main_gen ForExtraction.SaturatedSolinas.PipelineMain. End SaturatedSolinas. +Module SolinasReduction. + Definition main : IO_unit + := main_gen ForExtraction.SolinasReduction.PipelineMain. +End SolinasReduction. + Module BaseConversion. Definition main : IO_unit := main_gen ForExtraction.BaseConversion.PipelineMain. diff --git a/src/StandaloneOCamlMain.v b/src/StandaloneOCamlMain.v index 2d60dccec7..795af2a4c8 100644 --- a/src/StandaloneOCamlMain.v +++ b/src/StandaloneOCamlMain.v @@ -219,6 +219,11 @@ Module SaturatedSolinas. := main_gen ForExtraction.SaturatedSolinas.PipelineMain. End SaturatedSolinas. +Module SolinasReduction. + Definition main : unit + := main_gen ForExtraction.SolinasReduction.PipelineMain. +End SolinasReduction. + Module BaseConversion. Definition main : unit := main_gen ForExtraction.BaseConversion.PipelineMain.