|
|
// +build amd64_adx
// Copyright 2020 ConsenSys Software Inc. // // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License.
#include "textflag.h"
#include "funcdata.h"
// modulus q DATA q<>+0(SB)/8, $0x43e1f593f0000001 DATA q<>+8(SB)/8, $0x2833e84879b97091 DATA q<>+16(SB)/8, $0xb85045b68181585d DATA q<>+24(SB)/8, $0x30644e72e131a029 GLOBL q<>(SB), (RODATA+NOPTR), $32
// qInv0 q'[0] DATA qInv0<>(SB)/8, $0xc2e1f593efffffff GLOBL qInv0<>(SB), (RODATA+NOPTR), $8
#define REDUCE(ra0, ra1, ra2, ra3, rb0, rb1, rb2, rb3) \
MOVQ ra0, rb0; \
SUBQ q<>(SB), ra0; \
MOVQ ra1, rb1; \
SBBQ q<>+8(SB), ra1; \
MOVQ ra2, rb2; \
SBBQ q<>+16(SB), ra2; \
MOVQ ra3, rb3; \
SBBQ q<>+24(SB), ra3; \
CMOVQCS rb0, ra0; \
CMOVQCS rb1, ra1; \
CMOVQCS rb2, ra2; \
CMOVQCS rb3, ra3; \
// mul(res, x, y *Element) TEXT ·mul(SB), NOSPLIT, $0-24
// the algorithm is described here // https://hackmd.io/@zkteam/modular_multiplication // however, to benefit from the ADCX and ADOX carry chains // we split the inner loops in 2: // for i=0 to N-1 // for j=0 to N-1 // (A,t[j]) := t[j] + x[j]*y[i] + A // m := t[0]*q'[0] mod W // C,_ := t[0] + m*q[0] // for j=1 to N-1 // (C,t[j-1]) := t[j] + m*q[j] + C // t[N-1] = C + A
MOVQ x+8(FP), SI
// x[0] -> DI // x[1] -> R8 // x[2] -> R9 // x[3] -> R10 MOVQ 0(SI), DI MOVQ 8(SI), R8 MOVQ 16(SI), R9 MOVQ 24(SI), R10 MOVQ y+16(FP), R11
// A -> BP // t[0] -> R14 // t[1] -> R15 // t[2] -> CX // t[3] -> BX // clear the flags XORQ AX, AX MOVQ 0(R11), DX
// (A,t[0]) := x[0]*y[0] + A MULXQ DI, R14, R15
// (A,t[1]) := x[1]*y[0] + A MULXQ R8, AX, CX ADOXQ AX, R15
// (A,t[2]) := x[2]*y[0] + A MULXQ R9, AX, BX ADOXQ AX, CX
// (A,t[3]) := x[3]*y[0] + A MULXQ R10, AX, BP ADOXQ AX, BX
// A += carries from ADCXQ and ADOXQ MOVQ $0, AX ADOXQ AX, BP
// m := t[0]*q'[0] mod W MOVQ qInv0<>(SB), DX IMULQ R14, DX
// clear the flags XORQ AX, AX
// C,_ := t[0] + m*q[0] MULXQ q<>+0(SB), AX, R12 ADCXQ R14, AX MOVQ R12, R14
// (C,t[0]) := t[1] + m*q[1] + C ADCXQ R15, R14 MULXQ q<>+8(SB), AX, R15 ADOXQ AX, R14
// (C,t[1]) := t[2] + m*q[2] + C ADCXQ CX, R15 MULXQ q<>+16(SB), AX, CX ADOXQ AX, R15
// (C,t[2]) := t[3] + m*q[3] + C ADCXQ BX, CX MULXQ q<>+24(SB), AX, BX ADOXQ AX, CX
// t[3] = C + A MOVQ $0, AX ADCXQ AX, BX ADOXQ BP, BX
// clear the flags XORQ AX, AX MOVQ 8(R11), DX
// (A,t[0]) := t[0] + x[0]*y[1] + A MULXQ DI, AX, BP ADOXQ AX, R14
// (A,t[1]) := t[1] + x[1]*y[1] + A ADCXQ BP, R15 MULXQ R8, AX, BP ADOXQ AX, R15
// (A,t[2]) := t[2] + x[2]*y[1] + A ADCXQ BP, CX MULXQ R9, AX, BP ADOXQ AX, CX
// (A,t[3]) := t[3] + x[3]*y[1] + A ADCXQ BP, BX MULXQ R10, AX, BP ADOXQ AX, BX
// A += carries from ADCXQ and ADOXQ MOVQ $0, AX ADCXQ AX, BP ADOXQ AX, BP
// m := t[0]*q'[0] mod W MOVQ qInv0<>(SB), DX IMULQ R14, DX
// clear the flags XORQ AX, AX
// C,_ := t[0] + m*q[0] MULXQ q<>+0(SB), AX, R12 ADCXQ R14, AX MOVQ R12, R14
// (C,t[0]) := t[1] + m*q[1] + C ADCXQ R15, R14 MULXQ q<>+8(SB), AX, R15 ADOXQ AX, R14
// (C,t[1]) := t[2] + m*q[2] + C ADCXQ CX, R15 MULXQ q<>+16(SB), AX, CX ADOXQ AX, R15
// (C,t[2]) := t[3] + m*q[3] + C ADCXQ BX, CX MULXQ q<>+24(SB), AX, BX ADOXQ AX, CX
// t[3] = C + A MOVQ $0, AX ADCXQ AX, BX ADOXQ BP, BX
// clear the flags XORQ AX, AX MOVQ 16(R11), DX
// (A,t[0]) := t[0] + x[0]*y[2] + A MULXQ DI, AX, BP ADOXQ AX, R14
// (A,t[1]) := t[1] + x[1]*y[2] + A ADCXQ BP, R15 MULXQ R8, AX, BP ADOXQ AX, R15
// (A,t[2]) := t[2] + x[2]*y[2] + A ADCXQ BP, CX MULXQ R9, AX, BP ADOXQ AX, CX
// (A,t[3]) := t[3] + x[3]*y[2] + A ADCXQ BP, BX MULXQ R10, AX, BP ADOXQ AX, BX
// A += carries from ADCXQ and ADOXQ MOVQ $0, AX ADCXQ AX, BP ADOXQ AX, BP
// m := t[0]*q'[0] mod W MOVQ qInv0<>(SB), DX IMULQ R14, DX
// clear the flags XORQ AX, AX
// C,_ := t[0] + m*q[0] MULXQ q<>+0(SB), AX, R12 ADCXQ R14, AX MOVQ R12, R14
// (C,t[0]) := t[1] + m*q[1] + C ADCXQ R15, R14 MULXQ q<>+8(SB), AX, R15 ADOXQ AX, R14
// (C,t[1]) := t[2] + m*q[2] + C ADCXQ CX, R15 MULXQ q<>+16(SB), AX, CX ADOXQ AX, R15
// (C,t[2]) := t[3] + m*q[3] + C ADCXQ BX, CX MULXQ q<>+24(SB), AX, BX ADOXQ AX, CX
// t[3] = C + A MOVQ $0, AX ADCXQ AX, BX ADOXQ BP, BX
// clear the flags XORQ AX, AX MOVQ 24(R11), DX
// (A,t[0]) := t[0] + x[0]*y[3] + A MULXQ DI, AX, BP ADOXQ AX, R14
// (A,t[1]) := t[1] + x[1]*y[3] + A ADCXQ BP, R15 MULXQ R8, AX, BP ADOXQ AX, R15
// (A,t[2]) := t[2] + x[2]*y[3] + A ADCXQ BP, CX MULXQ R9, AX, BP ADOXQ AX, CX
// (A,t[3]) := t[3] + x[3]*y[3] + A ADCXQ BP, BX MULXQ R10, AX, BP ADOXQ AX, BX
// A += carries from ADCXQ and ADOXQ MOVQ $0, AX ADCXQ AX, BP ADOXQ AX, BP
// m := t[0]*q'[0] mod W MOVQ qInv0<>(SB), DX IMULQ R14, DX
// clear the flags XORQ AX, AX
// C,_ := t[0] + m*q[0] MULXQ q<>+0(SB), AX, R12 ADCXQ R14, AX MOVQ R12, R14
// (C,t[0]) := t[1] + m*q[1] + C ADCXQ R15, R14 MULXQ q<>+8(SB), AX, R15 ADOXQ AX, R14
// (C,t[1]) := t[2] + m*q[2] + C ADCXQ CX, R15 MULXQ q<>+16(SB), AX, CX ADOXQ AX, R15
// (C,t[2]) := t[3] + m*q[3] + C ADCXQ BX, CX MULXQ q<>+24(SB), AX, BX ADOXQ AX, CX
// t[3] = C + A MOVQ $0, AX ADCXQ AX, BX ADOXQ BP, BX
// reduce element(R14,R15,CX,BX) using temp registers (R13,SI,R12,R11) REDUCE(R14,R15,CX,BX,R13,SI,R12,R11)
MOVQ res+0(FP), AX MOVQ R14, 0(AX) MOVQ R15, 8(AX) MOVQ CX, 16(AX) MOVQ BX, 24(AX) RET
TEXT ·fromMont(SB), NOSPLIT, $0-8
// the algorithm is described here // https://hackmd.io/@zkteam/modular_multiplication // when y = 1 we have: // for i=0 to N-1 // t[i] = x[i] // for i=0 to N-1 // m := t[0]*q'[0] mod W // C,_ := t[0] + m*q[0] // for j=1 to N-1 // (C,t[j-1]) := t[j] + m*q[j] + C // t[N-1] = C MOVQ res+0(FP), DX MOVQ 0(DX), R14 MOVQ 8(DX), R15 MOVQ 16(DX), CX MOVQ 24(DX), BX XORQ DX, DX
// m := t[0]*q'[0] mod W MOVQ qInv0<>(SB), DX IMULQ R14, DX XORQ AX, AX
// C,_ := t[0] + m*q[0] MULXQ q<>+0(SB), AX, BP ADCXQ R14, AX MOVQ BP, R14
// (C,t[0]) := t[1] + m*q[1] + C ADCXQ R15, R14 MULXQ q<>+8(SB), AX, R15 ADOXQ AX, R14
// (C,t[1]) := t[2] + m*q[2] + C ADCXQ CX, R15 MULXQ q<>+16(SB), AX, CX ADOXQ AX, R15
// (C,t[2]) := t[3] + m*q[3] + C ADCXQ BX, CX MULXQ q<>+24(SB), AX, BX ADOXQ AX, CX MOVQ $0, AX ADCXQ AX, BX ADOXQ AX, BX XORQ DX, DX
// m := t[0]*q'[0] mod W MOVQ qInv0<>(SB), DX IMULQ R14, DX XORQ AX, AX
// C,_ := t[0] + m*q[0] MULXQ q<>+0(SB), AX, BP ADCXQ R14, AX MOVQ BP, R14
// (C,t[0]) := t[1] + m*q[1] + C ADCXQ R15, R14 MULXQ q<>+8(SB), AX, R15 ADOXQ AX, R14
// (C,t[1]) := t[2] + m*q[2] + C ADCXQ CX, R15 MULXQ q<>+16(SB), AX, CX ADOXQ AX, R15
// (C,t[2]) := t[3] + m*q[3] + C ADCXQ BX, CX MULXQ q<>+24(SB), AX, BX ADOXQ AX, CX MOVQ $0, AX ADCXQ AX, BX ADOXQ AX, BX XORQ DX, DX
// m := t[0]*q'[0] mod W MOVQ qInv0<>(SB), DX IMULQ R14, DX XORQ AX, AX
// C,_ := t[0] + m*q[0] MULXQ q<>+0(SB), AX, BP ADCXQ R14, AX MOVQ BP, R14
// (C,t[0]) := t[1] + m*q[1] + C ADCXQ R15, R14 MULXQ q<>+8(SB), AX, R15 ADOXQ AX, R14
// (C,t[1]) := t[2] + m*q[2] + C ADCXQ CX, R15 MULXQ q<>+16(SB), AX, CX ADOXQ AX, R15
// (C,t[2]) := t[3] + m*q[3] + C ADCXQ BX, CX MULXQ q<>+24(SB), AX, BX ADOXQ AX, CX MOVQ $0, AX ADCXQ AX, BX ADOXQ AX, BX XORQ DX, DX
// m := t[0]*q'[0] mod W MOVQ qInv0<>(SB), DX IMULQ R14, DX XORQ AX, AX
// C,_ := t[0] + m*q[0] MULXQ q<>+0(SB), AX, BP ADCXQ R14, AX MOVQ BP, R14
// (C,t[0]) := t[1] + m*q[1] + C ADCXQ R15, R14 MULXQ q<>+8(SB), AX, R15 ADOXQ AX, R14
// (C,t[1]) := t[2] + m*q[2] + C ADCXQ CX, R15 MULXQ q<>+16(SB), AX, CX ADOXQ AX, R15
// (C,t[2]) := t[3] + m*q[3] + C ADCXQ BX, CX MULXQ q<>+24(SB), AX, BX ADOXQ AX, CX MOVQ $0, AX ADCXQ AX, BX ADOXQ AX, BX
// reduce element(R14,R15,CX,BX) using temp registers (SI,DI,R8,R9) REDUCE(R14,R15,CX,BX,SI,DI,R8,R9)
MOVQ res+0(FP), AX MOVQ R14, 0(AX) MOVQ R15, 8(AX) MOVQ CX, 16(AX) MOVQ BX, 24(AX) RET
|