193 lines
7.1 KiB
NASM
Raw Normal View History

2023-03-21 10:56:25 -07:00
// Arithmetic on integers represented with 128-bit limbs.
// These integers are represented in LITTLE-ENDIAN form.
2023-03-07 15:15:20 -08:00
// All integers must be under a given length bound, and are padded with leading zeroes.
// Stores b ^ e % m in output_loc, leaving b, e, and m unchanged.
// b, e, and m must have the same length.
// output_loc must have size length and be initialized with zeroes; scratch_1 must have size length.
2023-02-21 17:04:25 -08:00
// All of scratch_2..scratch_5 must have size 2 * length and be initialized with zeroes.
2023-03-28 11:50:05 -07:00
// Also, scratch_2..scratch_5 must be CONSECUTIVE in memory.
2023-03-07 15:15:20 -08:00
global modexp_bignum:
2023-04-25 17:19:44 -07:00
// stack: len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
// Special input cases:
// (1) Modulus is zero (also covers len=0 case).
PUSH modulus_zero_return
// stack: modulus_zero_return, len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
DUP5
// stack: m_loc, modulus_zero_return, len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
DUP3
// stack: len, m_loc, modulus_zero_return, len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
%jump(iszero_bignum)
modulus_zero_return:
// stack: m==0, len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
%jumpi(modulus_zero_or_one)
// (2) Modulus is one.
PUSH modulus_one_return
// stack: modulus_one_return, len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
DUP5
// stack: m_loc, modulus_one_return, len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
DUP3
// stack: len, m_loc, modulus_one_return, len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
%jump(isone_bignum)
modulus_one_return:
// stack: m==1, len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
%jumpi(modulus_zero_or_one)
// (3) Both b and e are zero.
PUSH b_zero_return
// stack: b_zero_return, len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
DUP3
// stack: b_loc, b_zero_return, len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
DUP3
// stack: len, b_loc, b_zero_return, len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
%jump(iszero_bignum)
b_zero_return:
// stack: b==0, len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
PUSH e_zero_return
// stack: e_zero_return, b==0, len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
DUP5
// stack: e_loc, e_zero_return, b==0, len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
DUP4
// stack: len, e_loc, e_zero_return, b==0, len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
%jump(iszero_bignum)
e_zero_return:
// stack: e==0, b==0, len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
2023-04-25 17:19:44 -07:00
MUL // logical AND
%jumpi(b_and_e_zero)
2023-04-19 14:56:08 -07:00
// End of special cases.
2023-03-07 15:15:20 -08:00
// We store the repeated-squares accumulator x_i in scratch_1, starting with x_0 := b.
DUP1
DUP3
DUP8
2023-03-21 10:56:25 -07:00
// stack: s1, b_loc, len, len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
2023-06-20 12:01:24 -07:00
%memcpy_current_general
2023-03-21 10:56:25 -07:00
// stack: len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
2023-03-07 15:15:20 -08:00
// We store the accumulated output value x_i in output_loc, starting with x_0=1.
PUSH 1
DUP6
2023-03-21 10:56:25 -07:00
// stack: out_loc, 1, len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
2023-06-20 11:56:21 -07:00
%mstore_current_general
2023-03-07 15:15:20 -08:00
modexp_loop:
2023-03-21 10:56:25 -07:00
// stack: len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
2023-03-07 15:15:20 -08:00
// y := e % 2
DUP3
2023-03-21 10:56:25 -07:00
// stack: e_loc, len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
2023-06-20 11:56:21 -07:00
%mload_current_general
2023-03-21 10:56:25 -07:00
// stack: e_first, len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
2023-03-07 15:15:20 -08:00
%mod_const(2)
2023-03-21 10:56:25 -07:00
// stack: y = e_first % 2 = e % 2, len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
2023-03-07 15:15:20 -08:00
ISZERO
2023-03-21 10:56:25 -07:00
// stack: y == 0, len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
2023-03-07 15:15:20 -08:00
%jumpi(modexp_y_0)
2023-02-21 17:04:25 -08:00
// if y == 1, modular-multiply output_loc by scratch_1, using scratch_2..scratch_4 as scratch space, and store in scratch_5.
2023-03-07 15:15:20 -08:00
PUSH modexp_mul_return
2023-02-21 17:04:25 -08:00
DUP10
2023-03-07 15:15:20 -08:00
DUP10
DUP10
2023-02-21 17:04:25 -08:00
DUP14
DUP9
DUP12
DUP12
DUP9
2023-03-21 10:56:25 -07:00
// stack: len, out_loc, s1, m_loc, s5, s2, s3, s4, modexp_mul_return, len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
2023-03-07 15:15:20 -08:00
%jump(modmul_bignum)
modexp_mul_return:
2023-03-21 10:56:25 -07:00
// stack: len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
2023-03-07 15:15:20 -08:00
2023-02-21 17:04:25 -08:00
// Copy scratch_5 to output_loc.
2023-03-07 15:15:20 -08:00
DUP1
2023-02-21 17:04:25 -08:00
DUP11
2023-03-07 15:15:20 -08:00
DUP7
2023-03-21 10:56:25 -07:00
// stack: out_loc, s5, len, len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
2023-06-20 12:01:24 -07:00
%memcpy_current_general
2023-03-21 10:56:25 -07:00
// stack: len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
2023-03-07 15:15:20 -08:00
2023-02-21 17:04:25 -08:00
// Zero out scratch_2..scratch_5.
2023-03-07 15:15:20 -08:00
DUP1
2023-02-21 17:04:25 -08:00
%mul_const(8)
2023-03-07 15:15:20 -08:00
DUP8
2023-03-21 10:56:25 -07:00
// stack: s2, 8 * len, len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
2023-06-20 12:01:24 -07:00
%clear_current_general
2023-03-21 10:56:25 -07:00
// stack: len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
2023-03-07 15:15:20 -08:00
modexp_y_0:
// if y == 0, do nothing
2023-02-21 17:04:25 -08:00
// Modular-square repeated-squares accumulator x_i (in scratch_1), using scratch_2..scratch_4 as scratch space, and store in scratch_5.
2023-03-07 15:15:20 -08:00
PUSH modexp_square_return
DUP10
2023-02-21 17:04:25 -08:00
DUP10
2023-03-07 15:15:20 -08:00
DUP10
2023-02-21 17:04:25 -08:00
DUP14
DUP9
DUP12
DUP1
DUP9
2023-03-21 10:56:25 -07:00
// stack: len, s1, s1, m_loc, s5, s2, s3, s4, modexp_square_return, len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
2023-03-07 15:15:20 -08:00
%jump(modmul_bignum)
2023-03-21 10:56:25 -07:00
// stack: len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
2023-03-07 15:15:20 -08:00
modexp_square_return:
2023-02-21 17:04:25 -08:00
// Copy scratch_5 to scratch_1.
2023-03-07 15:15:20 -08:00
DUP1
2023-02-21 17:04:25 -08:00
DUP11
2023-03-07 15:15:20 -08:00
DUP8
2023-03-21 10:56:25 -07:00
// stack: s1, s5, len, len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
2023-06-20 12:01:24 -07:00
%memcpy_current_general
2023-03-21 10:56:25 -07:00
// stack: len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
2023-03-07 15:15:20 -08:00
2023-02-21 17:04:25 -08:00
// Zero out scratch_2..scratch_5.
2023-03-07 15:15:20 -08:00
DUP1
2023-02-21 17:04:25 -08:00
%mul_const(8)
2023-03-07 15:15:20 -08:00
DUP8
2023-03-21 10:56:25 -07:00
// stack: s2, 8 * len, len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
2023-06-20 12:01:24 -07:00
%clear_current_general
2023-03-21 10:56:25 -07:00
// stack: len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
2023-03-07 15:15:20 -08:00
2023-02-21 17:04:25 -08:00
// e //= 2 (with shr_bignum)
2023-03-07 15:15:20 -08:00
PUSH modexp_shr_return
DUP4
DUP3
2023-03-21 10:56:25 -07:00
// stack: len, e_loc, modexp_shr_return, len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
2023-03-07 15:15:20 -08:00
%jump(shr_bignum)
modexp_shr_return:
2023-03-21 10:56:25 -07:00
// stack: len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
2023-03-07 15:15:20 -08:00
// check if e == 0 (with iszero_bignum)
PUSH modexp_iszero_return
DUP4
DUP3
2023-03-21 10:56:25 -07:00
// stack: len, e_loc, modexp_iszero_return, len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
2023-03-07 15:15:20 -08:00
%jump(iszero_bignum)
modexp_iszero_return:
2023-03-21 10:56:25 -07:00
// stack: e == 0, len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
2023-03-07 15:15:20 -08:00
ISZERO
2023-03-21 10:56:25 -07:00
// stack: e != 0, len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
2023-03-07 15:15:20 -08:00
%jumpi(modexp_loop)
2023-03-21 10:56:25 -07:00
// end of modexp_loop
modulus_zero_or_one:
// If modulus is zero or one, return 0.
// stack: len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
%pop10
2023-03-07 15:15:20 -08:00
// stack: retdest
JUMP
b_and_e_zero:
// If base and exponent are zero (and modulus > 1), return 1.
// stack: len, b_loc, e_loc, m_loc, out_loc, s1, s2, s3, s4, s5, retdest
PUSH 1
DUP6
2023-06-20 11:56:21 -07:00
%mstore_current_general
%pop10
// stack: retdest
2023-04-19 15:27:49 -07:00
JUMP