The Upload (FS) shoud work. Not tested.
[brdnet.git] / ECC.pas
blob2150635f76dc7f66125ce7fa3a266cfd4f8645ad
1 unit ECC;
3 INTERFACE
4 uses ed25519,Sha1;
5 type tEccKey=ed25519.tKey32;
6 type tPoWRec=packed record
7 data:ed25519.tKey32;
8 stamp:LongWord; {NetOrder}
9 end;
11 var SecretKey:ed25519.tKey64;
12 var PublicKey:tEccKey;
13 var PublicPoW:tPoWRec;
14 var ZeroDigest:tSha1Digest;
15 const cDig3PowMask=%0010;
16 const cPoWValidDays=5;
17 const cTSEpoch=40179;
18 procedure CreateChallenge(out Challenge: tEccKey);
19 procedure CreateResponse(const Challenge: tEccKey; out Response: tSha1Digest; const srce:tEccKey);
20 function VerifyPoW(const proof:tPoWRec; const RemotePub:tEccKey):boolean;
22 operator :=(k:tEccKey) s:string;
24 IMPLEMENTATION
25 uses SysUtils,StrUtils,DateUtils;
27 procedure CreateChallenge(out Challenge: tEccKey);
28 var i:byte;
29 begin
30 for i:=0 to 31 do challenge[i]:=Random(256);
31 end;
33 procedure CreateResponse(const Challenge: tEccKey; out Response: tSha1Digest; const srce:tEccKey);
34 var Shared:tEccKey;
35 var shactx:tSha1Context;
36 begin
37 ed25519.SharedSecret(shared,srce,secretkey);
38 Sha1Init(shactx);
39 Sha1Update(shactx,challenge,sizeof(challenge));
40 Sha1Update(shactx,shared,sizeof(shared));
41 Sha1Final(shactx,Response);
42 end;
44 var TSNow:LongWord;
46 function VerifyPoW(const proof:tPoWRec; const RemotePub:tEccKey):boolean;
47 var shactx:tSha1Context;
48 var digest:tSha1Digest;
49 var delta:Integer;
50 begin
51 delta:=TSNow-BEtoN(proof.stamp);
52 if (delta<=cPoWValidDays) and (delta>=-1) then begin
53 Sha1Init(shactx);
54 Sha1Update(shactx,proof,sizeof(proof));
55 Sha1Update(shactx,RemotePub,sizeof(RemotePub));
56 Sha1Final(shactx,digest);
57 result:=(CompareByte(digest,ZeroDigest,3)=0)and((digest[3]and cDig3PoWMask)=0);
58 end else result:=false;
59 end;
61 const cPoWFN='proof.dat';
62 procedure PoWLoadFromFile;
63 var f:file of tPoWRec;
64 begin
65 assign(f,cPoWFN);
66 reset(f);
67 read(f,PublicPoW);
68 close(f);
69 end;
70 procedure PoWGenerate;
71 var f:file of tPoWRec;
72 var i:byte;
73 var counter:LongWord;
74 var start:tDateTime;
75 begin
76 assign(f,cPoWFN);
77 rewrite(f);
78 write('ECC: Generating PoW, this may take a while...');
79 PublicPow.stamp:=NtoBE(TSNow);
80 Start:=Now; counter:=0;
81 repeat
82 for i:=0 to 31 do PublicPoW.data[i]:=Random(256);
83 inc(counter);
84 until VerifyPoW(PublicPoW,PublicKey);
85 writeln(' PoW found in ',(Now-start)*SecsPerDay:1:0,'s speed=',counter/((Now-start)*SecsPerDay):1:0,'h/s');
86 write(f,PublicPoW);
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 TSNow:=trunc(Now-cTSEpoch);
139 //writeln('ECC: Today is W',TSNow);
140 try LoadFromFile;
141 except on e:Exception do begin
142 writeln('ECC: '+cSecKeyFN+' '+e.message+' while loading secret key, generating new keypair');
143 Generate;
144 (*until (PublicKey[31]=0)and(PublicKey[30]=0);*)
145 SaveGenerated;
146 end end;
147 DerivePublic;
148 writeln('ECC: pubkey is ',string(PublicKey));
150 PoWLoadFromFile;
151 if not VerifyPoW(PublicPoW,PublicKey)
152 then raise eXception.Create('invalid or expired proof');
153 if (TSNow-BEtoN(PublicPow.Stamp))>=cPoWValidDays
154 then raise eXception.Create('proof about to expire');
155 except on e:Exception do begin
156 writeln('ECC: '+cPOWFN+' '+e.message+' while loading proof');
157 PoWGenerate;
158 end end;
159 //writeln('ECC: ProofOfWork valid for W',BEtoN(PublicPow.Stamp));
160 END.