Skip to content

Commit

Permalink
* [CnECC] Update Demo to add a Lucas Int64 V routine.
Browse files Browse the repository at this point in the history
  • Loading branch information
liuxiao committed Sep 27, 2018
1 parent 1b9cfea commit adcc0a0
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 28 deletions.
12 changes: 10 additions & 2 deletions Examples/ECC/UnitEcc.dfm
Expand Up @@ -20,7 +20,7 @@ object FormEcc: TFormEcc
Top = 16
Width = 737
Height = 465
ActivePage = tsWrapData
ActivePage = tsLucas
TabOrder = 0
object tsSimpleECC: TTabSheet
Caption = 'Simple ECC'
Expand Down Expand Up @@ -1228,10 +1228,18 @@ object FormEcc: TFormEcc
Top = 56
Width = 153
Height = 21
Caption = 'Lucas Mod'
Caption = 'Lucas 2'
TabOrder = 6
OnClick = btnLucasModClick
end
object chkLucasMod: TCheckBox
Left = 296
Top = 28
Width = 49
Height = 17
Caption = 'Mod'
TabOrder = 7
end
end
object grpLegendre: TGroupBox
Left = 392
Expand Down
88 changes: 64 additions & 24 deletions Examples/ECC/UnitEcc.pas
Expand Up @@ -5,7 +5,7 @@ interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ComCtrls, CnECC, ExtCtrls, Buttons, TeEngine, Series, TeeProcs,
Chart, CnPrimeNumber, CnBigNumber;
Chart, CnPrimeNumber, CnBigNumber, CnNativeDecl;

type
TFormEcc = class(TForm)
Expand Down Expand Up @@ -173,6 +173,7 @@ TFormEcc = class(TForm)
btnBNTS: TButton;
mmoTSData: TMemo;
btnRandomTS: TButton;
chkLucasMod: TCheckBox;
procedure btnTest1Click(Sender: TObject);
procedure btnTest0Click(Sender: TObject);
procedure btnTestOnClick(Sender: TObject);
Expand Down Expand Up @@ -973,6 +974,7 @@ procedure TFormEcc.btnBNGXtoPointClick(Sender: TObject);

procedure TFormEcc.btnInt64GXtoPtClick(Sender: TObject);
var
// I: Integer;
P, A, B, X, Y, N: Int64;
Ecc: TCnInt64Ecc;
Pt: TCnInt64EccPoint;
Expand All @@ -989,6 +991,11 @@ procedure TFormEcc.btnInt64GXtoPtClick(Sender: TObject);
// 15/194/64403/41589/5579 是 4u3 型的测试通过
// 12/199/73/21/21/61 是 8u1 型的也基本测试通过

//P := GetTickCount;
//for I := 0 to 100000 do // 一万次要 453/469 毫秒,十万次要 4484 毫秒
// Ecc.PlainToPoint(X, Pt);
//ShowMessage(IntToStr(GetTickCount - P));

if Ecc.PlainToPoint(X, Pt) then
begin
ShowMessage('Convert to ' + CnInt64EccPointToString(Pt));
Expand All @@ -1003,11 +1010,12 @@ procedure TFormEcc.btnInt64GXtoPtClick(Sender: TObject);

procedure TFormEcc.btnLucasRecurClick(Sender: TObject);
var
X, Y, U, V, U_2, V_2, U_1, V_1: Int64;
X, Y, P, U, V, U_2, V_2, U_1, V_1: Int64;
I: Integer;
begin
X := StrToInt(edtLucasX.Text);
Y := StrToInt(edtLucasY.Text);
P := StrToInt(edtLucasP.Text);

mmoLucasRes.Lines.Clear;
mmoLucasRes.Lines.Add(Format('%d: %d, %d', [0, 0, 2]));
Expand All @@ -1025,10 +1033,14 @@ procedure TFormEcc.btnLucasRecurClick(Sender: TObject);

U_1 := U;
V_1 := V;
mmoLucasRes.Lines.Add(Format('%d: %d, %d', [I, U, V]));
if chkLucasMod.Checked then
mmoLucasRes.Lines.Add(Format('%d: %d, %d', [I, U mod P, V mod P]))
else
mmoLucasRes.Lines.Add(Format('%d: %d, %d', [I, U, V]));
end;
end;

// 按定义递归计算 Lucas 序列,照理慢但准确
procedure TFormEcc.CalcLucas(X, Y, U_2, V_2, U_1, V_1: Int64; var U, V: Int64);
begin
U := X * U_1 - Y * U_2;
Expand All @@ -1051,7 +1063,7 @@ function Int64MultipleMod(A, B, C: Int64): Int64;
end;

// 计算 Lucas 序列以及模的两种不同实现函数,但结果对不上,弃用。
procedure CalcLucasSequence(X, Y, K, P: Int64; out U, V: Int64);
procedure CalcLucasSequenceBad(X, Y, K, P: Int64; out U, V: Int64);
var
I: Integer;
U_2, V_2, U_1, V_1: Int64;
Expand Down Expand Up @@ -1090,33 +1102,58 @@ procedure CalcLucasSequence(X, Y, K, P: Int64; out U, V: Int64);
end;
end;

procedure CalcLucasSequenceMod(X, Y, K, P: Int64; out U, V: Int64);
// 另一种 Lucas 计算,V 对得上号但 U 不靠谱
procedure CalcLucasSequence2(X, Y, K, P: Int64; out U, V: Int64);
var
C, I: Integer;
D, UT, VT: Int64;
V0, V1, Q0, Q1: Int64;
begin
if K < 0 then
raise ECnEccException.Create('Invalid K for Lucas Sequence');

function GetInt64BitSet(B: Int64; Index: Integer): Boolean; // 返回 Int64 的第几位是否是 1,0 开始
if K = 0 then
begin
U := 0;
V := 2;
Exit;
end
else if K = 1 then
begin
B := B and (Int64(1) shl Index);
Result := B <> 0;
U := 1;
V := X;
Exit;
end;

// 返回 Int64 的最高二进制位是第几位,0 开始
function GetInt64HighBits(B: Int64): Integer;
var
J: Integer;
V0 := 2;
V1 := X;
Q0 := 1;
Q1 := 1;

C := GetUInt64HighBits(K);
for I := C downto 0 do
begin
for J := 63 downto 0 do
Q0 := Q0 * Q1;
if GetUInt64BitSet(K, I) then
begin
if GetInt64BitSet(B, J) then
begin
Result := J;
Exit;
end;
Q1 := Q0 * Y;
V0 := V0 * V1 - X * Q0;
V1 := V1 * V1 - 2 * Q1;
end
else
begin
Q1 := Q0;
V1 := V0 * V1 - X * Q0;
V0 := V0 * V0 - 2 * Q0;
end;
Result := 0;
end;
U := Q0;
V := V0;
end;

procedure CalcLucasSequenceMod(X, Y, K, P: Int64; out U, V: Int64);
var
C, I: Integer;
D, UT, VT: Int64;
begin
if K < 0 then
raise ECnEccException.Create('Invalid K for Lucas Sequence');
Expand All @@ -1139,15 +1176,15 @@ procedure CalcLucasSequenceMod(X, Y, K, P: Int64; out U, V: Int64);
U := 1;
V := X;

C := GetInt64HighBits(K);
C := GetUInt64HighBits(K);
for I := C - 1 downto 0 do
begin
UT := Int64MultipleMod(U, V, P);
VT := ((V * V + D * U * U) div 2) mod P;

U := UT;
V := VT;
if GetInt64BitSet(K, I) then
if GetUInt64BitSet(K, I) then
begin
UT := ((X * U + V) div 2) mod P;
VT := ((X * V + D * U) div 2) mod P;
Expand All @@ -1174,8 +1211,11 @@ procedure TFormEcc.btnLucasModClick(Sender: TObject);

for I := 0 to 100 do
begin
CalcLucasSequence(X, Y, I, P, U, V);
mmoLucasMod.Lines.Add(Format('%d: %d, %d', [I, U, V]));
CalcLucasSequence2(X, Y, I, P, U, V);
if chkLucasMod.Checked then
mmoLucasMod.Lines.Add(Format('%d: %d, %d', [I, U mod P, V mod P]))
else
mmoLucasMod.Lines.Add(Format('%d: %d, %d', [I, U, V]));
end;
end;

Expand Down
4 changes: 2 additions & 2 deletions Source/Common/CnBigNumber.pas
Expand Up @@ -471,8 +471,8 @@ function BigNumberLegendre2(A, P: TCnBigNumber): Integer;
{* 用欧拉判别法计算勒让德符号 ( A / P) 的值,较慢}

function BigNumberTonelliShanks(const Res: TCnBigNumber; A, P: TCnBigNumber): Boolean;
{* 使用 Tonelli Shanks 算法进行模素数二次剩余求解,也就是求 Res^2 mod P = A
调用者需自行保证 P 为奇素数或奇素数的整数次方,并且保证 A/P 的勒让德符号为 1 也就是有解}
{* 使用 Tonelli Shanks 算法进行模素数二次剩余求解,也就是求 Res^2 mod P = A,返回是否有解
调用者需自行保证 P 为奇素数或奇素数的整数次方}

procedure BigNumberFindFactors(Num: TCnBigNumber; Factors: TCnBigNumberList);
{* 找出大数的质因数列表}
Expand Down
29 changes: 29 additions & 0 deletions Source/Common/CnNativeDecl.pas
Expand Up @@ -110,6 +110,12 @@ function UInt32IsNegative(N: Cardinal): Boolean;
function UInt64IsNegative(N: TUInt64): Boolean;
{* 该 UInt64 被当成 Int64 时是否小于 0}

function GetUInt64BitSet(B: TUInt64; Index: Integer): Boolean;
{* 返回 Int64 的某一位是否是 1,位 Index 从 0 开始}

function GetUInt64HighBits(B: TUInt64): Integer;
{* 返回 Int64 的最高二进制位是第几位,最低位是 0}

implementation

{
Expand Down Expand Up @@ -291,4 +297,27 @@ function UInt64IsNegative(N: TUInt64): Boolean;
{$ENDIF}
end;

// 返回 UInt64 的第几位是否是 1,0 开始
function GetUInt64BitSet(B: TUInt64; Index: Integer): Boolean;
begin
B := B and (TUInt64(1) shl Index);
Result := B <> 0;
end;

// 返回 UInt64 的最高二进制位是第几位,0 开始
function GetUInt64HighBits(B: TUInt64): Integer;
var
J: Integer;
begin
for J := 63 downto 0 do
begin
if GetUInt64BitSet(B, J) then
begin
Result := J;
Exit;
end;
end;
Result := 0;
end;

end.

0 comments on commit adcc0a0

Please sign in to comment.