%% ---
%%  Excerpted from "Programming Erlang",
%%  published by The Pragmatic Bookshelf.
%%  Copyrights apply to this code. It may not be used to create training material,
%%  courses, books, articles, and the like. Contact us if you are in doubt.
%%  We make no guarantees that this code is fit for any purpose.
%%  Visit http://www.pragmaticprogrammer.com/titles/jaerlang for more book information.
%%  
%%  日本語版の『プログラミングErlang』、およびサンプルコードについては、
%%   http://ssl.ohmsha.co.jp/cgi-bin/menu.cgi?ISBN=978-4-274-06714-3 を確認してください。
%% ---
-module(lib_rsa).

-export([make_sig/1, make_sig/2]).

make_sig(Who, Len) when Len > 79 ->
    {Public, Private} = make_sig(Len),
    file:write_file(Who ++ ".pub", term_to_binary(Public)),
    file:write_file(Who ++ ".pri", term_to_binary(Private)),
    {keyfilecreated,for,Who}.

%% The "book" says ...◆→asktheauthor: どの本のこと？ Schneierの本？kazuya←◆
%% 1. Bobは2つの素数pとqを生成する
%% 2. Bobはn = pqとphi(n) = (p-1)*(q-1)を計算する
%% 3. Bobはgcd(b, phi(n)) = 1を満たすような乱数b（ただし0 < b < phi(n)）
%%    を選ぶ
%% 4. BobはEuclidのアルゴリズムを使ってa = b^(-1) mod phi(n)を計算する
%% 5. Bobはnとbを自分の公開鍵としてディレクトリに公開する


make_sig(Len) ->
    %% Len桁の素数を2つ生成する
    P = primes:make_prime(Len),
    io:format("P = ~p~n", [P]),
    Q = primes:make_prime(Len),
    io:format("Q = ~p~n", [Q]),
    N = P*Q,
    io:format("N = ~p~n", [N]),
    Phi = (P-1)*(Q-1),
    %% B < Phi and gcd(B, Phi) = 1を満たすようなBを作る
    B = b(Phi),
    io:format("Public key (B) = ~p~n", [B]),
    A = lin:inv(B, Phi),
    io:format("Private key (A) = ~p~n", [A]),
    {{B,N},{A,N}}.

b(Phi) ->
    io:format("Generating a public key B "),
    K = length(integer_to_list(Phi)) - 1,
    B = b(1, K, Phi),
    io:format("~n", []),
    B.

b(Try, K, Phi) ->
    io:format("."),
    B = primes:make(K),
    if 
	B < Phi ->
	    case lin:gcd(B, Phi) of
		1 -> B;
		_ -> b(Try+1, K, Phi)
	    end;
	true ->
	    b(Try, K, Phi)
    end.



