2023-03-28 11:54:14 -07:00

69 lines
2.1 KiB
NASM

// Arithmetic on little-endian integers represented with 128-bit limbs.
// All integers must be under a given length bound, and are padded with leading zeroes.
// Shifts a given bignum right by one bit (in place).
// Assumes that len > 0.
global shr_bignum:
// stack: len, start_loc, retdest
DUP1
// stack: len, len, start_loc, retdest
ISZERO
%jumpi(len_zero)
// stack: len, start_loc, retdest
DUP2
// stack: start_loc, len, start_loc, retdest
ADD
// stack: start_loc + len, start_loc, retdest
%decrement
// stack: end_loc, start_loc, retdest
%stack (e) -> (e, 0)
// stack: i=end_loc, carry=0, start_loc, retdest
shr_loop:
// stack: i, carry, start_loc, retdest
DUP1
// stack: i, i, carry, start_loc, retdest
%mload_kernel_general
// stack: a[i], i, carry, start_loc, retdest
DUP1
// stack: a[i], a[i], i, carry, start_loc, retdest
%shr_const(1)
// stack: a[i] >> 1, a[i], i, carry, start_loc, retdest
SWAP1
// stack: a[i], a[i] >> 1, i, carry, start_loc, retdest
%mod_const(2)
// stack: new_carry = a[i] % 2, a[i] >> 1, i, carry, start_loc, retdest
SWAP3
// stack: carry, a[i] >> 1, i, new_carry, start_loc, retdest
%shl_const(127)
// stack: carry << 127, a[i] >> 1, i, new_carry, start_loc, retdest
ADD
// stack: carry << 127 | a[i] >> 1, i, new_carry, start_loc, retdest
DUP2
// stack: i, carry << 127 | a[i] >> 1, i, new_carry, start_loc, retdest
%mstore_kernel_general
// stack: i, new_carry, start_loc, retdest
DUP1
// stack: i, i, new_carry, start_loc, retdest
%decrement
// stack: i-1, i, new_carry, start_loc, retdest
SWAP1
// stack: i, i-1, new_carry, start_loc, retdest
DUP4
// stack: start_loc, i, i-1, new_carry, start_loc, retdest
EQ
// stack: i == start_loc, i-1, new_carry, start_loc, retdest
ISZERO
// stack: i != start_loc, i-1, new_carry, start_loc, retdest
%jumpi(shr_loop)
shr_end:
// stack: i, new_carry, start_loc, retdest
%pop3
// stack: retdest
JUMP
len_zero:
// stack: len, start_loc, retdest
%pop2
// stack: retdest
JUMP