KeyPair.php 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. <?php
  2. namespace Elliptic\EdDSA;
  3. use Elliptic\Utils;
  4. class KeyPair {
  5. public $eddsa;
  6. public $_pubBytes;
  7. /**
  8. * @param {\Elliptic\EdDSA} eddsa - instance
  9. * @param {Object} params - public/private key parameters
  10. *
  11. * @param {Array<Byte>} [params.secret] - secret seed bytes
  12. * @param {Point} [params.pub] - public key point (aka `A` in eddsa terms)
  13. * @param {Array<Byte>} [params.pub] - public key point encoded as bytes
  14. *
  15. */
  16. function __construct($eddsa, #[\SensitiveParameter]
  17. $params) {
  18. $this->eddsa = $eddsa;
  19. $this->_secret = isset($params["secret"]) ? Utils::parseBytes($params["secret"]) : null;
  20. if (!isset($params["pub"])) {
  21. $this->_pub = null;
  22. $this->_pubBytes = null;
  23. return;
  24. }
  25. if ($eddsa->isPoint($params["pub"]))
  26. $this->_pub = $params["pub"];
  27. else
  28. $this->_pubBytes = Utils::parseBytes($params["pub"]);
  29. }
  30. public static function fromPublic($eddsa, $pub) {
  31. if ($pub instanceof KeyPair)
  32. return $pub;
  33. return new KeyPair($eddsa, [ "pub" => $pub ]);
  34. }
  35. public static function fromSecret($eddsa, #[\SensitiveParameter]
  36. $secret) {
  37. if ($secret instanceof KeyPair)
  38. return $secret;
  39. return new KeyPair($eddsa, [ "secret" => $secret ]);
  40. }
  41. private $_secret;
  42. public function secret() {
  43. return $this->_secret;
  44. }
  45. public function pubBytes() {
  46. if (!$this->_pubBytes)
  47. $this->_pubBytes = $this->eddsa->encodePoint($this->pub());
  48. return $this->_pubBytes;
  49. }
  50. private $_pub;
  51. public function pub() {
  52. if (!$this->_pub) {
  53. if ($this->_pubBytes)
  54. $this->_pub = $this->eddsa->decodePoint($this->_pubBytes);
  55. else
  56. $this->_pub = $this->eddsa->g->mul($this->priv());
  57. }
  58. return $this->_pub;
  59. }
  60. private $_privBytes;
  61. public function privBytes() {
  62. if (!$this->_privBytes) {
  63. $eddsa = $this->eddsa;
  64. $hash = $this->hash();
  65. $lastIx = $eddsa->encodingLength - 1;
  66. $a = array_slice($hash, 0, $eddsa->encodingLength);
  67. $a[0] &= 248;
  68. $a[$lastIx] &= 127;
  69. $a[$lastIx] |= 64;
  70. $this->_privBytes = $a;
  71. }
  72. return $this->_privBytes;
  73. }
  74. private $_priv;
  75. public function priv() {
  76. if (!$this->_priv) {
  77. $this->_priv = $this->eddsa->decodeInt($this->privBytes());
  78. }
  79. return $this->_priv;
  80. }
  81. private $_hash;
  82. public function hash() {
  83. if (!$this->_hash) {
  84. // TODO: !!!
  85. $hash = hash_init('sha512');
  86. hash_update($hash, Utils::toBin($this->secret()));
  87. $this->_hash = Utils::toArray( hash_final($hash), 'hex' );
  88. }
  89. return $this->_hash;
  90. }
  91. private $_messagePrefix;
  92. public function messagePrefix() {
  93. if (!$this->_messagePrefix) {
  94. $this->_messagePrefix = array_slice($this->hash(), $this->eddsa->encodingLength);
  95. }
  96. return $this->_messagePrefix;
  97. }
  98. public function sign($message) {
  99. assert($this->_secret); //, 'KeyPair can only verify');
  100. return $this->eddsa->sign($message, $this);
  101. }
  102. public function verify($message, $sig) {
  103. return $this->eddsa->verify($message, $sig, $this);
  104. }
  105. public function getSecret($enc = false) {
  106. assert($this->_secret); //, 'KeyPair is public only');
  107. return Utils::encode($this->secret(), $enc);
  108. }
  109. public function getPublic($enc = false) {
  110. return Utils::encode($this->pubBytes(), $enc);
  111. }
  112. }