refactor: remove sha.js in favour of nobel hashes

This commit is contained in:
kyranjamie
2022-12-08 16:41:04 +01:00
committed by kyranjamie
parent 6f32662361
commit b032debbcd
9 changed files with 94 additions and 89 deletions

View File

@@ -129,6 +129,7 @@
"@emotion/react": "11.7.1",
"@emotion/styled": "11.6.0",
"@ledgerhq/hw-transport-webusb": "6.24.1",
"@noble/hashes": "1.1.4",
"@noble/secp256k1": "1.6.3",
"@reach/alert": "0.15.3",
"@reach/auto-id": "0.15.3",
@@ -178,7 +179,7 @@
"ecdsa-sig-formatter": "1.0.11",
"formik": "2.2.9",
"jotai": "1.5.3",
"jsontokens": "3.0.0",
"jsontokens": "4.0.1",
"limiter": "2.1.0",
"lodash.get": "4.4.2",
"mdi-react": "7.5.0",
@@ -199,7 +200,6 @@
"react-virtuoso": "2.19.1",
"redux-persist": "6.0.0",
"rxjs": "7.5.7",
"sha.js": "2.4.11",
"ts-debounce": "4",
"use-events": "1.4.2",
"use-latest": "1.2.0",

View File

@@ -34,9 +34,7 @@ export function LedgerScreenDetail(props: LedgerScreenDetailProps) {
)}
</Caption>
<Flex alignItems="center" mt="base">
<Text overflowWrap="break-word" maxWidth={['280px', '360px']}>
{children}
</Text>
<Text overflowWrap="break-word">{children}</Text>
</Flex>
</Flex>
);

View File

@@ -1,6 +1,7 @@
import { sha256 } from '@noble/hashes/sha256';
import { bytesToHex } from '@stacks/common';
import StacksApp from '@zondax/ledger-stacks';
import ecdsaFormat from 'ecdsa-sig-formatter';
import { sha256 } from 'sha.js';
import { getIdentityDerivationPath } from '../../ledger-utils';
@@ -17,7 +18,7 @@ export function addSignatureToAuthResponseJwt(authResponse: string, signature: U
}
export function getSha256HashOfJwtAuthPayload(payload: string) {
return new sha256().update(payload).digest('hex');
return bytesToHex(sha256(payload));
}
export function signLedgerJwtHash(app: StacksApp) {

View File

@@ -0,0 +1,36 @@
import { sha256 } from '@noble/hashes/sha256';
import { bytesToHex } from '@stacks/common';
import {
ChainID,
ClarityType,
ClarityValue,
cvToString,
encodeStructuredData,
} from '@stacks/transactions';
import { SignedMessageStructured } from '@shared/signature/signature-types';
import { whenStxChainId } from '@app/common/utils';
export function cvToDisplay(cv: ClarityValue): string {
return cvToString(cv).replaceAll('"', '');
}
export function chainIdToDisplay(chainIdCv: ClarityValue): string {
if (chainIdCv.type !== ClarityType.UInt) return '';
const chainIdString = cvToString(chainIdCv);
const chainId = parseInt(chainIdString.replace('u', ''));
if (!Object.values(ChainID).includes(chainId)) return '';
return whenStxChainId(chainId as ChainID)({
[ChainID.Testnet]: 'Testnet',
[ChainID.Mainnet]: 'Mainnet',
});
}
export function deriveStructuredMessageHash({
domain,
message,
}: Omit<SignedMessageStructured, 'messageType'>) {
return bytesToHex(sha256(encodeStructuredData({ message, domain })));
}

View File

@@ -1,13 +1,12 @@
import { useContext } from 'react';
import { cvToString } from '@stacks/transactions';
import { logger } from '@shared/logger';
import { whenSignedMessageOfType } from '@shared/signature/signature-types';
import { ApproveLedgerOperationLayout } from '../../../generic-steps';
import { useHasApprovedOperation } from '../../../hooks/use-has-approved-transaction';
import { ledgerMsgSigningContext } from '../ledger-sign-msg.context';
import { cvToDisplay, deriveStructuredMessageHash } from '../message-signing.utils';
export function SignLedgerMessage() {
const { message } = useContext(ledgerMsgSigningContext);
@@ -26,16 +25,26 @@ export function SignLedgerMessage() {
status={hasApprovedOperation ? 'approved' : 'awaiting-approval'}
/>
),
structured: domain => (
<ApproveLedgerOperationLayout
description="Sign structured data on your Ledger"
details={[
['Chain ID', cvToString(domain.data['chain-id'])],
['Name', cvToString(domain.data.name)],
['Version', cvToString(domain.data.version)],
]}
status={hasApprovedOperation ? 'approved' : 'awaiting-approval'}
/>
),
structured: (domain, message) => {
const ledgerFirstHashPageInView = 34;
const hash = deriveStructuredMessageHash({ domain, message });
const [hashPart1, hashPart2] = [
hash.slice(0, ledgerFirstHashPageInView),
hash.slice(ledgerFirstHashPageInView),
];
return (
<ApproveLedgerOperationLayout
description="Sign structured data on your Ledger"
details={[
['Chain ID', cvToDisplay(domain.data['chain-id'])],
['Name', cvToDisplay(domain.data.name)],
['Version', cvToDisplay(domain.data.version)],
['Message hash [1/2]', hashPart1],
['Message hash [2/2]', hashPart2],
]}
status={hasApprovedOperation ? 'approved' : 'awaiting-approval'}
/>
);
},
}) as JSX.Element;
}

View File

@@ -9,7 +9,8 @@ import {
chainIdToDisplay,
cvToDisplay,
deriveStructuredMessageHash,
} from '../message-signing.utils';
} from '@app/features/ledger/flows/message-signing/message-signing.utils';
import { ClarityValueListDisplayer } from './clarity-value-list';
import { HashDrawer } from './hash-drawer';

View File

@@ -1,21 +1,10 @@
import { useCallback } from 'react';
import {
ChainID,
ClarityType,
ClarityValue,
TupleCV,
createStacksPrivateKey,
cvToString,
encodeStructuredData,
} from '@stacks/transactions';
import { sha256 } from 'sha.js';
import { ClarityValue, TupleCV, createStacksPrivateKey } from '@stacks/transactions';
import { signMessage, signStructuredDataMessage } from '@shared/crypto/sign-message';
import { SignedMessageStructured } from '@shared/signature/signature-types';
import { isString } from '@shared/utils';
import { whenStxChainId } from '@app/common/utils';
import { useCurrentAccount } from '@app/store/accounts/account.hooks';
export function useMessageSignerSoftwareWallet() {
@@ -35,26 +24,3 @@ export function useMessageSignerSoftwareWallet() {
[account]
);
}
export function cvToDisplay(cv: ClarityValue): string {
return cvToString(cv).replaceAll('"', '');
}
export function chainIdToDisplay(chainIdCv: ClarityValue): string {
if (chainIdCv.type !== ClarityType.UInt) return '';
const chainIdString = cvToString(chainIdCv);
const chainId = parseInt(chainIdString.replace('u', ''));
if (!Object.values(ChainID).includes(chainId)) return '';
return whenStxChainId(chainId as ChainID)({
[ChainID.Testnet]: 'Testnet',
[ChainID.Mainnet]: 'Mainnet',
});
}
export function deriveStructuredMessageHash({
domain,
message,
}: Omit<SignedMessageStructured, 'messageType'>) {
return new sha256().update(encodeStructuredData({ message, domain })).digest('hex');
}

View File

@@ -1,15 +1,22 @@
import React, { useEffect, useState } from 'react';
import { Box, Button, Text } from '@stacks/ui';
import {
stacksMainnetNetwork,
stacksTestnetNetwork as network,
stacksTestnetNetwork,
} from '@common/utils';
import { SignatureData } from '@stacks/connect';
import {
stacksTestnetNetwork as network,
stacksMainnetNetwork,
stacksTestnetNetwork,
} from '@common/utils';
import { sha256 } from '@noble/hashes/sha256';
import { bytesToHex } from '@noble/hashes/utils';
import { SignatureData } from '@stacks/connect';
import { useConnect } from '@stacks/connect-react';
import { hashMessage, verifyMessageSignatureRsv } from '@stacks/encryption';
import { StacksNetwork } from '@stacks/network';
import {
ClarityValue,
TupleCV,
bufferCVFromString,
contractPrincipalCV,
encodeStructuredData,
falseCV,
intCV,
listCV,
@@ -23,14 +30,8 @@ import {
trueCV,
tupleCV,
uintCV,
ClarityValue,
encodeStructuredData,
TupleCV,
} from '@stacks/transactions';
import { useConnect } from '@stacks/connect-react';
import { hashMessage, verifyMessageSignatureRsv } from '@stacks/encryption';
import { sha256 } from 'sha.js';
import { StacksNetwork } from '@stacks/network';
import { Box, Button, Text } from '@stacks/ui';
export const Signature = () => {
const [signature, setSignature] = useState<SignatureData | undefined>();
@@ -90,7 +91,7 @@ export const Signature = () => {
useEffect(() => {
if (!signatureStructured || !currentStructuredData) return;
const message = encodeStructuredData(currentStructuredData);
const messageHash = new sha256().update(message).digest('hex');
const messageHash = bytesToHex(sha256(message));
const verified = verifyMessageSignatureRsv({
...signatureStructured,
message: Buffer.from(messageHash, 'hex'),

View File

@@ -2281,6 +2281,11 @@
strict-event-emitter "^0.2.0"
xmldom "^0.6.0"
"@noble/hashes@1.1.4":
version "1.1.4"
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.1.4.tgz#2611ebf5764c1bf754da7c7794de4fb30512336d"
integrity sha512-+PYsVPrTSqtVjatKt2A/Proukn2Yrz61OBThOCKErc5w2/r1Fh37vbDv0Eah7pyNltrmacjwTvdw3JoR+WE4TA==
"@noble/hashes@^1.0.0", "@noble/hashes@^1.1.2", "@noble/hashes@^1.1.3", "@noble/hashes@~1.1.1", "@noble/hashes@~1.1.3":
version "1.1.3"
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.1.3.tgz#360afc77610e0a61f3417e497dcf36862e4f8111"
@@ -5865,7 +5870,7 @@
resolved "https://registry.yarnpkg.com/@types/dragula/-/dragula-3.7.1.tgz#79940c2b9a9f0bc5f7d0c486f2cb56651f73170c"
integrity sha512-hbMEG5+wZEwV6NK4cbexldLWEvYNox8PywM9ICIeCTM99g8nJxccE3C8vvl66TCfnN+R8ioNdOrHWJT+5X0pvw==
"@types/elliptic@^6.4.12", "@types/elliptic@^6.4.9":
"@types/elliptic@^6.4.12":
version "6.4.14"
resolved "https://registry.yarnpkg.com/@types/elliptic/-/elliptic-6.4.14.tgz#7bbaad60567a588c1f08b10893453e6b9b4de48e"
integrity sha512-z4OBcDAU0GVwDTuwJzQCiL6188QvZMkvoERgcVjq0/mPM8jCfdwZ3x5zQEVoL9WCAru3aG5wl3Z5Ww5wBWn7ZQ==
@@ -7493,7 +7498,7 @@ array.prototype.flat@^1.2.5:
es-abstract "^1.19.2"
es-shim-unscopables "^1.0.0"
asn1.js@^5.0.1, asn1.js@^5.2.0:
asn1.js@^5.2.0:
version "5.4.1"
resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07"
integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==
@@ -7806,7 +7811,7 @@ base64id@1.0.0:
resolved "https://registry.yarnpkg.com/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6"
integrity sha512-rz8L+d/xByiB/vLVftPkyY215fqNrmasrcJsYkVcm4TgJNz+YXKrFaFAWibSaHkiKoSgMDCb+lipOIRQNGYesw==
base64url@3.0.1, base64url@^3.0.1:
base64url@3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/base64url/-/base64url-3.0.1.tgz#6399d572e2bc3f90a9a8b22d5dbb0a32d33f788d"
integrity sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==
@@ -9899,7 +9904,7 @@ ecc-jsbn@~0.1.1:
jsbn "~0.1.0"
safer-buffer "^2.1.0"
ecdsa-sig-formatter@1.0.11, ecdsa-sig-formatter@^1.0.11:
ecdsa-sig-formatter@1.0.11:
version "1.0.11"
resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf"
integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==
@@ -9925,7 +9930,7 @@ electron@^18.0.1:
"@types/node" "^16.11.26"
extract-zip "^1.0.3"
elliptic@^6.4.0, elliptic@^6.4.1, elliptic@^6.5.2, elliptic@^6.5.3:
elliptic@^6.4.0, elliptic@^6.5.2, elliptic@^6.5.3:
version "6.5.4"
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb"
integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==
@@ -13882,19 +13887,7 @@ jsonrpc-lite@^2.2.0:
resolved "https://registry.yarnpkg.com/jsonrpc-lite/-/jsonrpc-lite-2.2.0.tgz#fb3aa9d292c8970eb7f83c6040c6554767bbc6a6"
integrity sha512-/cbbSxtZWs1O7R4tWqabrCM/t3N8qKUZMAg9IUqpPvUs6UyRvm6pCNYkskyKN/XU0UgffW+NY2ZRr8t0AknX7g==
jsontokens@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/jsontokens/-/jsontokens-3.0.0.tgz#629984d260a4081b11541313acdba708377314d3"
integrity sha512-P0QZC5AjOkn3t1ej6OuI7+XqoEctYj83UK4pw0WpHY4/z6a5PpZCJSpp5NZodq94GFkw2PfB9DPFoDM5qpyp/g==
dependencies:
"@types/elliptic" "^6.4.9"
asn1.js "^5.0.1"
base64url "^3.0.1"
ecdsa-sig-formatter "^1.0.11"
elliptic "^6.4.1"
sha.js "^2.4.11"
jsontokens@^4.0.1:
jsontokens@4.0.1, jsontokens@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/jsontokens/-/jsontokens-4.0.1.tgz#c3edf74a01160b2ca6d62b021b288edd59d1184a"
integrity sha512-+MO415LEN6M+3FGsRz4wU20g7N2JA+2j9d9+pGaNJHviG4L8N0qzavGyENw6fJqsq9CcrHOIL6iWX5yeTZ86+Q==