11<?php
22
3- namespace AndKom \Bitcoin \Blockchain ;
3+ namespace AndKom \Bitcoin \Blockchain \ Crypto ;
44
5- use AndKom \Bitcoin \Blockchain \Exception \PublicKeyException ;
5+ use AndKom \Bitcoin \Blockchain \Exception \CryptoException ;
6+ use AndKom \Bitcoin \Blockchain \Utils ;
67use Mdanter \Ecc \EccFactory ;
78
89/**
910 * Class PublicKey
10- * @package AndKom\Bitcoin\Blockchain
11+ * @package AndKom\Bitcoin\Blockchain\Crypto
1112 */
1213class PublicKey
1314{
@@ -56,12 +57,12 @@ public function getX(): \GMP
5657
5758 /**
5859 * @return \GMP
59- * @throws PublicKeyException
60+ * @throws CryptoException
6061 */
6162 public function getY (): \GMP
6263 {
6364 if ($ this ->isCompressed ()) {
64- throw new PublicKeyException ("Compressed public key doesn't have Y coordinate. " );
65+ throw new CryptoException ("Compressed public key doesn't have Y coordinate. " );
6566 }
6667
6768 return $ this ->y ;
@@ -83,28 +84,14 @@ public function isCompressed(): bool
8384 return is_null ($ this ->y );
8485 }
8586
86- /**
87- * @return bool
88- */
89- public function isValid (): bool
90- {
91- try {
92- $ this ->getEccPublicKey ();
93- } catch (\Exception $ exception ) {
94- return false ;
95- }
96-
97- return true ;
98- }
99-
10087 /**
10188 * @return PublicKey
102- * @throws PublicKeyException
89+ * @throws CryptoException
10390 */
10491 public function compress (): self
10592 {
10693 if ($ this ->isCompressed ()) {
107- throw new PublicKeyException ('Public key is already compressed. ' );
94+ throw new CryptoException ('Public key is already compressed. ' );
10895 }
10996
11097 $ wasOdd = gmp_cmp (
@@ -117,12 +104,12 @@ public function compress(): self
117104
118105 /**
119106 * @return PublicKey
120- * @throws PublicKeyException
107+ * @throws CryptoException
121108 */
122109 public function decompress (): self
123110 {
124111 if (!$ this ->isCompressed ()) {
125- throw new PublicKeyException ('Public key is already decompressed. ' );
112+ throw new CryptoException ('Public key is already decompressed. ' );
126113 }
127114
128115 $ curve = EccFactory::getSecgCurves ()->generator256k1 ()->getCurve ();
@@ -133,7 +120,7 @@ public function decompress(): self
133120
134121 /**
135122 * @return \Mdanter\Ecc\Crypto\Key\PublicKey
136- * @throws PublicKeyException
123+ * @throws CryptoException
137124 */
138125 public function getEccPublicKey (): \Mdanter \Ecc \Crypto \Key \PublicKey
139126 {
@@ -155,7 +142,7 @@ public function getEccPublicKey(): \Mdanter\Ecc\Crypto\Key\PublicKey
155142 /**
156143 * @param string $data
157144 * @return PublicKey
158- * @throws PublicKeyException
145+ * @throws CryptoException
159146 */
160147 static public function parse (string $ data ): self
161148 {
@@ -165,7 +152,7 @@ static public function parse(string $data): self
165152 $ prefix = $ data [0 ];
166153
167154 if ($ prefix != static ::PREFIX_COMPRESSED_ODD && $ prefix != static ::PREFIX_COMPRESSED_EVEN ) {
168- throw new PublicKeyException ('Invalid compressed public key prefix. ' );
155+ throw new CryptoException ('Invalid compressed public key prefix. ' );
169156 }
170157
171158 $ x = Utils::binToGmp (substr ($ data , 1 , 32 ));
@@ -174,13 +161,13 @@ static public function parse(string $data): self
174161 $ prefix = $ data [0 ];
175162
176163 if ($ prefix != static ::PREFIX_UNCOMPRESSED ) {
177- throw new PublicKeyException ('Invalid uncompressed public key prefix. ' );
164+ throw new CryptoException ('Invalid uncompressed public key prefix. ' );
178165 }
179166
180167 $ x = Utils::binToGmp (substr ($ data , 1 , 32 ));
181168 $ y = Utils::binToGmp (substr ($ data , 33 , 32 ));
182169 } else {
183- throw new PublicKeyException ('Invalid public key size. ' );
170+ throw new CryptoException ('Invalid public key size. ' );
184171 }
185172
186173 return new static ($ x , $ y , $ prefix == static ::PREFIX_COMPRESSED_ODD );
@@ -203,4 +190,43 @@ public function serialize(): string
203190
204191 return $ prefix . $ x . $ y ;
205192 }
193+
194+ /**
195+ * @param string $pubKey
196+ * @return bool
197+ */
198+ static public function isValid (string $ pubKey ): bool
199+ {
200+ $ length = strlen ($ pubKey );
201+
202+ if ($ length == static ::LENGTH_COMPRESSED && ($ pubKey [0 ] == static ::PREFIX_COMPRESSED_ODD || $ pubKey [0 ] == static ::PREFIX_COMPRESSED_EVEN )) {
203+ return true ;
204+ }
205+
206+ if ($ length == static ::LENGTH_UNCOMPRESSED && $ pubKey [0 ] == static ::PREFIX_UNCOMPRESSED ) {
207+ return true ;
208+ }
209+
210+ return false ;
211+ }
212+
213+ /**
214+ * @param string $pubKey
215+ * @return bool
216+ */
217+ static public function isFullyValid (string $ pubKey ): bool
218+ {
219+ if (!static ::isValid ($ pubKey )) {
220+ return false ;
221+ }
222+
223+ try {
224+ $ key = static ::parse ($ pubKey );
225+ $ key ->getEccPublicKey ();
226+ } catch (\Exception $ exception ) {
227+ return false ;
228+ }
229+
230+ return true ;
231+ }
206232}
0 commit comments