5 type tEccKey
=ed25519
.tKey32
;
6 type tPoWTimeStamp
=Word;
8 var SecretKey
:ed25519
.tKey64
;
10 var PublicPoW
:tEccKey
;
12 var ZeroDigest
:tSha1Digest
;
13 const cDig3PowMask
=%0010;
14 const cPoWValidWeeks
=1;
16 const cWeekEpoch
=40179;
17 procedure CreateChallenge(out Challenge
: tEccKey
);
18 procedure CreateResponse(const Challenge
: tEccKey
; out Response
: tSha1Digest
; const srce
:tEccKey
);
19 function VerifyPoW(const proof
:tEccKey
; const RemotePub
:tEccKey
; const stamp
:Word):boolean;
21 operator
:=(k
:tEccKey
) s
:string;
24 uses SysUtils
,StrUtils
,DateUtils
;
26 procedure CreateChallenge(out Challenge
: tEccKey
);
29 for i
:=0 to 31 do challenge
[i
]:=Random(256);
32 procedure CreateResponse(const Challenge
: tEccKey
; out Response
: tSha1Digest
; const srce
:tEccKey
);
34 var shactx
:tSha1Context
;
36 ed25519
.SharedSecret(shared
,srce
,secretkey
);
38 Sha1Update(shactx
,challenge
,sizeof(challenge
));
39 Sha1Update(shactx
,shared
,sizeof(shared
));
40 Sha1Final(shactx
,Response
);
45 function VerifyPoW(const proof
:tEccKey
; const RemotePub
:tEccKey
; const stamp
:Word):boolean;
46 var shactx
:tSha1Context
;
47 var digest
:tSha1Digest
;
49 if abs(Week
-BEtoN(stamp
))<=cPoWValidWeeks
then begin
51 Sha1Update(shactx
,proof
,sizeof(proof
));
52 Sha1Update(shactx
,RemotePub
,sizeof(RemotePub
));
53 Sha1Update(shactx
,stamp
,sizeof(stamp
));
54 Sha1Final(shactx
,digest
);
55 result
:=(CompareByte(digest
,ZeroDigest
,3)=0)and((digest
[3]and cDig3PoWMask
)=0);
56 end else result
:=false;
59 const cPoWFN
='proof.dat';
60 procedure PoWLoadFromFile
;
65 blockread(f
,PublicPoW
,sizeof(PublicPoW
));
66 blockread(f
,PublicPoWTS
,2);
69 procedure PoWGenerate
;
77 write('ECC: Generating PoW, this may take a while...');
78 PublicPowTS
:=NtoBE(Week
);
79 Start
:=Now
; counter
:=0;
81 for i
:=0 to 31 do PublicPoW
[i
]:=Random(256);
83 until VerifyPoW(PublicPoW
,PublicKey
,PublicPoWTS
);
84 writeln(' PoW found in ',(Now
-start
)*SecsPerDay
:1:0,'s speed=',counter
/((Now
-start
)*SecsPerDay
):1:0,'h/s');
85 blockwrite(f
,PublicPoW
,sizeof(PublicPoW
));
86 blockwrite(f
,PublicPoWTS
,sizeof(PublicPoWTS
));
90 const cSeckeyFN
='secret.dat';
91 procedure LoadFromFile
;
92 var f
:file of ed25519
.tPrivKey
;
100 procedure SaveGenerated
;
101 var f
:file of ed25519
.tPrivKey
;
112 var f
:file of ed25519
.tPrivKey
;
114 assign(f
,'/dev/urandom');
120 {$WARNING Not enough Random in windows license key}
121 {$ERROR This unit requires UNIX-compatile operating system}
125 procedure DerivePublic
;
127 CreatekeyPair(PublicKey
,SecretKey
);
130 operator
:=(k
:tEccKey
) s
:string;
133 BinToHex(@k
,@s
[1],32);
137 FillChar(ZeroDigest
,sizeof(ZeroDigest
),0);
138 week
:=trunc((Now
-cWeekEpoch
)/cWeekDays
);
139 //writeln('ECC: Today is W',Week);
141 except on e
:Exception
do begin
142 writeln('ECC: '+e
.message+' while loading secret key');
144 (*until (PublicKey[31]=0)and(PublicKey[30]=0);*)
146 writeln('ECC: random secret key saved to '+cSecKeyFN
);
149 writeln('ECC: pubkey is ',string(PublicKey
));
152 if not VerifyPoW(PublicPoW
,PublicKey
,PublicPoWTS
)
153 then raise eXception
.Create('invalid or expired proof');
154 if (week
-BEtoN(PublicPowTS
))>=cPoWValidWeeks
155 then raise eXception
.Create('proof about to expire');
156 except on e
:Exception
do begin
157 writeln('ECC: '+e
.message+' while loading proof');
160 writeln('ECC: ProofOfWork valid for W',BEtoN(PublicPowTS
));