-
Notifications
You must be signed in to change notification settings - Fork 446
Expand file tree
/
Copy pathMessageSigner.php
More file actions
104 lines (92 loc) · 2.97 KB
/
MessageSigner.php
File metadata and controls
104 lines (92 loc) · 2.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
<?php
declare(strict_types=1);
namespace BitWasp\Bitcoin\MessageSigner;
use BitWasp\Bitcoin\Address\Address;
use BitWasp\Bitcoin\Bitcoin;
use BitWasp\Bitcoin\Crypto\EcAdapter\Adapter\EcAdapterInterface;
use BitWasp\Bitcoin\Crypto\EcAdapter\Key\PrivateKeyInterface;
use BitWasp\Bitcoin\Crypto\Hash;
use BitWasp\Bitcoin\Crypto\Random\Rfc6979;
use BitWasp\Bitcoin\Network\NetworkInterface;
use BitWasp\Buffertools\Buffer;
use BitWasp\Buffertools\BufferInterface;
use BitWasp\Buffertools\Buffertools;
class MessageSigner
{
/**
* @var EcAdapterInterface
*/
private $ecAdapter;
/**
* @param EcAdapterInterface $ecAdapter
*/
public function __construct(EcAdapterInterface $ecAdapter = null)
{
$this->ecAdapter = $ecAdapter ?: Bitcoin::getEcAdapter();
}
/**
* @param NetworkInterface $network
* @param string $message
* @return BufferInterface
* @throws \Exception
*/
private function calculateBody(NetworkInterface $network, string $message): BufferInterface
{
$prefix = sprintf("%s:\n", $network->getSignedMessageMagic());
return new Buffer(sprintf(
"%s%s%s%s",
Buffertools::numToVarInt(strlen($prefix))->getBinary(),
$prefix,
Buffertools::numToVarInt(strlen($message))->getBinary(),
$message
));
}
/**
* @param NetworkInterface $network
* @param string $message
* @return BufferInterface
*/
public function calculateMessageHash(NetworkInterface $network, string $message): BufferInterface
{
return Hash::sha256d($this->calculateBody($network, $message));
}
/**
* @param SignedMessage $signedMessage
* @param Address $address
* @param NetworkInterface|null $network
* @return bool
*/
public function verify(SignedMessage $signedMessage, Address $address, NetworkInterface $network = null): bool
{
$network = $network ?: Bitcoin::getNetwork();
$hash = $this->calculateMessageHash($network, $signedMessage->getMessage());
$publicKey = $this->ecAdapter->recover(
$hash,
$signedMessage->getCompactSignature()
);
return $publicKey->getPubKeyHash()->equals($address->getHash());
}
/**
* @param string $message
* @param PrivateKeyInterface $privateKey
* @param NetworkInterface|null $network
* @return SignedMessage
*/
public function sign(string $message, PrivateKeyInterface $privateKey, NetworkInterface $network = null): SignedMessage
{
$network = $network ?: Bitcoin::getNetwork();
$hash = $this->calculateMessageHash($network, $message);
return new SignedMessage(
$message,
$privateKey->signCompact(
$hash,
new Rfc6979(
$this->ecAdapter,
$privateKey,
$hash,
'sha256'
)
)
);
}
}