; Copyright (C) 2026 Kiyotsugu Arai ; SPDX-License-Identifier: LGPL-3.0-or-later ; ; mpn_x64_mont.asm — Montgomery CIOS multiplication / REDC (BMI2+ADX) ; ; Functions: ; mpn_mont_mul_mulx(rp, ap, bp, n, mp, m_inv, scratch) ; mpn_mont_redc_mulx(rp, tp, tn, mp, n, m_inv) ; mpn_mont_mul_8(rp, ap, bp, mp, m_inv) — n=8 specialized SOS ; mpn_mont_redc_16(rp, tp, mp, m_inv) — n=16 specialized REDC ; mpn_mont_redc_32(rp, tp, mp, m_inv) — n=32 specialized REDC ; mpn_mont_mul_4(rp, ap, bp, mp, m_inv) — n=4 specialized SOS ; mpn_mont_sqr_4(rp, ap, mp, m_inv) — n=4 fused SQR+REDC ; mpn_mont_mul_3(rp, ap, bp, mp, m_inv) — n=3 specialized SOS (192-bit) ; mpn_mont_mul_2(rp, ap, bp, mp, m_inv) — n=2 specialized SOS ; mpn_mont_sqr_2(rp, ap, mp, m_inv) — n=2 fused SQR+REDC ; mpn_mont_sqr_16(rp, ap, mp, m_inv) — n=16 fused SQR+REDC ; ; Precondition: CPU must support BMI2 + ADX (CPUID already checked by the caller) ; ; Windows x64 calling convention: ; rcx = 1st, rdx = 2nd, r8 = 3rd, r9 = 4th ; Return value: rax ; Non-volatile: rbx, rbp, rdi, rsi, r12-r15 ; Volatile: rax, rcx, rdx, r8, r9, r10, r11 ; ===================================================================== ; Macro: inline addmul_1 body (4x unrolled + 1x tail) ; ; Input: rdx = multiplier, rsi = source, rbx = dest, rcx = n ; r9 = carry (initial value 0), r8 = 0 constant ; Output: r9 = final carry ; Clobbers: r10-r15, rdi, rax, flags ; ===================================================================== INLINE_ADDMUL_1 MACRO LOCAL am_4x, am_tail_check, am_tail, am_done cmp rcx, 4 jb am_tail_check am_4x: xor eax, eax ; CF=0, OF=0 mulx r10, r11, [rsi] mulx r12, r13, [rsi+8] mulx r14, r15, [rsi+16] mulx rdi, rax, [rsi+24] adcx r11, r9 adox r11, [rbx] mov QWORD PTR [rbx], r11 adcx r13, r10 adox r13, [rbx+8] mov QWORD PTR [rbx+8], r13 adcx r15, r12 adox r15, [rbx+16] mov QWORD PTR [rbx+16], r15 adcx rax, r14 adox rax, [rbx+24] mov QWORD PTR [rbx+24], rax mov r9, rdi adcx r9, r8 adox r9, r8 lea rsi, [rsi+32] lea rbx, [rbx+32] sub rcx, 4 cmp rcx, 4 jae am_4x am_tail_check: test rcx, rcx jz am_done am_tail: mulx r10, r11, [rsi] add r11, r9 adc r10, 0 add QWORD PTR [rbx], r11 adc r10, 0 mov r9, r10 lea rsi, [rsi+8] lea rbx, [rbx+8] dec rcx jnz am_tail am_done: ENDM ; ===================================================================== ; n=8 register-resident Montgomery multiplication macro set ; Shift trick based on IPP analysis: accumulator r8-r14 + r15(carry) ; rbp/rbx used alternately as MULX hi/lo temporaries ; ===================================================================== ; 8-limb addmul first limb: start of dual carry chain ; Input: rdx = multiplier, rsi = source array, r8-r14 = acc[0..6], r15 = acc[7] ; Output: r8 = shifted-out word (store or discard), rbx = hi (for REST_8) ADDMUL_FIRST_8 MACRO xor eax, eax mulx rbx, rbp, [rsi] adox r8, rbp ENDM ; 8-limb addmul remaining 7 limbs + carry capture ; Input: right after ADDMUL_FIRST_8, rbx = hi of limb 0 ; Output: r8-r14 = new acc[0..6], r15 = carry word, rax = 0 ADDMUL_REST_8 MACRO adcx r9, rbx mulx rbp, r8, [rsi+8] adox r8, r9 adcx r10, rbp mulx rbx, r9, [rsi+16] adox r9, r10 adcx r11, rbx mulx rbp, r10, [rsi+24] adox r10, r11 adcx r12, rbp mulx rbx, r11, [rsi+32] adox r11, r12 adcx r13, rbx mulx rbp, r12, [rsi+40] adox r12, r13 adcx r14, rbp mulx rbx, r13, [rsi+48] adox r13, r14 adcx r15, rbx mulx rbp, r14, [rsi+56] adox r14, r15 mov r15, rax adcx r15, rbp adox r15, rax ENDM ; REDC 1 iteration: q = r8 * m_inv, acc += mp * q, shift, add carry to P[8+i] ; Input: rsi = mp, rdi = product buffer, r8-r14 = acc[0..6], r15 = acc[7] ; [rsp+168] = m_inv ; Output: r8-r14 = shifted acc[0..6], r15 = P[8+i] + carry ; 4-word addmul block (fixed-offset version, no pointer advance) ; Input: rdx = multiplier, rsi = source base, rbx = dest base ; r9 = carry_in, r8 = 0 constant, off = byte offset ; Output: r9 = carry_out ; Clobbers: r10-r15, rdi, rax, flags ADDMUL_BLOCK_4 MACRO off xor eax, eax mulx r10, r11, [rsi+off] mulx r12, r13, [rsi+off+8] mulx r14, r15, [rsi+off+16] mulx rdi, rax, [rsi+off+24] adcx r11, r9 adox r11, [rbx+off] mov [rbx+off], r11 adcx r13, r10 adox r13, [rbx+off+8] mov [rbx+off+8], r13 adcx r15, r12 adox r15, [rbx+off+16] mov [rbx+off+16], r15 adcx rax, r14 adox rax, [rbx+off+24] mov [rbx+off+24], rax mov r9, rdi adcx r9, r8 adox r9, r8 ENDM REDC_ITER MACRO iter_idx LOCAL ri_nc mov rax, r8 imul rax, QWORD PTR [rsp+168] mov rdx, rax ADDMUL_FIRST_8 ADDMUL_REST_8 add r15, QWORD PTR [rdi + (8 + iter_idx)*8] jnc ri_nc _prop_idx = 9 + iter_idx WHILE _prop_idx LE 16 add QWORD PTR [rdi + _prop_idx*8], 1 jnc ri_nc _prop_idx = _prop_idx + 1 ENDM ri_nc: ENDM .code ; ===================================================================== ; void mpn_mont_mul_mulx(uint64_t* rp, const uint64_t* ap, ; const uint64_t* bp, size_t n, ; const uint64_t* mp, uint64_t m_inv, ; uint64_t* scratch) ; ; CIOS Montgomery multiplication: rp = ap * bp * R^{-1} mod mp ; ; rcx = rp, rdx = ap, r8 = bp, r9 = n ; [rsp+40] = mp, [rsp+48] = m_inv, [rsp+56] = scratch ; ; scratch must be at least 2n+1 words (zero-initialized inside the function) ; ; addmul_1 is inlined to remove push/pop overhead. ; Conventional: 2n addmul_1 function calls (each 7 push + 7 pop) ; This function: runs all iterations with a single push/pop ; ===================================================================== mpn_mont_mul_mulx PROC push rbx push rsi push rdi push r12 push r13 push r14 push r15 push rbp sub rsp, 64 ; local variables 8 qwords ; Stack layout: ; 8 push × 8 = 64, sub 64 → total = 128 ; 5th arg (mp): [rsp + 168] ; 6th arg (m_inv): [rsp + 176] ; 7th arg (scratch): [rsp + 184] ; ; Local variables: ; [rsp+0] = rp ; [rsp+8] = ap ; [rsp+16] = n ; [rsp+24] = mp ; [rsp+32] = m_inv ; [rsp+40] = scratch ; [rsp+48] = bp mov [rsp+0], rcx mov [rsp+8], rdx mov [rsp+16], r9 mov rax, [rsp+168] mov [rsp+24], rax mov rax, [rsp+176] mov [rsp+32], rax mov rax, [rsp+184] mov [rsp+40], rax mov [rsp+48], r8 ; zero-initialize scratch[0..2n] mov rdi, rax ; scratch ptr xor eax, eax mov rcx, r9 lea rcx, [rcx*2+1] rep stosq ; === Outer loop: i = 0 .. n-1 === xor ebp, ebp ; rbp = i = 0 mm_outer: ; --- Phase 1: scratch[i..i+n-1] += ap[0..n-1] * bp[i] --- mov rsi, [rsp+8] ; ap mov rbx, [rsp+40] ; scratch lea rbx, [rbx + rbp*8] mov rax, [rsp+48] ; bp mov rdx, [rax + rbp*8] ; bp[i] → MULX multiplier mov rcx, [rsp+16] ; n xor r9d, r9d xor r8d, r8d INLINE_ADDMUL_1 ; carry (r9) → scratch[i+n], propagate mov rax, [rsp+40] mov rcx, rbp add rcx, [rsp+16] ; i + n add [rax + rcx*8], r9 jnc mm_phase2 mov rdi, [rsp+16] shl rdi, 1 ; 2n mm_carry1: inc rcx cmp rcx, rdi ja mm_phase2 add QWORD PTR [rax + rcx*8], 1 jc mm_carry1 mm_phase2: ; --- Phase 2: q = scratch[i] * m_inv, scratch += mp * q --- mov rax, [rsp+40] ; scratch mov rax, [rax + rbp*8] ; scratch[i] imul rax, QWORD PTR [rsp+32] ; q = scratch[i] * m_inv mov rdx, rax ; q → MULX multiplier mov rsi, [rsp+24] ; mp mov rbx, [rsp+40] ; scratch lea rbx, [rbx + rbp*8] mov rcx, [rsp+16] ; n xor r9d, r9d xor r8d, r8d INLINE_ADDMUL_1 ; carry (r9) → scratch[i+n], propagate mov rax, [rsp+40] mov rcx, rbp add rcx, [rsp+16] add [rax + rcx*8], r9 jnc mm_next mov rdi, [rsp+16] shl rdi, 1 mm_carry2: inc rcx cmp rcx, rdi ja mm_next add QWORD PTR [rax + rcx*8], 1 jc mm_carry2 mm_next: inc rbp cmp rbp, [rsp+16] jb mm_outer ; === Conditional subtraction: subtract if scratch[n..2n-1] >= mp === ; try scratch[n..2n] - mp[0..n-1], adopt if no borrow mov rax, [rsp+40] ; scratch mov rcx, [rsp+16] ; n mov rbx, [rsp+0] ; rp (result destination) mov rsi, [rsp+24] ; mp ; negative-index loop (inc does not clobber CF) mov r11, rcx ; r11 = n lea rdi, [rax + rcx*8] ; &scratch[n] neg rcx lea r12, [rdi + r11*8] ; &scratch[2n] (save for scratch[2n] check) lea rdi, [rdi + r11*8] ; &scratch[2n] lea rsi, [rsi + r11*8] ; &mp[n] lea rbx, [rbx + r11*8] ; &rp[n] clc mm_sub_loop: mov r10, [rdi + rcx*8] sbb r10, [rsi + rcx*8] mov [rbx + rcx*8], r10 inc rcx ; CF preserved jnz mm_sub_loop ; scratch[2n] - 0 - borrow mov r10, [r12] ; scratch[2n] sbb r10, 0 jnc mm_done ; no borrow → subtraction result is valid ; borrow → copy original scratch[n..2n-1] to rp mov rax, [rsp+40] ; scratch mov rbx, [rsp+0] ; rp lea rdi, [rax + r11*8] ; &scratch[n] xor r9d, r9d mm_copy: mov r10, [rdi + r9*8] mov [rbx + r9*8], r10 inc r9 cmp r9, r11 jb mm_copy mm_done: add rsp, 64 pop rbp pop r15 pop r14 pop r13 pop r12 pop rdi pop rsi pop rbx ret mpn_mont_mul_mulx ENDP ; ===================================================================== ; void mpn_mont_redc_mulx(uint64_t* rp, uint64_t* tp, size_t tn, ; const uint64_t* mp, size_t n, uint64_t m_inv) ; ; Montgomery reduction: rp = tp * R^{-1} mod mp ; tp[0..tn-1] is destroyed (in-place reduction) ; tn >= 2n+1 must hold ; ; rcx = rp, rdx = tp, r8 = tn, r9 = mp ; [rsp+40] = n, [rsp+48] = m_inv ; ; Used to Montgomery-reduce the output of mpn::square(). ; Replaces the scalar carry loop of the C++ mont_redc with an ADCX/ADOX chain. ; ===================================================================== mpn_mont_redc_mulx PROC push rbx push rsi push rdi push r12 push r13 push r14 push r15 push rbp sub rsp, 48 ; local variables 6 qwords ; Stack layout: ; 8 push × 8 = 64, sub 48 → total = 112 ; 5th arg (n): [rsp + 152] ; 6th arg (m_inv): [rsp + 160] ; ; Local variables: ; [rsp+0] = rp ; [rsp+8] = tp ; [rsp+16] = tn ; [rsp+24] = mp ; [rsp+32] = n ; [rsp+40] = m_inv mov [rsp+0], rcx mov [rsp+8], rdx mov [rsp+16], r8 mov [rsp+24], r9 mov rax, [rsp+152] mov [rsp+32], rax mov rax, [rsp+160] mov [rsp+40], rax ; === Outer loop: i = 0 .. n-1 === xor ebp, ebp ; rbp = i = 0 mr_outer: ; q = tp[i] * m_inv mov rax, [rsp+8] ; tp mov rax, [rax + rbp*8] ; tp[i] imul rax, QWORD PTR [rsp+40] ; q = tp[i] * m_inv mov rdx, rax ; q → MULX multiplier ; tp[i..i+n-1] += mp[0..n-1] * q mov rsi, [rsp+24] ; mp mov rbx, [rsp+8] ; tp lea rbx, [rbx + rbp*8] mov rcx, [rsp+32] ; n xor r9d, r9d xor r8d, r8d INLINE_ADDMUL_1 ; carry (r9) → tp[i+n], propagate mov rax, [rsp+8] ; tp mov rcx, rbp add rcx, [rsp+32] ; i + n mov rdi, [rsp+16] ; tn dec rdi ; max valid index = tn - 1 add [rax + rcx*8], r9 jnc mr_next mr_carry: inc rcx cmp rcx, rdi ja mr_next add QWORD PTR [rax + rcx*8], 1 jc mr_carry mr_next: inc rbp cmp rbp, [rsp+32] jb mr_outer ; === tp[n..2n-1] → rp, conditional subtraction === mov rax, [rsp+8] ; tp mov rcx, [rsp+32] ; n mov rbx, [rsp+0] ; rp mov rsi, [rsp+24] ; mp mov r11, rcx ; r11 = n lea rdi, [rax + rcx*8] ; &tp[n] neg rcx lea rdi, [rdi + r11*8] ; &tp[2n] lea rsi, [rsi + r11*8] lea rbx, [rbx + r11*8] clc mr_sub_loop: mov r10, [rdi + rcx*8] sbb r10, [rsi + rcx*8] mov [rbx + rcx*8], r10 inc rcx jnz mr_sub_loop ; check for tp[2n] if present mov rax, [rsp+8] lea r12, [rax + r11*8] lea r12, [r12 + r11*8] ; &tp[2n] mov r10, [r12] sbb r10, 0 jnc mr_done ; borrow → copy original tp[n..2n-1] to rp mov rax, [rsp+8] mov rbx, [rsp+0] lea rdi, [rax + r11*8] xor r9d, r9d mr_copy: mov r10, [rdi + r9*8] mov [rbx + r9*8], r10 inc r9 cmp r9, r11 jb mr_copy mr_done: add rsp, 48 pop rbp pop r15 pop r14 pop r13 pop r12 pop rdi pop rsi pop rbx ret mpn_mont_redc_mulx ENDP ; ===================================================================== ; void mpn_mont_mul_8(uint64_t* rp, const uint64_t* ap, ; const uint64_t* bp, const uint64_t* mp, ; uint64_t m_inv) ; ; register-resident n=8 SOS Montgomery multiplication: rp = ap * bp * R^{-1} mod mp ; 512-bit specialized, no scratch buffer needed (product buffer on the stack) ; ; rcx = rp, rdx = ap, r8 = bp, r9 = mp, [rsp+40] = m_inv ; ; Phase 1: 8×8 full multiplication (accumulator r8-r14 register-resident, shift trick) ; Phase 2: REDC 8 iterations (similar register-resident addmul) ; Phase 3: conditional subtraction ; ===================================================================== mpn_mont_mul_8 PROC push rbx push rsi push rdi push r12 push r13 push r14 push r15 push rbp sub rsp, 184 ; P[0..16] 136B + locals 40B + pad 8B ; Stack layout: ; 8 push × 8 = 64, sub 184 → total = 248 ; 5th arg (m_inv): [rsp + 288] ; ; Local variables: ; [rsp+0..135] = P[0..16] product buffer (17 qwords) ; [rsp+136] = rp ; [rsp+144] = ap ; [rsp+152] = bp ; [rsp+160] = mp ; [rsp+168] = m_inv mov [rsp+136], rcx mov [rsp+144], rdx mov [rsp+152], r8 mov [rsp+160], r9 mov rax, [rsp+288] mov [rsp+168], rax mov rdi, rsp ; product buffer base mov rsi, rdx ; ap mov rcx, r8 ; bp ; ===== Phase 1: 8×8 full multiplication (SOS) ===== xor r8d, r8d xor r9d, r9d xor r10d, r10d xor r11d, r11d xor r12d, r12d xor r13d, r13d xor r14d, r14d xor r15d, r15d ; Row 0: b[0] mov rdx, [rcx] ADDMUL_FIRST_8 mov QWORD PTR [rdi], r8 ADDMUL_REST_8 ; Row 1: b[1] mov rdx, [rcx+8] ADDMUL_FIRST_8 mov QWORD PTR [rdi+8], r8 ADDMUL_REST_8 ; Row 2: b[2] mov rdx, [rcx+16] ADDMUL_FIRST_8 mov QWORD PTR [rdi+16], r8 ADDMUL_REST_8 ; Row 3: b[3] mov rdx, [rcx+24] ADDMUL_FIRST_8 mov QWORD PTR [rdi+24], r8 ADDMUL_REST_8 ; Row 4: b[4] mov rdx, [rcx+32] ADDMUL_FIRST_8 mov QWORD PTR [rdi+32], r8 ADDMUL_REST_8 ; Row 5: b[5] mov rdx, [rcx+40] ADDMUL_FIRST_8 mov QWORD PTR [rdi+40], r8 ADDMUL_REST_8 ; Row 6: b[6] mov rdx, [rcx+48] ADDMUL_FIRST_8 mov QWORD PTR [rdi+48], r8 ADDMUL_REST_8 ; Row 7: b[7] mov rdx, [rcx+56] ADDMUL_FIRST_8 mov QWORD PTR [rdi+56], r8 ADDMUL_REST_8 ; P[8..15] ← accumulator, P[16] = 0 mov [rdi+64], r8 mov [rdi+72], r9 mov [rdi+80], r10 mov [rdi+88], r11 mov [rdi+96], r12 mov [rdi+104], r13 mov [rdi+112], r14 mov [rdi+120], r15 mov QWORD PTR [rdi+128], 0 ; ===== Phase 2: REDC (8 iterations) ===== mov r8, [rdi] mov r9, [rdi+8] mov r10, [rdi+16] mov r11, [rdi+24] mov r12, [rdi+32] mov r13, [rdi+40] mov r14, [rdi+48] mov r15, [rdi+56] mov rsi, [rsp+160] ; mp REDC_ITER 0 REDC_ITER 1 REDC_ITER 2 REDC_ITER 3 REDC_ITER 4 REDC_ITER 5 REDC_ITER 6 REDC_ITER 7 ; ===== Phase 3: conditional subtraction ===== ; r8-r14 = result[0..6], r15 = result[7] mov rbx, [rsp+136] ; rp mov rsi, [rsp+160] ; mp mov rax, r8 sub rax, [rsi] mov [rbx], rax mov rax, r9 sbb rax, [rsi+8] mov [rbx+8], rax mov rax, r10 sbb rax, [rsi+16] mov [rbx+16], rax mov rax, r11 sbb rax, [rsi+24] mov [rbx+24], rax mov rax, r12 sbb rax, [rsi+32] mov [rbx+32], rax mov rax, r13 sbb rax, [rsi+40] mov [rbx+40], rax mov rax, r14 sbb rax, [rsi+48] mov [rbx+48], rax mov rax, r15 sbb rax, [rsi+56] mov [rbx+56], rax ; account for P[16] overflow mov rax, [rdi+128] sbb rax, 0 jnc m8_done ; borrow → subtraction result invalid, copy original result to rp mov [rbx], r8 mov [rbx+8], r9 mov [rbx+16], r10 mov [rbx+24], r11 mov [rbx+32], r12 mov [rbx+40], r13 mov [rbx+48], r14 mov [rbx+56], r15 m8_done: add rsp, 184 pop rbp pop r15 pop r14 pop r13 pop r12 pop rdi pop rsi pop rbx ret mpn_mont_mul_8 ENDP ; ===================================================================== ; void mpn_mont_sqr_8(uint64_t* rp, const uint64_t* ap, ; const uint64_t* mp, uint64_t m_inv) ; ; register-resident n=8 SOS Montgomery squaring: rp = ap^2 * R^{-1} mod mp ; 512-bit specialized, exploits symmetry (28+8=36 MULX vs 64 MULX for multiplication) ; ; rcx = rp, rdx = ap, r8 = mp, r9 = m_inv ; ; Phase 1a: upper-triangle multiplication (off-diagonal, ADCX/ADOX dual carry) ; Phase 1b: doubling (P[1..15] <<= 1) ; Phase 1c: add diagonal terms a[i]^2 ; Phase 2: REDC 8 iterations (reuse REDC_ITER macro) ; Phase 3: conditional subtraction ; ===================================================================== mpn_mont_sqr_8 PROC push rbx push rsi push rdi push r12 push r13 push r14 push r15 push rbp sub rsp, 184 ; P[0..16] 136B + locals 48B ; Stack layout (compatible with mont_mul_8 and REDC_ITER): ; [rsp+0..135] = P[0..16] product buffer (17 qwords) ; [rsp+136] = rp ; [rsp+160] = mp ; [rsp+168] = m_inv mov [rsp+136], rcx mov rsi, rdx ; rsi = ap mov [rsp+160], r8 ; mp mov [rsp+168], r9 ; m_inv mov rdi, rsp ; rdi = product buffer P ; --- Zero P[0..16] --- xor eax, eax mov [rdi], rax mov [rdi+8], rax mov [rdi+16], rax mov [rdi+24], rax mov [rdi+32], rax mov [rdi+40], rax mov [rdi+48], rax mov [rdi+56], rax mov [rdi+64], rax mov [rdi+72], rax mov [rdi+80], rax mov [rdi+88], rax mov [rdi+96], rax mov [rdi+104], rax mov [rdi+112], rax mov [rdi+120], rax mov [rdi+128], rax ; ===== Phase 1a: Off-diagonal upper triangle (28 MULX) ===== ; --- Row 0: a[0]*a[1..7] → P[1..8] (P=0 so store only) --- mov rdx, [rsi] mulx rbx, rcx, [rsi+8] mov [rdi+8], rcx mulx rbp, rcx, [rsi+16] add rcx, rbx mov [rdi+16], rcx mulx rbx, rcx, [rsi+24] adc rcx, rbp mov [rdi+24], rcx mulx rbp, rcx, [rsi+32] adc rcx, rbx mov [rdi+32], rcx mulx rbx, rcx, [rsi+40] adc rcx, rbp mov [rdi+40], rcx mulx rbp, rcx, [rsi+48] adc rcx, rbx mov [rdi+48], rcx mulx rbx, rcx, [rsi+56] adc rcx, rbp mov [rdi+56], rcx adc rbx, 0 mov [rdi+64], rbx ; --- Row 1: a[1]*a[2..7] → P[3..9] (ADCX/ADOX) --- mov rdx, [rsi+8] xor eax, eax mulx rbx, rcx, [rsi+16] adox rcx, [rdi+24] mov [rdi+24], rcx mulx rbp, rcx, [rsi+24] adcx rcx, rbx adox rcx, [rdi+32] mov [rdi+32], rcx mulx rbx, rcx, [rsi+32] adcx rcx, rbp adox rcx, [rdi+40] mov [rdi+40], rcx mulx rbp, rcx, [rsi+40] adcx rcx, rbx adox rcx, [rdi+48] mov [rdi+48], rcx mulx rbx, rcx, [rsi+48] adcx rcx, rbp adox rcx, [rdi+56] mov [rdi+56], rcx mulx rbp, rcx, [rsi+56] adcx rcx, rbx adox rcx, [rdi+64] mov [rdi+64], rcx ; tail → P[9] mov rcx, rax adcx rcx, rbp adox rcx, [rdi+72] mov [rdi+72], rcx ; residual CF+OF → P[10] mov rcx, rax adcx rcx, rcx adox rax, rax add rcx, rax add [rdi+80], rcx ; --- Row 2: a[2]*a[3..7] → P[5..10] --- mov rdx, [rsi+16] xor eax, eax mulx rbx, rcx, [rsi+24] adox rcx, [rdi+40] mov [rdi+40], rcx mulx rbp, rcx, [rsi+32] adcx rcx, rbx adox rcx, [rdi+48] mov [rdi+48], rcx mulx rbx, rcx, [rsi+40] adcx rcx, rbp adox rcx, [rdi+56] mov [rdi+56], rcx mulx rbp, rcx, [rsi+48] adcx rcx, rbx adox rcx, [rdi+64] mov [rdi+64], rcx mulx rbx, rcx, [rsi+56] adcx rcx, rbp adox rcx, [rdi+72] mov [rdi+72], rcx mov rcx, rax adcx rcx, rbx adox rcx, [rdi+80] mov [rdi+80], rcx mov rcx, rax adcx rcx, rcx adox rax, rax add rcx, rax add [rdi+88], rcx ; --- Row 3: a[3]*a[4..7] → P[7..11] --- mov rdx, [rsi+24] xor eax, eax mulx rbx, rcx, [rsi+32] adox rcx, [rdi+56] mov [rdi+56], rcx mulx rbp, rcx, [rsi+40] adcx rcx, rbx adox rcx, [rdi+64] mov [rdi+64], rcx mulx rbx, rcx, [rsi+48] adcx rcx, rbp adox rcx, [rdi+72] mov [rdi+72], rcx mulx rbp, rcx, [rsi+56] adcx rcx, rbx adox rcx, [rdi+80] mov [rdi+80], rcx mov rcx, rax adcx rcx, rbp adox rcx, [rdi+88] mov [rdi+88], rcx mov rcx, rax adcx rcx, rcx adox rax, rax add rcx, rax add [rdi+96], rcx ; --- Row 4: a[4]*a[5..7] → P[9..12] --- mov rdx, [rsi+32] xor eax, eax mulx rbx, rcx, [rsi+40] adox rcx, [rdi+72] mov [rdi+72], rcx mulx rbp, rcx, [rsi+48] adcx rcx, rbx adox rcx, [rdi+80] mov [rdi+80], rcx mulx rbx, rcx, [rsi+56] adcx rcx, rbp adox rcx, [rdi+88] mov [rdi+88], rcx mov rcx, rax adcx rcx, rbx adox rcx, [rdi+96] mov [rdi+96], rcx mov rcx, rax adcx rcx, rcx adox rax, rax add rcx, rax add [rdi+104], rcx ; --- Row 5: a[5]*a[6..7] → P[11..13] --- mov rdx, [rsi+40] xor eax, eax mulx rbx, rcx, [rsi+48] adox rcx, [rdi+88] mov [rdi+88], rcx mulx rbp, rcx, [rsi+56] adcx rcx, rbx adox rcx, [rdi+96] mov [rdi+96], rcx mov rcx, rax adcx rcx, rbp adox rcx, [rdi+104] mov [rdi+104], rcx mov rcx, rax adcx rcx, rcx adox rax, rax add rcx, rax add [rdi+112], rcx ; --- Row 6: a[6]*a[7] → P[13..14] (single product, add/adc) --- mov rdx, [rsi+48] mulx rbx, rcx, [rsi+56] add [rdi+104], rcx adc [rdi+112], rbx adc QWORD PTR [rdi+120], 0 ; ===== Phase 1b: doubling P[1..15] ===== ; P[0]=0 so skip, start a new carry chain at P[1] with add mov rax, [rdi+8] add rax, rax mov [rdi+8], rax mov rax, [rdi+16] adc rax, rax mov [rdi+16], rax mov rax, [rdi+24] adc rax, rax mov [rdi+24], rax mov rax, [rdi+32] adc rax, rax mov [rdi+32], rax mov rax, [rdi+40] adc rax, rax mov [rdi+40], rax mov rax, [rdi+48] adc rax, rax mov [rdi+48], rax mov rax, [rdi+56] adc rax, rax mov [rdi+56], rax mov rax, [rdi+64] adc rax, rax mov [rdi+64], rax mov rax, [rdi+72] adc rax, rax mov [rdi+72], rax mov rax, [rdi+80] adc rax, rax mov [rdi+80], rax mov rax, [rdi+88] adc rax, rax mov [rdi+88], rax mov rax, [rdi+96] adc rax, rax mov [rdi+96], rax mov rax, [rdi+104] adc rax, rax mov [rdi+104], rax mov rax, [rdi+112] adc rax, rax mov [rdi+112], rax mov rax, [rdi+120] adc rax, rax mov [rdi+120], rax ; carry → P[16] mov rax, 0 adc rax, 0 mov [rdi+128], rax ; ===== Phase 1c: diagonal terms a[i]^2 (adc chain) ===== mov rdx, [rsi] mulx rbx, rax, rdx add [rdi], rax adc [rdi+8], rbx mov rdx, [rsi+8] mulx rbx, rax, rdx adc [rdi+16], rax adc [rdi+24], rbx mov rdx, [rsi+16] mulx rbx, rax, rdx adc [rdi+32], rax adc [rdi+40], rbx mov rdx, [rsi+24] mulx rbx, rax, rdx adc [rdi+48], rax adc [rdi+56], rbx mov rdx, [rsi+32] mulx rbx, rax, rdx adc [rdi+64], rax adc [rdi+72], rbx mov rdx, [rsi+40] mulx rbx, rax, rdx adc [rdi+80], rax adc [rdi+88], rbx mov rdx, [rsi+48] mulx rbx, rax, rdx adc [rdi+96], rax adc [rdi+104], rbx mov rdx, [rsi+56] mulx rbx, rax, rdx adc [rdi+112], rax adc [rdi+120], rbx adc QWORD PTR [rdi+128], 0 ; ===== Phase 2: REDC (8 iterations) ===== mov r8, [rdi] mov r9, [rdi+8] mov r10, [rdi+16] mov r11, [rdi+24] mov r12, [rdi+32] mov r13, [rdi+40] mov r14, [rdi+48] mov r15, [rdi+56] mov rsi, [rsp+160] ; mp REDC_ITER 0 REDC_ITER 1 REDC_ITER 2 REDC_ITER 3 REDC_ITER 4 REDC_ITER 5 REDC_ITER 6 REDC_ITER 7 ; ===== Phase 3: conditional subtraction ===== mov rbx, [rsp+136] ; rp mov rsi, [rsp+160] ; mp mov rax, r8 sub rax, [rsi] mov [rbx], rax mov rax, r9 sbb rax, [rsi+8] mov [rbx+8], rax mov rax, r10 sbb rax, [rsi+16] mov [rbx+16], rax mov rax, r11 sbb rax, [rsi+24] mov [rbx+24], rax mov rax, r12 sbb rax, [rsi+32] mov [rbx+32], rax mov rax, r13 sbb rax, [rsi+40] mov [rbx+40], rax mov rax, r14 sbb rax, [rsi+48] mov [rbx+48], rax mov rax, r15 sbb rax, [rsi+56] mov [rbx+56], rax ; account for P[16] overflow mov rax, [rdi+128] sbb rax, 0 jnc s8_done ; borrow → subtraction result invalid, copy original result to rp mov [rbx], r8 mov [rbx+8], r9 mov [rbx+16], r10 mov [rbx+24], r11 mov [rbx+32], r12 mov [rbx+40], r13 mov [rbx+48], r14 mov [rbx+56], r15 s8_done: add rsp, 184 pop rbp pop r15 pop r14 pop r13 pop r12 pop rdi pop rsi pop rbx ret mpn_mont_sqr_8 ENDP ; ===================================================================== ; void mpn_mont_redc_16(uint64_t* rp, uint64_t* tp, ; const uint64_t* mp, uint64_t m_inv) ; ; n=16 specialized Montgomery REDC: rp = tp * R^{-1} mod mp ; tp[0..32] is 33 words (2*16+1), destroyed ; optimized for 1024-bit modulus ; ; rcx = rp, rdx = tp, r8 = mp, r9 = m_inv ; ; Optimizations: ; - 16-word addmul fully unrolled (no pointer advance, fixed offsets) ; - rsi = mp register-resident (no reload across 16 iterations) ; - r8 = 0 constant register-resident ; - stack reads per iteration: m_inv only, once ; ===================================================================== mpn_mont_redc_16 PROC push rbx push rsi push rdi push r12 push r13 push r14 push r15 push rbp sub rsp, 32 ; Stack layout: ; 8 push × 8 = 64, sub 32 → total = 96 ; [rsp+0] = rp ; [rsp+8] = m_inv ; [rsp+16] = tp_end (&tp[16], loop termination check) ; [rsp+24] = &tp[32] (carry propagation upper bound) mov [rsp+0], rcx mov [rsp+8], r9 mov rsi, r8 ; rsi = mp (register-resident during loop) mov rbp, rdx ; rbp = &tp[i] (advances by +8 in loop) lea rax, [rdx + 128] mov [rsp+16], rax ; tp_end = &tp[16] lea rax, [rdx + 256] mov [rsp+24], rax ; &tp[32] xor r8d, r8d ; r8 = 0 (kept across the whole loop) r16_outer: ; q = tp[i] * m_inv mov rax, [rbp] imul rax, QWORD PTR [rsp+8] mov rdx, rax ; q → MULX multiplier mov rbx, rbp ; rbx = &tp[i] (dest) xor r9d, r9d ; carry_in = 0 ; === 16-word addmul (4 blocks × 4 words, ADCX/ADOX) === ; Block 0: mp[0..3] * q + tp[i..i+3] xor eax, eax ; CF=0, OF=0 mulx r10, r11, [rsi] mulx r12, r13, [rsi+8] mulx r14, r15, [rsi+16] mulx rdi, rax, [rsi+24] adcx r11, r9 adox r11, [rbx] mov [rbx], r11 adcx r13, r10 adox r13, [rbx+8] mov [rbx+8], r13 adcx r15, r12 adox r15, [rbx+16] mov [rbx+16], r15 adcx rax, r14 adox rax, [rbx+24] mov [rbx+24], rax mov r9, rdi adcx r9, r8 adox r9, r8 ; Block 1: mp[4..7] * q + tp[i+4..i+7] xor eax, eax mulx r10, r11, [rsi+32] mulx r12, r13, [rsi+40] mulx r14, r15, [rsi+48] mulx rdi, rax, [rsi+56] adcx r11, r9 adox r11, [rbx+32] mov [rbx+32], r11 adcx r13, r10 adox r13, [rbx+40] mov [rbx+40], r13 adcx r15, r12 adox r15, [rbx+48] mov [rbx+48], r15 adcx rax, r14 adox rax, [rbx+56] mov [rbx+56], rax mov r9, rdi adcx r9, r8 adox r9, r8 ; Block 2: mp[8..11] * q + tp[i+8..i+11] xor eax, eax mulx r10, r11, [rsi+64] mulx r12, r13, [rsi+72] mulx r14, r15, [rsi+80] mulx rdi, rax, [rsi+88] adcx r11, r9 adox r11, [rbx+64] mov [rbx+64], r11 adcx r13, r10 adox r13, [rbx+72] mov [rbx+72], r13 adcx r15, r12 adox r15, [rbx+80] mov [rbx+80], r15 adcx rax, r14 adox rax, [rbx+88] mov [rbx+88], rax mov r9, rdi adcx r9, r8 adox r9, r8 ; Block 3: mp[12..15] * q + tp[i+12..i+15] xor eax, eax mulx r10, r11, [rsi+96] mulx r12, r13, [rsi+104] mulx r14, r15, [rsi+112] mulx rdi, rax, [rsi+120] adcx r11, r9 adox r11, [rbx+96] mov [rbx+96], r11 adcx r13, r10 adox r13, [rbx+104] mov [rbx+104], r13 adcx r15, r12 adox r15, [rbx+112] mov [rbx+112], r15 adcx rax, r14 adox rax, [rbx+120] mov [rbx+120], rax mov r9, rdi adcx r9, r8 adox r9, r8 ; === carry propagation: tp[i+16] += r9 === add [rbp + 128], r9 jnc r16_nc lea rax, [rbp + 136] ; &tp[i+17] mov rcx, [rsp+24] ; &tp[32] r16_carry: cmp rax, rcx ja r16_nc add QWORD PTR [rax], 1 lea rax, [rax + 8] jc r16_carry r16_nc: lea rbp, [rbp + 8] ; tp[i] → tp[i+1] cmp rbp, [rsp+16] ; tp_end jb r16_outer ; === Conditional subtraction: tp[16..31] - mp → rp === ; rbp = &tp[16] (at loop end), rsi = mp mov rbx, [rsp+0] ; rp mov rax, [rbp] sub rax, [rsi] mov [rbx], rax mov rax, [rbp+8] sbb rax, [rsi+8] mov [rbx+8], rax mov rax, [rbp+16] sbb rax, [rsi+16] mov [rbx+16], rax mov rax, [rbp+24] sbb rax, [rsi+24] mov [rbx+24], rax mov rax, [rbp+32] sbb rax, [rsi+32] mov [rbx+32], rax mov rax, [rbp+40] sbb rax, [rsi+40] mov [rbx+40], rax mov rax, [rbp+48] sbb rax, [rsi+48] mov [rbx+48], rax mov rax, [rbp+56] sbb rax, [rsi+56] mov [rbx+56], rax mov rax, [rbp+64] sbb rax, [rsi+64] mov [rbx+64], rax mov rax, [rbp+72] sbb rax, [rsi+72] mov [rbx+72], rax mov rax, [rbp+80] sbb rax, [rsi+80] mov [rbx+80], rax mov rax, [rbp+88] sbb rax, [rsi+88] mov [rbx+88], rax mov rax, [rbp+96] sbb rax, [rsi+96] mov [rbx+96], rax mov rax, [rbp+104] sbb rax, [rsi+104] mov [rbx+104], rax mov rax, [rbp+112] sbb rax, [rsi+112] mov [rbx+112], rax mov rax, [rbp+120] sbb rax, [rsi+120] mov [rbx+120], rax ; tp[32] - borrow mov rax, [rbp+128] sbb rax, 0 jnc r16_done ; borrow → copy tp[16..31] verbatim to rp mov rax, [rbp] mov [rbx], rax mov rax, [rbp+8] mov [rbx+8], rax mov rax, [rbp+16] mov [rbx+16], rax mov rax, [rbp+24] mov [rbx+24], rax mov rax, [rbp+32] mov [rbx+32], rax mov rax, [rbp+40] mov [rbx+40], rax mov rax, [rbp+48] mov [rbx+48], rax mov rax, [rbp+56] mov [rbx+56], rax mov rax, [rbp+64] mov [rbx+64], rax mov rax, [rbp+72] mov [rbx+72], rax mov rax, [rbp+80] mov [rbx+80], rax mov rax, [rbp+88] mov [rbx+88], rax mov rax, [rbp+96] mov [rbx+96], rax mov rax, [rbp+104] mov [rbx+104], rax mov rax, [rbp+112] mov [rbx+112], rax mov rax, [rbp+120] mov [rbx+120], rax r16_done: add rsp, 32 pop rbp pop r15 pop r14 pop r13 pop r12 pop rdi pop rsi pop rbx ret mpn_mont_redc_16 ENDP ; ===================================================================== ; void mpn_mont_redc_32(uint64_t* rp, uint64_t* tp, ; const uint64_t* mp, uint64_t m_inv) ; ; n=32 specialized Montgomery REDC: rp = tp * R^{-1} mod mp ; tp[0..64] is 65 words (2*32+1), destroyed ; optimized for 2048-bit modulus ; ; rcx = rp, rdx = tp, r8 = mp, r9 = m_inv ; ; Optimizations: ; - 32-word addmul fully unrolled with ADDMUL_BLOCK_4 × 8 blocks ; - rsi = mp register-resident, r8 = 0 constant ; - conditional subtraction is the loop version (full unroll of 32 words is redundant) ; ===================================================================== mpn_mont_redc_32 PROC push rbx push rsi push rdi push r12 push r13 push r14 push r15 push rbp sub rsp, 32 ; Stack layout: ; [rsp+0] = rp ; [rsp+8] = m_inv ; [rsp+16] = tp_end (&tp[32]) ; [rsp+24] = &tp[64] (carry propagation upper bound) mov [rsp+0], rcx mov [rsp+8], r9 mov rsi, r8 ; rsi = mp (register-resident) mov rbp, rdx ; rbp = &tp[i] lea rax, [rdx + 256] mov [rsp+16], rax ; tp_end = &tp[32] lea rax, [rdx + 512] mov [rsp+24], rax ; &tp[64] xor r8d, r8d ; r8 = 0 r32_outer: ; q = tp[i] * m_inv mov rax, [rbp] imul rax, QWORD PTR [rsp+8] mov rdx, rax mov rbx, rbp xor r9d, r9d ; === 32-word addmul (8 blocks × 4 words) === ADDMUL_BLOCK_4 0 ADDMUL_BLOCK_4 32 ADDMUL_BLOCK_4 64 ADDMUL_BLOCK_4 96 ADDMUL_BLOCK_4 128 ADDMUL_BLOCK_4 160 ADDMUL_BLOCK_4 192 ADDMUL_BLOCK_4 224 ; === carry propagation: tp[i+32] += r9 === add [rbp + 256], r9 jnc r32_nc lea rax, [rbp + 264] mov rcx, [rsp+24] r32_carry: cmp rax, rcx ja r32_nc add QWORD PTR [rax], 1 lea rax, [rax + 8] jc r32_carry r32_nc: lea rbp, [rbp + 8] cmp rbp, [rsp+16] jb r32_outer ; === Conditional subtraction: tp[32..63] - mp → rp (loop version) === ; rbp = &tp[32], rsi = mp mov rbx, [rsp+0] ; rp mov rcx, 32 ; n xor r9d, r9d ; index ; first 1 word: sub mov rax, [rbp] sub rax, [rsi] mov [rbx], rax inc r9 r32_sub: mov rax, [rbp + r9*8] sbb rax, [rsi + r9*8] mov [rbx + r9*8], rax inc r9 cmp r9, rcx jb r32_sub ; tp[64] - borrow mov rax, [rbp + 256] sbb rax, 0 jnc r32_done ; borrow → copy tp[32..63] verbatim to rp xor r9d, r9d r32_copy: mov rax, [rbp + r9*8] mov [rbx + r9*8], rax inc r9 cmp r9, rcx jb r32_copy r32_done: add rsp, 32 pop rbp pop r15 pop r14 pop r13 pop r12 pop rdi pop rsi pop rbx ret mpn_mont_redc_32 ENDP ; ===================================================================== ; void mpn_mont_sqr_16(uint64_t* rp, const uint64_t* ap, ; const uint64_t* mp, uint64_t m_inv) ; ; n=16 fused SOS Montgomery squaring: rp = ap^2 * R^{-1} mod mp ; 1024-bit specialized, exploits symmetry (120+16=136 MULX for sqr, 256 MULX for REDC) ; ; rcx = rp, rdx = ap, r8 = mp, r9 = m_inv ; ; Phase 1a: upper-triangle multiplication (120 MULX, hand-unrolled ADCX/ADOX) ; Phase 1b: doubling (P[1..31] <<= 1) ; Phase 1c: add diagonal terms a[i]^2 ; Phase 2: REDC 16 iterations (ADDMUL_BLOCK_4 × 4) ; Phase 3: conditional subtraction ; ===================================================================== mpn_mont_sqr_16 PROC push rbx push rsi push rdi push r12 push r13 push r14 push r15 push rbp sub rsp, 328 ; Stack layout: ; [rsp+0..263] = P[0..32] product buffer (33 qwords) ; [rsp+264] = rp ; [rsp+272] = ap ; [rsp+280] = mp ; [rsp+288] = m_inv mov [rsp+264], rcx mov [rsp+272], rdx mov [rsp+280], r8 mov [rsp+288], r9 ; --- Zero P[0..32] (33 qwords) --- xor eax, eax lea rdi, [rsp] _s16z = 0 REPEAT 33 mov QWORD PTR [rdi+_s16z], rax _s16z = _s16z + 8 ENDM ; ===== Phase 1a: Upper triangle (120 MULX, hand-unrolled) ===== mov rsi, [rsp+272] ; rsi = ap ; --- Row 0: a[0]*a[1..15] → P[1..16] (mul_1, ADC chain) --- mov rdx, [rsi] mulx rbx, rcx, [rsi+8] mov [rsp+8], rcx mulx rbp, rcx, [rsi+16] add rcx, rbx mov [rsp+16], rcx _s16k = 2 WHILE _s16k LE 13 _s16_off = (_s16k + 1) * 8 IF (_s16k AND 1) mulx rbp, rcx, [rsi + _s16_off] adc rcx, rbx ELSE mulx rbx, rcx, [rsi + _s16_off] adc rcx, rbp ENDIF mov [rsp + _s16_off], rcx _s16k = _s16k + 1 ENDM mulx rbx, rcx, [rsi + 120] adc rcx, rbp mov [rsp + 120], rcx adc rbx, 0 mov [rsp + 128], rbx ; --- Rows 1..13: a[i]*a[i+1..15] (ADCX/ADOX dual carry chain) --- _s16i = 1 WHILE _s16i LE 13 _s16n = 15 - _s16i mov rdx, [rsi + _s16i*8] xor eax, eax _s16_src = (_s16i + 1) * 8 _s16_dst = (2 * _s16i + 1) * 8 mulx rbx, rcx, [rsi + _s16_src] adox rcx, [rsp + _s16_dst] mov [rsp + _s16_dst], rcx _s16j = 1 WHILE _s16j LT _s16n _s16_src = (_s16i + 1 + _s16j) * 8 _s16_dst = (2 * _s16i + 1 + _s16j) * 8 IF (_s16j AND 1) mulx rbp, rcx, [rsi + _s16_src] adcx rcx, rbx ELSE mulx rbx, rcx, [rsi + _s16_src] adcx rcx, rbp ENDIF adox rcx, [rsp + _s16_dst] mov [rsp + _s16_dst], rcx _s16j = _s16j + 1 ENDM _s16_tail = (_s16i + 16) * 8 mov rcx, rax IF ((_s16n - 1) AND 1) adcx rcx, rbp ELSE adcx rcx, rbx ENDIF adox rcx, [rsp + _s16_tail] mov [rsp + _s16_tail], rcx mov rcx, rax adcx rcx, rcx adox rax, rax add rcx, rax add [rsp + _s16_tail + 8], rcx _s16i = _s16i + 1 ENDM ; --- Row 14: a[14]*a[15] → P[29..31] (1 MULX, add/adc) --- mov rdx, [rsi+112] mulx rbx, rcx, [rsi+120] add [rsp+232], rcx adc [rsp+240], rbx adc QWORD PTR [rsp+248], 0 ; ===== Phase 1b: Double P[1..31] ===== mov rax, [rsp+8] ; P[1] add rax, rax mov [rsp+8], rax _s16d = 16 REPEAT 30 mov rax, [rsp+_s16d] adc rax, rax mov [rsp+_s16d], rax _s16d = _s16d + 8 ENDM ; carry → P[32] mov rax, 0 adc rax, 0 add [rsp+256], rax ; ===== Phase 1c: Diagonal a[i]^2 (16 MULX, adc chain) ===== mov rcx, [rsp+272] ; ap mov rdx, [rcx] mulx rbx, rax, rdx add [rsp], rax adc [rsp+8], rbx mov rdx, [rcx+8] mulx rbx, rax, rdx adc [rsp+16], rax adc [rsp+24], rbx mov rdx, [rcx+16] mulx rbx, rax, rdx adc [rsp+32], rax adc [rsp+40], rbx mov rdx, [rcx+24] mulx rbx, rax, rdx adc [rsp+48], rax adc [rsp+56], rbx mov rdx, [rcx+32] mulx rbx, rax, rdx adc [rsp+64], rax adc [rsp+72], rbx mov rdx, [rcx+40] mulx rbx, rax, rdx adc [rsp+80], rax adc [rsp+88], rbx mov rdx, [rcx+48] mulx rbx, rax, rdx adc [rsp+96], rax adc [rsp+104], rbx mov rdx, [rcx+56] mulx rbx, rax, rdx adc [rsp+112], rax adc [rsp+120], rbx mov rdx, [rcx+64] mulx rbx, rax, rdx adc [rsp+128], rax adc [rsp+136], rbx mov rdx, [rcx+72] mulx rbx, rax, rdx adc [rsp+144], rax adc [rsp+152], rbx mov rdx, [rcx+80] mulx rbx, rax, rdx adc [rsp+160], rax adc [rsp+168], rbx mov rdx, [rcx+88] mulx rbx, rax, rdx adc [rsp+176], rax adc [rsp+184], rbx mov rdx, [rcx+96] mulx rbx, rax, rdx adc [rsp+192], rax adc [rsp+200], rbx mov rdx, [rcx+104] mulx rbx, rax, rdx adc [rsp+208], rax adc [rsp+216], rbx mov rdx, [rcx+112] mulx rbx, rax, rdx adc [rsp+224], rax adc [rsp+232], rbx mov rdx, [rcx+120] mulx rbx, rax, rdx adc [rsp+240], rax adc [rsp+248], rbx adc QWORD PTR [rsp+256], 0 ; P[32] final carry ; ===== Phase 2: REDC (16 iterations) ===== mov rsi, [rsp+280] ; mp (register-resident) lea rbp, [rsp] ; rbp = &P[i], starts at &P[0] xor r8d, r8d ; r8 = 0 constant s16_redc_outer: mov rax, [rbp] imul rax, QWORD PTR [rsp+288] ; q = P[i] * m_inv mov rdx, rax mov rbx, rbp ; dest = &P[i] xor r9d, r9d ; carry_in = 0 ; Block 0: mp[0..3] * q + P[i..i+3] xor eax, eax mulx r10, r11, [rsi] mulx r12, r13, [rsi+8] mulx r14, r15, [rsi+16] mulx rdi, rax, [rsi+24] adcx r11, r9 adox r11, [rbx] mov [rbx], r11 adcx r13, r10 adox r13, [rbx+8] mov [rbx+8], r13 adcx r15, r12 adox r15, [rbx+16] mov [rbx+16], r15 adcx rax, r14 adox rax, [rbx+24] mov [rbx+24], rax mov r9, rdi adcx r9, r8 adox r9, r8 ; Block 1: mp[4..7] * q + P[i+4..i+7] xor eax, eax mulx r10, r11, [rsi+32] mulx r12, r13, [rsi+40] mulx r14, r15, [rsi+48] mulx rdi, rax, [rsi+56] adcx r11, r9 adox r11, [rbx+32] mov [rbx+32], r11 adcx r13, r10 adox r13, [rbx+40] mov [rbx+40], r13 adcx r15, r12 adox r15, [rbx+48] mov [rbx+48], r15 adcx rax, r14 adox rax, [rbx+56] mov [rbx+56], rax mov r9, rdi adcx r9, r8 adox r9, r8 ; Block 2: mp[8..11] * q + P[i+8..i+11] xor eax, eax mulx r10, r11, [rsi+64] mulx r12, r13, [rsi+72] mulx r14, r15, [rsi+80] mulx rdi, rax, [rsi+88] adcx r11, r9 adox r11, [rbx+64] mov [rbx+64], r11 adcx r13, r10 adox r13, [rbx+72] mov [rbx+72], r13 adcx r15, r12 adox r15, [rbx+80] mov [rbx+80], r15 adcx rax, r14 adox rax, [rbx+88] mov [rbx+88], rax mov r9, rdi adcx r9, r8 adox r9, r8 ; Block 3: mp[12..15] * q + P[i+12..i+15] xor eax, eax mulx r10, r11, [rsi+96] mulx r12, r13, [rsi+104] mulx r14, r15, [rsi+112] mulx rdi, rax, [rsi+120] adcx r11, r9 adox r11, [rbx+96] mov [rbx+96], r11 adcx r13, r10 adox r13, [rbx+104] mov [rbx+104], r13 adcx r15, r12 adox r15, [rbx+112] mov [rbx+112], r15 adcx rax, r14 adox rax, [rbx+120] mov [rbx+120], rax mov r9, rdi adcx r9, r8 adox r9, r8 ; carry → P[i+16] add [rbp + 128], r9 jnc s16_redc_nc lea rax, [rbp + 136] lea rcx, [rsp + 256] ; &P[32] s16_redc_carry: cmp rax, rcx ja s16_redc_nc add QWORD PTR [rax], 1 lea rax, [rax + 8] jc s16_redc_carry s16_redc_nc: lea rbp, [rbp + 8] lea rax, [rsp + 128] ; &P[16] cmp rbp, rax jb s16_redc_outer ; ===== Phase 3: Conditional subtraction ===== ; rbp = rsp + 128 = &P[16] mov rbx, [rsp+264] ; rp ; rsi = mp (still loaded) mov rax, [rbp] sub rax, [rsi] mov [rbx], rax _s16s = 8 REPEAT 15 mov rax, [rbp+_s16s] sbb rax, [rsi+_s16s] mov [rbx+_s16s], rax _s16s = _s16s + 8 ENDM ; P[32] - borrow mov rax, [rbp+128] sbb rax, 0 jnc s16_sqr_done ; borrow → copy P[16..31] verbatim to rp _s16c = 0 REPEAT 16 mov rax, [rbp+_s16c] mov [rbx+_s16c], rax _s16c = _s16c + 8 ENDM s16_sqr_done: add rsp, 328 pop rbp pop r15 pop r14 pop r13 pop r12 pop rdi pop rsi pop rbx ret mpn_mont_sqr_16 ENDP ; ===================================================================== ; n=4 specialized macros (256-bit Montgomery) ; ; ADDMUL_FIRST_4 / ADDMUL_REST_4: register-resident 4-word addmul ; Accumulator: r8, r9, r10, r11 ; rdx = multiplier, rsi = source, rax = 0 constant (xor'd in FIRST) ; rbx, rbp = MULX hi/lo temporaries ; ===================================================================== ADDMUL_FIRST_4 MACRO xor eax, eax mulx rbx, rbp, [rsi] adox r8, rbp ENDM ADDMUL_REST_4 MACRO adcx r9, rbx mulx rbp, r8, [rsi+8] adox r8, r9 adcx r10, rbp mulx rbx, r9, [rsi+16] adox r9, r10 adcx r11, rbx mulx rbp, r10, [rsi+24] adox r10, r11 mov r11, rax adcx r11, rbp adox r11, rax ENDM REDC_ITER_4 MACRO iter_idx LOCAL ri_nc mov rax, r8 imul rax, QWORD PTR [rsp+88] mov rdx, rax ADDMUL_FIRST_4 ADDMUL_REST_4 add r11, QWORD PTR [rdi + (4 + iter_idx)*8] jnc ri_nc _prop_idx = 5 + iter_idx WHILE _prop_idx LE 8 add QWORD PTR [rdi + _prop_idx*8], 1 jnc ri_nc _prop_idx = _prop_idx + 1 ENDM ri_nc: ENDM ; ===================================================================== ; void mpn_mont_mul_4(uint64_t* rp, const uint64_t* ap, ; const uint64_t* bp, const uint64_t* mp, ; uint64_t m_inv) ; ; register-resident n=4 SOS Montgomery multiplication: rp = ap * bp * R^{-1} mod mp ; 256-bit specialized, register-resident accumulator scheme like n=8 ; ; rcx = rp, rdx = ap, r8 = bp, r9 = mp ; [rsp+176] = m_inv (5th arg, after 4 pushes + sub 104) ; ; Phase 1: 4×4 full multiplication (SOS, 16 MULX) ; Phase 2: REDC 4 iterations (16 MULX) ; Phase 3: conditional subtraction ; ===================================================================== mpn_mont_mul_4 PROC push rbx push rbp push rsi push rdi sub rsp, 104 ; Stack layout: ; 4 push × 8 = 32, sub 104 → total = 136 ; 5th arg (m_inv): [rsp + 136 + 40] = [rsp + 176] ; ; [rsp+0..71] = P[0..8] product buffer (9 qwords) ; [rsp+72] = rp ; [rsp+80] = mp ; [rsp+88] = m_inv mov [rsp+72], rcx mov rsi, rdx ; rsi = ap mov rcx, r8 ; rcx = bp mov [rsp+80], r9 ; mp mov rax, [rsp+176] mov [rsp+88], rax ; m_inv mov rdi, rsp ; product buffer ; ===== Phase 1: 4×4 full multiplication (SOS) ===== xor r8d, r8d xor r9d, r9d xor r10d, r10d xor r11d, r11d ; Row 0: b[0] mov rdx, [rcx] ADDMUL_FIRST_4 mov QWORD PTR [rdi], r8 ADDMUL_REST_4 ; Row 1: b[1] mov rdx, [rcx+8] ADDMUL_FIRST_4 mov QWORD PTR [rdi+8], r8 ADDMUL_REST_4 ; Row 2: b[2] mov rdx, [rcx+16] ADDMUL_FIRST_4 mov QWORD PTR [rdi+16], r8 ADDMUL_REST_4 ; Row 3: b[3] mov rdx, [rcx+24] ADDMUL_FIRST_4 mov QWORD PTR [rdi+24], r8 ADDMUL_REST_4 ; P[4..7] ← accumulator, P[8] = 0 mov [rdi+32], r8 mov [rdi+40], r9 mov [rdi+48], r10 mov [rdi+56], r11 mov QWORD PTR [rdi+64], 0 ; ===== Phase 2: REDC (4 iterations) ===== mov r8, [rdi] mov r9, [rdi+8] mov r10, [rdi+16] mov r11, [rdi+24] mov rsi, [rsp+80] ; mp REDC_ITER_4 0 REDC_ITER_4 1 REDC_ITER_4 2 REDC_ITER_4 3 ; ===== Phase 3: conditional subtraction ===== mov rbx, [rsp+72] ; rp mov rsi, [rsp+80] ; mp mov rax, r8 sub rax, [rsi] mov [rbx], rax mov rax, r9 sbb rax, [rsi+8] mov [rbx+8], rax mov rax, r10 sbb rax, [rsi+16] mov [rbx+16], rax mov rax, r11 sbb rax, [rsi+24] mov [rbx+24], rax ; account for P[8] overflow mov rax, [rdi+64] sbb rax, 0 jnc m4_done ; borrow → subtraction result invalid mov [rbx], r8 mov [rbx+8], r9 mov [rbx+16], r10 mov [rbx+24], r11 m4_done: add rsp, 104 pop rdi pop rsi pop rbp pop rbx ret mpn_mont_mul_4 ENDP ; ===================================================================== ; void mpn_mont_sqr_4(uint64_t* rp, const uint64_t* ap, ; const uint64_t* mp, uint64_t m_inv) ; ; register-resident n=4 fused SQR+REDC: rp = ap^2 * R^{-1} mod mp ; 256-bit specialized, exploits symmetry (6+4=10 MULX vs 16 MULX for multiplication) ; ; rcx = rp, rdx = ap, r8 = mp, r9 = m_inv ; ; Phase 1a: upper-triangle multiplication (off-diagonal, 6 MULX) ; Phase 1b: doubling (P[1..7] <<= 1) ; Phase 1c: add diagonal terms a[i]^2 (4 MULX) ; Phase 2: REDC 4 iterations (REDC_ITER_4 macro) ; Phase 3: conditional subtraction ; ===================================================================== mpn_mont_sqr_4 PROC push rbx push rbp push rsi push rdi sub rsp, 104 ; Stack layout (same as mont_mul_4): ; [rsp+0..71] = P[0..8] product buffer (9 qwords) ; [rsp+72] = rp ; [rsp+80] = mp ; [rsp+88] = m_inv mov [rsp+72], rcx ; rp mov rsi, rdx ; rsi = ap mov [rsp+80], r8 ; mp mov [rsp+88], r9 ; m_inv mov rdi, rsp ; product buffer ; --- Zero P[0..8] --- xor eax, eax mov [rdi], rax mov [rdi+8], rax mov [rdi+16], rax mov [rdi+24], rax mov [rdi+32], rax mov [rdi+40], rax mov [rdi+48], rax mov [rdi+56], rax mov [rdi+64], rax ; ===== Phase 1a: Off-diagonal upper triangle (6 MULX) ===== ; --- Row 0: a[0]*a[1..3] → P[1..4] --- mov rdx, [rsi] mulx rbx, rcx, [rsi+8] mov [rdi+8], rcx mulx rbp, rcx, [rsi+16] add rcx, rbx mov [rdi+16], rcx mulx rbx, rcx, [rsi+24] adc rcx, rbp mov [rdi+24], rcx adc rbx, 0 mov [rdi+32], rbx ; --- Row 1: a[1]*a[2..3] → P[3..5] (ADCX/ADOX) --- mov rdx, [rsi+8] xor eax, eax mulx rbx, rcx, [rsi+16] adox rcx, [rdi+24] mov [rdi+24], rcx mulx rbp, rcx, [rsi+24] adcx rcx, rbx adox rcx, [rdi+32] mov [rdi+32], rcx mov rcx, rax adcx rcx, rbp adox rcx, [rdi+40] mov [rdi+40], rcx ; residual CF+OF → P[6] mov rcx, rax adcx rcx, rcx adox rax, rax add rcx, rax add [rdi+48], rcx ; --- Row 2: a[2]*a[3] → P[5..6] (single product, add/adc) --- mov rdx, [rsi+16] mulx rbx, rcx, [rsi+24] add [rdi+40], rcx adc [rdi+48], rbx adc QWORD PTR [rdi+56], 0 ; ===== Phase 1b: doubling P[1..7] ===== mov rax, [rdi+8] add rax, rax mov [rdi+8], rax mov rax, [rdi+16] adc rax, rax mov [rdi+16], rax mov rax, [rdi+24] adc rax, rax mov [rdi+24], rax mov rax, [rdi+32] adc rax, rax mov [rdi+32], rax mov rax, [rdi+40] adc rax, rax mov [rdi+40], rax mov rax, [rdi+48] adc rax, rax mov [rdi+48], rax mov rax, [rdi+56] adc rax, rax mov [rdi+56], rax ; carry → P[8] mov rax, 0 adc rax, 0 mov [rdi+64], rax ; ===== Phase 1c: add diagonal terms a[i]^2 ===== mov rdx, [rsi] mulx rbx, rax, rdx add [rdi], rax adc [rdi+8], rbx mov rdx, [rsi+8] mulx rbx, rax, rdx adc [rdi+16], rax adc [rdi+24], rbx mov rdx, [rsi+16] mulx rbx, rax, rdx adc [rdi+32], rax adc [rdi+40], rbx mov rdx, [rsi+24] mulx rbx, rax, rdx adc [rdi+48], rax adc [rdi+56], rbx adc QWORD PTR [rdi+64], 0 ; ===== Phase 2: REDC (4 iterations) ===== mov r8, [rdi] mov r9, [rdi+8] mov r10, [rdi+16] mov r11, [rdi+24] mov rsi, [rsp+80] ; mp REDC_ITER_4 0 REDC_ITER_4 1 REDC_ITER_4 2 REDC_ITER_4 3 ; ===== Phase 3: conditional subtraction ===== mov rbx, [rsp+72] ; rp mov rsi, [rsp+80] ; mp mov rax, r8 sub rax, [rsi] mov [rbx], rax mov rax, r9 sbb rax, [rsi+8] mov [rbx+8], rax mov rax, r10 sbb rax, [rsi+16] mov [rbx+16], rax mov rax, r11 sbb rax, [rsi+24] mov [rbx+24], rax ; account for P[8] overflow mov rax, [rdi+64] sbb rax, 0 jnc s4_done ; borrow → subtraction result invalid mov [rbx], r8 mov [rbx+8], r9 mov [rbx+16], r10 mov [rbx+24], r11 s4_done: add rsp, 104 pop rdi pop rsi pop rbp pop rbx ret mpn_mont_sqr_4 ENDP ; ===================================================================== ; n=3 specialized macros (192-bit Montgomery) ; ; ADDMUL_FIRST_3 / ADDMUL_REST_3: register-resident 3-word addmul ; Accumulator: r8, r9, r10 ; rdx = multiplier, rsi = source, rax = 0 constant (xor'd in FIRST) ; rbx, rbp = MULX hi/lo temporaries ; ===================================================================== ADDMUL_FIRST_3 MACRO xor eax, eax mulx rbx, rbp, [rsi] adox r8, rbp ENDM ADDMUL_REST_3 MACRO adcx r9, rbx mulx rbp, r8, [rsi+8] adox r8, r9 adcx r10, rbp mulx rbx, r9, [rsi+16] adox r9, r10 mov r10, rax adcx r10, rbx adox r10, rax ENDM REDC_ITER_3 MACRO iter_idx LOCAL ri_nc mov rax, r8 imul rax, QWORD PTR [rsp+72] mov rdx, rax ADDMUL_FIRST_3 ADDMUL_REST_3 add r10, QWORD PTR [rdi + (3 + iter_idx)*8] jnc ri_nc _prop_idx = 4 + iter_idx WHILE _prop_idx LE 6 add QWORD PTR [rdi + _prop_idx*8], 1 jnc ri_nc _prop_idx = _prop_idx + 1 ENDM ri_nc: ENDM ; ===================================================================== ; void mpn_mont_mul_3(uint64_t* rp, const uint64_t* ap, ; const uint64_t* bp, const uint64_t* mp, ; uint64_t m_inv) ; ; register-resident n=3 SOS Montgomery multiplication: rp = ap * bp * R^{-1} mod mp ; 192-bit specialized, extension of the same structure as n=2/n=4 ; ; rcx = rp, rdx = ap, r8 = bp, r9 = mp ; [rsp+160] = m_inv (5th arg, after 4 pushes + sub 88) ; ; Phase 1: 3×3 full multiplication (SOS, 9 MULX) ; Phase 2: REDC 3 iterations (9 MULX) ; Phase 3: conditional subtraction ; ===================================================================== mpn_mont_mul_3 PROC push rbx push rbp push rsi push rdi sub rsp, 88 ; Stack layout: ; 4 push × 8 = 32, sub 88 → total = 120 ; 5th arg (m_inv): [rsp + 120 + 40] = [rsp + 160] ; ; [rsp+0..55] = P[0..6] product buffer (7 qwords) ; [rsp+56] = rp ; [rsp+64] = mp ; [rsp+72] = m_inv ; [rsp+80..87] = padding (8 bytes) mov [rsp+56], rcx mov rsi, rdx ; rsi = ap mov rcx, r8 ; rcx = bp mov [rsp+64], r9 ; mp mov rax, [rsp+160] mov [rsp+72], rax ; m_inv mov rdi, rsp ; product buffer ; ===== Phase 1: 3×3 full multiplication (SOS) ===== xor r8d, r8d xor r9d, r9d xor r10d, r10d ; Row 0: b[0] mov rdx, [rcx] ADDMUL_FIRST_3 mov QWORD PTR [rdi], r8 ADDMUL_REST_3 ; Row 1: b[1] mov rdx, [rcx+8] ADDMUL_FIRST_3 mov QWORD PTR [rdi+8], r8 ADDMUL_REST_3 ; Row 2: b[2] mov rdx, [rcx+16] ADDMUL_FIRST_3 mov QWORD PTR [rdi+16], r8 ADDMUL_REST_3 ; P[3..5] ← accumulator, P[6] = 0 mov [rdi+24], r8 mov [rdi+32], r9 mov [rdi+40], r10 mov QWORD PTR [rdi+48], 0 ; ===== Phase 2: REDC (3 iterations) ===== mov r8, [rdi] mov r9, [rdi+8] mov r10, [rdi+16] mov rsi, [rsp+64] ; mp REDC_ITER_3 0 REDC_ITER_3 1 REDC_ITER_3 2 ; ===== Phase 3: conditional subtraction ===== mov rbx, [rsp+56] ; rp mov rsi, [rsp+64] ; mp mov rax, r8 sub rax, [rsi] mov [rbx], rax mov rax, r9 sbb rax, [rsi+8] mov [rbx+8], rax mov rax, r10 sbb rax, [rsi+16] mov [rbx+16], rax ; account for P[6] overflow mov rax, [rdi+48] sbb rax, 0 jnc m3_done ; borrow → subtraction result invalid mov [rbx], r8 mov [rbx+8], r9 mov [rbx+16], r10 m3_done: add rsp, 88 pop rdi pop rsi pop rbp pop rbx ret mpn_mont_mul_3 ENDP ; ===================================================================== ; n=2 specialized macros (128-bit Montgomery) ; ; ADDMUL_FIRST_2 / ADDMUL_REST_2: register-resident 2-word addmul ; Accumulator: r8, r9 ; rdx = multiplier, rsi = source, rax = 0 constant (xor'd in FIRST) ; rbx, rbp = MULX hi/lo temporaries ; ===================================================================== ADDMUL_FIRST_2 MACRO xor eax, eax mulx rbx, rbp, [rsi] adox r8, rbp ENDM ADDMUL_REST_2 MACRO adcx r9, rbx mulx rbp, r8, [rsi+8] adox r8, r9 mov r9, rax adcx r9, rbp adox r9, rax ENDM REDC_ITER_2 MACRO iter_idx LOCAL ri_nc mov rax, r8 imul rax, QWORD PTR [rsp+56] mov rdx, rax ADDMUL_FIRST_2 ADDMUL_REST_2 add r9, QWORD PTR [rdi + (2 + iter_idx)*8] jnc ri_nc _prop_idx = 3 + iter_idx WHILE _prop_idx LE 4 add QWORD PTR [rdi + _prop_idx*8], 1 jnc ri_nc _prop_idx = _prop_idx + 1 ENDM ri_nc: ENDM ; ===================================================================== ; void mpn_mont_mul_2(uint64_t* rp, const uint64_t* ap, ; const uint64_t* bp, const uint64_t* mp, ; uint64_t m_inv) ; ; register-resident n=2 SOS Montgomery multiplication: rp = ap * bp * R^{-1} mod mp ; 128-bit specialized ; ; rcx = rp, rdx = ap, r8 = bp, r9 = mp ; [rsp+144] = m_inv (5th arg, after 4 pushes + sub 72) ; ; Phase 1: 2×2 full multiplication (SOS, 4 MULX) ; Phase 2: REDC 2 iterations (4 MULX) ; Phase 3: conditional subtraction ; ===================================================================== mpn_mont_mul_2 PROC push rbx push rbp push rsi push rdi sub rsp, 72 ; Stack layout: ; 4 push × 8 = 32, sub 72 → total = 104 ; 5th arg (m_inv): [rsp + 104 + 40] = [rsp + 144] ; ; [rsp+0..39] = P[0..4] product buffer (5 qwords) ; [rsp+40] = rp ; [rsp+48] = mp ; [rsp+56] = m_inv mov [rsp+40], rcx mov rsi, rdx ; rsi = ap mov rcx, r8 ; rcx = bp mov [rsp+48], r9 ; mp mov rax, [rsp+144] mov [rsp+56], rax ; m_inv mov rdi, rsp ; product buffer ; ===== Phase 1: 2×2 full multiplication (SOS) ===== xor r8d, r8d xor r9d, r9d ; Row 0: b[0] mov rdx, [rcx] ADDMUL_FIRST_2 mov QWORD PTR [rdi], r8 ADDMUL_REST_2 ; Row 1: b[1] mov rdx, [rcx+8] ADDMUL_FIRST_2 mov QWORD PTR [rdi+8], r8 ADDMUL_REST_2 ; P[2..3] ← accumulator, P[4] = 0 mov [rdi+16], r8 mov [rdi+24], r9 mov QWORD PTR [rdi+32], 0 ; ===== Phase 2: REDC (2 iterations) ===== mov r8, [rdi] mov r9, [rdi+8] mov rsi, [rsp+48] ; mp REDC_ITER_2 0 REDC_ITER_2 1 ; ===== Phase 3: conditional subtraction ===== mov rbx, [rsp+40] ; rp mov rsi, [rsp+48] ; mp mov rax, r8 sub rax, [rsi] mov [rbx], rax mov rax, r9 sbb rax, [rsi+8] mov [rbx+8], rax ; account for P[4] overflow mov rax, [rdi+32] sbb rax, 0 jnc m2_done ; borrow → subtraction result invalid mov [rbx], r8 mov [rbx+8], r9 m2_done: add rsp, 72 pop rdi pop rsi pop rbp pop rbx ret mpn_mont_mul_2 ENDP ; ===================================================================== ; void mpn_mont_sqr_2(uint64_t* rp, const uint64_t* ap, ; const uint64_t* mp, uint64_t m_inv) ; ; register-resident n=2 fused SQR+REDC: rp = ap^2 * R^{-1} mod mp ; 128-bit specialized, exploits symmetry (1+2=3 MULX vs 4 MULX for multiplication) ; ; rcx = rp, rdx = ap, r8 = mp, r9 = m_inv ; ; Phase 1a: upper-triangle multiplication (off-diagonal, 1 MULX) ; Phase 1b: doubling (P[1..3] <<= 1) ; Phase 1c: add diagonal terms a[i]^2 (2 MULX) ; Phase 2: REDC 2 iterations (REDC_ITER_2 macro) ; Phase 3: conditional subtraction ; ===================================================================== mpn_mont_sqr_2 PROC push rbx push rbp push rsi push rdi sub rsp, 72 ; Stack layout (same as mont_mul_2): ; [rsp+0..39] = P[0..4] product buffer (5 qwords) ; [rsp+40] = rp ; [rsp+48] = mp ; [rsp+56] = m_inv mov [rsp+40], rcx ; rp mov rsi, rdx ; rsi = ap mov [rsp+48], r8 ; mp mov [rsp+56], r9 ; m_inv mov rdi, rsp ; product buffer ; --- Zero P[0..4] --- xor eax, eax mov [rdi], rax mov [rdi+8], rax mov [rdi+16], rax mov [rdi+24], rax mov [rdi+32], rax ; ===== Phase 1a: Off-diagonal upper triangle (1 MULX) ===== ; a[0]*a[1] → P[1], P[2] mov rdx, [rsi] mulx rbx, rcx, [rsi+8] mov [rdi+8], rcx mov [rdi+16], rbx ; ===== Phase 1b: doubling P[1..3] ===== mov rax, [rdi+8] add rax, rax mov [rdi+8], rax mov rax, [rdi+16] adc rax, rax mov [rdi+16], rax mov rax, [rdi+24] adc rax, rax mov [rdi+24], rax ; carry → P[4] mov rax, 0 adc rax, 0 mov [rdi+32], rax ; ===== Phase 1c: add diagonal terms a[i]^2 ===== mov rdx, [rsi] mulx rbx, rax, rdx add [rdi], rax adc [rdi+8], rbx mov rdx, [rsi+8] mulx rbx, rax, rdx adc [rdi+16], rax adc [rdi+24], rbx adc QWORD PTR [rdi+32], 0 ; ===== Phase 2: REDC (2 iterations) ===== mov r8, [rdi] mov r9, [rdi+8] mov rsi, [rsp+48] ; mp REDC_ITER_2 0 REDC_ITER_2 1 ; ===== Phase 3: conditional subtraction ===== mov rbx, [rsp+40] ; rp mov rsi, [rsp+48] ; mp mov rax, r8 sub rax, [rsi] mov [rbx], rax mov rax, r9 sbb rax, [rsi+8] mov [rbx+8], rax ; account for P[4] overflow mov rax, [rdi+32] sbb rax, 0 jnc s2_done ; borrow → subtraction result invalid mov [rbx], r8 mov [rbx+8], r9 s2_done: add rsp, 72 pop rdi pop rsi pop rbp pop rbx ret mpn_mont_sqr_2 ENDP END