src/jwa/jose_jwa_math.erl

%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*-
%% vim: ts=4 sw=4 ft=erlang noet
%%%-------------------------------------------------------------------
%%% @author Andrew Bennett <potatosaladx@gmail.com>
%%% @copyright 2014-2022, Andrew Bennett
%%% @doc
%%% 
%%% @end
%%% Created :  06 Jan 2016 by Andrew Bennett <potatosaladx@gmail.com>
%%%-------------------------------------------------------------------
-module(jose_jwa_math).

%% Public API
-export([expmod/3]).
-export([exprem/3]).
-export([intpow/2]).
-export([mod/2]).
-export([mod_pow/3]).

%% Private API
-export([expmod_fast/3]).
-export([expmod_slow/3]).
-export([exprem_fast/3]).
-export([exprem_slow/3]).

%%====================================================================
%% Public API
%%====================================================================

expmod(B, E, M) ->
	expmod_fast(B, E, M).

exprem(B, E, M) ->
	exprem_fast(B, E, M).

intpow(B, E) when is_integer(B) andalso is_integer(E) andalso E >= 0 ->
	case B of
		0 ->
			0;
		1 ->
			1;
		2 ->
			1 bsl E;
		_ ->
			intpow(B, E, 1)
	end.

mod(B, M) ->
	(B rem M + M) rem M.

mod_pow(B, E, M) ->
	Bytes = crypto:mod_pow(B, E, M),
	Size = byte_size(Bytes),
	<< ((crypto:bytes_to_integer(Bytes) + M) rem M):Size/signed-big-integer-unit:8 >>.

%%====================================================================
%% Private API
%%====================================================================

% @private
expmod_fast(B, E, M) ->
	(exprem_fast(B, E, M) + M) rem M.

% @private
expmod_slow(B, E, M) ->
	(exprem_slow(B, E, M) + M) rem M.

% @private
exprem_fast(B, E, M) when B < 0 andalso E rem 2 =/= 0 ->
	-exprem_fast(abs(B), E, M);
exprem_fast(B, E, M) when B < 0 ->
	exprem_fast(abs(B), E, M);
exprem_fast(B, E, M) ->
	crypto:bytes_to_integer(crypto:mod_pow(B, E, M)).

%% @private
exprem_slow(_B, 0, _M) ->
	1;
exprem_slow(B, E, M) ->
	T0 = exprem_slow(B, E div 2, M),
	T = (T0 * T0) rem M,
	case E rem 2 of
		0 ->
			T band M;
		_ ->
			(T * B) rem M
	end.

%%%-------------------------------------------------------------------
%%% Internal functions
%%%-------------------------------------------------------------------

%% @private
intpow(B, E, R) when (E rem 2) =:= 0 ->
	intpow(B * B, E div 2, R);
intpow(B, E, R) when (E div 2) =:= 0 ->
	B * R;
intpow(B, E, R) ->
	intpow(B * B, E div 2, B * R).