crypto.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. import { ADDRESS_PREFIX, ADDRESS_PREFIX_BYTE, ADDRESS_SIZE } from './address.js';
  2. import { base64EncodeToString, base64DecodeFromString, hexStr2byteArray } from './code.js';
  3. import { encode58, decode58 } from './base58.js';
  4. import { byte2hexStr, byteArray2hexStr } from './bytes.js';
  5. import { keccak256, sha256, SigningKey, recoverAddress, arrayify, Signature } from './ethersUtils.js';
  6. import { TypedDataEncoder } from './typedData.js';
  7. import { secp256k1 as secp } from 'ethereum-cryptography/secp256k1';
  8. function normalizePrivateKeyBytes(priKeyBytes) {
  9. return hexStr2byteArray(byteArray2hexStr(priKeyBytes).padStart(64, '0'));
  10. }
  11. export function getBase58CheckAddress(addressBytes) {
  12. const hash0 = SHA256(addressBytes);
  13. const hash1 = SHA256(hash0);
  14. let checkSum = hash1.slice(0, 4);
  15. checkSum = addressBytes.concat(checkSum);
  16. return encode58(checkSum);
  17. }
  18. export function decodeBase58Address(base58Sting) {
  19. if (typeof base58Sting != 'string')
  20. return false;
  21. if (base58Sting.length <= 4)
  22. return false;
  23. let address = decode58(base58Sting);
  24. if (base58Sting.length <= 4)
  25. return false;
  26. const len = address.length;
  27. const offset = len - 4;
  28. const checkSum = address.slice(offset);
  29. address = address.slice(0, offset);
  30. const hash0 = SHA256(address);
  31. const hash1 = SHA256(hash0);
  32. const checkSum1 = hash1.slice(0, 4);
  33. if (checkSum[0] == checkSum1[0] &&
  34. checkSum[1] == checkSum1[1] &&
  35. checkSum[2] == checkSum1[2] &&
  36. checkSum[3] == checkSum1[3]) {
  37. return address;
  38. }
  39. throw new Error('Invalid address provided');
  40. }
  41. // @TODO transaction type should be determined.
  42. export function signTransaction(priKeyBytes, transaction) {
  43. if (typeof priKeyBytes === 'string')
  44. priKeyBytes = hexStr2byteArray(priKeyBytes);
  45. const txID = transaction.txID;
  46. const signature = ECKeySign(hexStr2byteArray(txID), priKeyBytes);
  47. if (Array.isArray(transaction.signature)) {
  48. if (!transaction.signature.includes(signature))
  49. transaction.signature.push(signature);
  50. }
  51. else
  52. transaction.signature = [signature];
  53. return transaction;
  54. }
  55. export function ecRecover(signedData, signature) {
  56. signedData = '0x' + signedData.replace(/^0x/, '');
  57. signature = '0x' + signature.replace(/^0x/, '');
  58. const recovered = recoverAddress(arrayify(signedData), Signature.from(signature));
  59. const tronAddress = ADDRESS_PREFIX + recovered.substring(2);
  60. return tronAddress;
  61. }
  62. export function arrayToBase64String(a) {
  63. return btoa(String.fromCharCode(...a));
  64. }
  65. export function signBytes(privateKey, contents) {
  66. if (typeof privateKey === 'string')
  67. privateKey = hexStr2byteArray(privateKey);
  68. const hashBytes = SHA256(contents);
  69. const signBytes = ECKeySign(hashBytes, privateKey);
  70. return signBytes;
  71. }
  72. export function _signTypedData(domain, types, value, privateKey) {
  73. const key = `0x${privateKey.replace(/^0x/, '')}`;
  74. const signingKey = new SigningKey(key);
  75. const messageDigest = TypedDataEncoder.hash(domain, types, value);
  76. const signature = signingKey.sign(messageDigest);
  77. const signatureHex = ['0x', signature.r.substring(2), signature.s.substring(2), Number(signature.v).toString(16)].join('');
  78. return signatureHex;
  79. }
  80. export function getRowBytesFromTransactionBase64(base64Data) {
  81. const bytesDecode = base64DecodeFromString(base64Data);
  82. // eslint-disable-next-line @typescript-eslint/ban-ts-comment
  83. // @ts-ignore
  84. const transaction = globalThis.proto.protocol.Transaction.deserializeBinary(bytesDecode);
  85. const raw = transaction.getRawData();
  86. return raw.serializeBinary();
  87. }
  88. export function genPriKey() {
  89. const priKey = secp.utils.randomPrivateKey();
  90. let priKeyHex = byteArray2hexStr(priKey);
  91. priKeyHex = priKeyHex.padStart(64, '0');
  92. return hexStr2byteArray(priKeyHex);
  93. }
  94. export function computeAddress(pubBytes) {
  95. if (pubBytes.length === 65)
  96. pubBytes = pubBytes.slice(1);
  97. const hash = keccak256(new Uint8Array(pubBytes)).toString().substring(2);
  98. const addressHex = ADDRESS_PREFIX + hash.substring(24);
  99. return hexStr2byteArray(addressHex);
  100. }
  101. export function getAddressFromPriKey(priKeyBytes) {
  102. const pubBytes = getPubKeyFromPriKey(priKeyBytes);
  103. return computeAddress(pubBytes);
  104. }
  105. export function decode58Check(addressStr) {
  106. const decodeCheck = decode58(addressStr);
  107. if (decodeCheck.length <= 4)
  108. return false;
  109. const decodeData = decodeCheck.slice(0, decodeCheck.length - 4);
  110. const hash0 = SHA256(decodeData);
  111. const hash1 = SHA256(hash0);
  112. if (hash1[0] === decodeCheck[decodeData.length] &&
  113. hash1[1] === decodeCheck[decodeData.length + 1] &&
  114. hash1[2] === decodeCheck[decodeData.length + 2] &&
  115. hash1[3] === decodeCheck[decodeData.length + 3]) {
  116. return decodeData;
  117. }
  118. return false;
  119. }
  120. export function isAddressValid(base58Str) {
  121. if (typeof base58Str !== 'string')
  122. return false;
  123. if (base58Str.length !== ADDRESS_SIZE)
  124. return false;
  125. let address = decode58(base58Str);
  126. if (address.length !== 25)
  127. return false;
  128. if (address[0] !== ADDRESS_PREFIX_BYTE)
  129. return false;
  130. const checkSum = address.slice(21);
  131. address = address.slice(0, 21);
  132. const hash0 = SHA256(address);
  133. const hash1 = SHA256(hash0);
  134. const checkSum1 = hash1.slice(0, 4);
  135. if (checkSum[0] == checkSum1[0] &&
  136. checkSum[1] == checkSum1[1] &&
  137. checkSum[2] == checkSum1[2] &&
  138. checkSum[3] == checkSum1[3]) {
  139. return true;
  140. }
  141. return false;
  142. }
  143. export function getBase58CheckAddressFromPriKeyBase64String(priKeyBase64String) {
  144. const priKeyBytes = base64DecodeFromString(priKeyBase64String);
  145. const pubBytes = getPubKeyFromPriKey(priKeyBytes);
  146. const addressBytes = computeAddress(pubBytes);
  147. return getBase58CheckAddress(addressBytes);
  148. }
  149. export function getHexStrAddressFromPriKeyBase64String(priKeyBase64String) {
  150. const priKeyBytes = base64DecodeFromString(priKeyBase64String);
  151. const pubBytes = getPubKeyFromPriKey(priKeyBytes);
  152. const addressBytes = computeAddress(pubBytes);
  153. const addressHex = byteArray2hexStr(addressBytes);
  154. return addressHex;
  155. }
  156. export function getAddressFromPriKeyBase64String(priKeyBase64String) {
  157. const priKeyBytes = base64DecodeFromString(priKeyBase64String);
  158. const pubBytes = getPubKeyFromPriKey(priKeyBytes);
  159. const addressBytes = computeAddress(pubBytes);
  160. const addressBase64 = base64EncodeToString(addressBytes);
  161. return addressBase64;
  162. }
  163. export function getPubKeyFromPriKey(priKeyBytes) {
  164. const pubkey = secp.ProjectivePoint.fromPrivateKey(new Uint8Array(normalizePrivateKeyBytes(priKeyBytes)));
  165. const x = pubkey.x;
  166. const y = pubkey.y;
  167. const xHex = x.toString(16).padStart(64, '0');
  168. const yHex = y.toString(16).padStart(64, '0');
  169. const pubkeyHex = `04${xHex}${yHex}`;
  170. const pubkeyBytes = hexStr2byteArray(pubkeyHex);
  171. return pubkeyBytes;
  172. }
  173. export function ECKeySign(hashBytes, priKeyBytes) {
  174. const signature = secp.sign(byteArray2hexStr(hashBytes), byteArray2hexStr(priKeyBytes));
  175. const r = signature.r.toString(16);
  176. const s = signature.s.toString(16);
  177. const v = signature.recovery + 27;
  178. return r.padStart(64, '0') + s.padStart(64, '0') + byte2hexStr(v);
  179. }
  180. export function SHA256(msgBytes) {
  181. const msgHex = byteArray2hexStr(msgBytes);
  182. const hashHex = sha256('0x' + msgHex).replace(/^0x/, '');
  183. return hexStr2byteArray(hashHex);
  184. }
  185. export function passwordToAddress(password) {
  186. const com_priKeyBytes = base64DecodeFromString(password);
  187. const com_addressBytes = getAddressFromPriKey(com_priKeyBytes);
  188. return getBase58CheckAddress(com_addressBytes);
  189. }
  190. export function pkToAddress(privateKey, strict = false) {
  191. const com_priKeyBytes = hexStr2byteArray(privateKey, strict);
  192. const com_addressBytes = getAddressFromPriKey(com_priKeyBytes);
  193. return getBase58CheckAddress(com_addressBytes);
  194. }
  195. export function sha3(string, prefix = true) {
  196. return (prefix ? '0x' : '') + keccak256(Buffer.from(string, 'utf-8')).toString().substring(2);
  197. }
  198. //# sourceMappingURL=crypto.js.map