Use Edwards curve instead of the motogomery version.
[brdnet.git] / ECC.pas
blobd98157a8a90944c9cd2a43841da5aa8f84ea4d8a
1 unit ECC;
3 INTERFACE
4 uses ed25519,Sha1;
5 type tEccKey=ed25519.tKey32;
6 type tPoWTimeStamp=Word;
8 var SecretKey:ed25519.tKey64;
9 var PublicKey:tEccKey;
10 var PublicPoW:tEccKey;
11 var PublicPoWTS:Word;
12 var ZeroDigest:tSha1Digest;
13 const cDig3PowMask=%0010;
14 const cPoWValidWeeks=1;
15 const cWeekDays=5;
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;
23 IMPLEMENTATION
24 uses SysUtils,StrUtils,DateUtils;
26 procedure CreateChallenge(out Challenge: tEccKey);
27 var i:byte;
28 begin
29 for i:=0 to 31 do challenge[i]:=Random(256);
30 end;
32 procedure CreateResponse(const Challenge: tEccKey; out Response: tSha1Digest; const srce:tEccKey);
33 var Shared:tEccKey;
34 var shactx:tSha1Context;
35 begin
36 ed25519.SharedSecret(shared,srce,secretkey);
37 Sha1Init(shactx);
38 Sha1Update(shactx,challenge,sizeof(challenge));
39 Sha1Update(shactx,shared,sizeof(shared));
40 Sha1Final(shactx,Response);
41 end;
43 var week:Word;
45 function VerifyPoW(const proof:tEccKey; const RemotePub:tEccKey; const stamp:Word):boolean;
46 var shactx:tSha1Context;
47 var digest:tSha1Digest;
48 begin
49 if abs(Week-BEtoN(stamp))<=cPoWValidWeeks then begin
50 Sha1Init(shactx);
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;
57 end;
59 const cPoWFN='proof.dat';
60 procedure PoWLoadFromFile;
61 var f:file of byte;
62 begin
63 assign(f,cPoWFN);
64 reset(f,1);
65 blockread(f,PublicPoW,sizeof(PublicPoW));
66 blockread(f,PublicPoWTS,2);
67 close(f);
68 end;
69 procedure PoWGenerate;
70 var f:file of byte;
71 var i:byte;
72 var counter:LongWord;
73 var start:tDateTime;
74 begin
75 assign(f,cPoWFN);
76 rewrite(f,1);
77 write('ECC: Generating PoW, this may take a while...');
78 PublicPowTS:=NtoBE(Week);
79 Start:=Now; counter:=0;
80 repeat
81 for i:=0 to 31 do PublicPoW[i]:=Random(256);
82 inc(counter);
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));
87 close(f);
88 end;
90 const cSeckeyFN='secret.dat';
91 procedure LoadFromFile;
92 var f:file of ed25519.tPrivKey;
93 begin
94 assign(f,cSecKeyFN);
95 reset(f);
96 read(f,SecretKey);
97 close(f);
98 end;
100 procedure SaveGenerated;
101 var f:file of ed25519.tPrivKey;
102 begin
103 assign(f,cSecKeyFN);
104 rewrite(f);
105 //fpchmod
106 write(f,SecretKey);
107 close(f);
108 end;
110 procedure Generate;
111 {$IFDEF UNIX}
112 var f:file of ed25519.tPrivKey;
113 begin
114 assign(f,'/dev/urandom');
115 reset(f);
116 read(f,SecretKey);
117 close(f);
118 {$ELSE}
119 begin
120 {$WARNING Not enough Random in windows license key}
121 {$ERROR This unit requires UNIX-compatile operating system}
122 {$ENDIF}
123 end;
125 procedure DerivePublic;
126 begin
127 CreatekeyPair(PublicKey,SecretKey);
128 end;
130 operator :=(k:tEccKey) s:string;
131 begin
132 Setlength(s,64);
133 BinToHex(@k,@s[1],32);
134 end;
136 BEGIN
137 FillChar(ZeroDigest,sizeof(ZeroDigest),0);
138 week:=trunc((Now-cWeekEpoch)/cWeekDays);
139 //writeln('ECC: Today is W',Week);
140 try LoadFromFile;
141 except on e:Exception do begin
142 writeln('ECC: '+e.message+' while loading secret key');
143 Generate;
144 (*until (PublicKey[31]=0)and(PublicKey[30]=0);*)
145 SaveGenerated;
146 writeln('ECC: random secret key saved to '+cSecKeyFN);
147 end end;
148 DerivePublic;
149 writeln('ECC: pubkey is ',string(PublicKey));
151 PoWLoadFromFile;
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');
158 PoWGenerate;
159 end end;
160 writeln('ECC: ProofOfWork valid for W',BEtoN(PublicPowTS));
161 END.