@dynamic-labs-wallet/core 1.1.26 → 1.1.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.cjs CHANGED
@@ -593,6 +593,57 @@ function getEnvironmentFromUrl(url) {
593
593
  return ENVIRONMENT_ENUM.production;
594
594
  }
595
595
 
596
+ // secp256k1 group order n; ECDSA and BIP340 private keys must be in [1, n).
597
+ const SECP256K1_ORDER = BigInt('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141');
598
+ const PRIVATE_KEY_HEX_LENGTH = 64;
599
+ // A malformed key fails every ceremony attempt identically, so flag it
600
+ // non-retryable for callers wrapped in retryPromise (browser client).
601
+ const invalidPrivateKeyError = (message)=>{
602
+ const error = new Error(message);
603
+ error.isRetryable = false;
604
+ return error;
605
+ };
606
+ /**
607
+ * Validates a private key for `importPrivateKey` before any API call or MPC
608
+ * ceremony starts, and returns it normalized for the MPC importer (surrounding
609
+ * whitespace trimmed, optional `0x` prefix stripped).
610
+ *
611
+ * Every chain expects a 32-byte hex key at this layer — chain-specific input
612
+ * formats (WIF, base58, bech32, Stellar seed) are converted to hex by the chain
613
+ * clients beforehand. For secp256k1 chains (ECDSA, BIP340) the key is also
614
+ * range-checked against the curve order.
615
+ *
616
+ * Error messages report only the key's length and character class — never the
617
+ * key material itself.
618
+ */ const normalizeAndValidatePrivateKey = ({ privateKey, chainName, bitcoinConfig })=>{
619
+ const chainLabel = chainName ? ` for chain ${chainName}` : '';
620
+ if (typeof privateKey !== 'string') {
621
+ throw invalidPrivateKeyError(`Invalid private key${chainLabel}: expected a hex string, got ${typeof privateKey}`);
622
+ }
623
+ let normalized = privateKey.trim();
624
+ if (normalized.startsWith('0x') || normalized.startsWith('0X')) {
625
+ normalized = normalized.slice(2);
626
+ }
627
+ if (normalized.length !== PRIVATE_KEY_HEX_LENGTH) {
628
+ throw invalidPrivateKeyError(`Invalid private key${chainLabel}: expected ${PRIVATE_KEY_HEX_LENGTH} hex characters ` + `(32 bytes), got ${normalized.length}`);
629
+ }
630
+ if (!/^[0-9a-fA-F]+$/.test(normalized)) {
631
+ throw invalidPrivateKeyError(`Invalid private key${chainLabel}: expected ${PRIVATE_KEY_HEX_LENGTH} hex characters ` + `(32 bytes), got non-hex characters`);
632
+ }
633
+ const { signingAlgorithm } = getMPCChainConfig(chainName, bitcoinConfig);
634
+ const isSecp256k1Chain = signingAlgorithm === primitives.SigningAlgorithm.ECDSA || signingAlgorithm === primitives.SigningAlgorithm.BIP340;
635
+ if (isSecp256k1Chain) {
636
+ const keyValue = BigInt(`0x${normalized}`);
637
+ if (keyValue === 0n) {
638
+ throw invalidPrivateKeyError(`Invalid private key${chainLabel}: key cannot be zero`);
639
+ }
640
+ if (keyValue >= SECP256K1_ORDER) {
641
+ throw invalidPrivateKeyError(`Invalid private key${chainLabel}: key exceeds the secp256k1 curve order`);
642
+ }
643
+ }
644
+ return normalized;
645
+ };
646
+
596
647
  function _extends() {
597
648
  _extends = Object.assign || function assign(target) {
598
649
  for(var i = 1; i < arguments.length; i++){
@@ -1228,7 +1279,7 @@ const getRequiredExternalKeyShareId = (ks)=>{
1228
1279
  * before it is posted and surfaces in Datadog exactly as the recovery path does.
1229
1280
  */ const assertDynamicLocationsHaveExternalKeyShareId = (locations)=>locations.filter((location)=>location.location === BackupLocation.DYNAMIC).forEach((location)=>getRequiredExternalKeyShareId(location));
1230
1281
 
1231
- var version = "1.1.26";
1282
+ var version = "1.1.28";
1232
1283
 
1233
1284
  /**
1234
1285
  * Reads the Authorization header off an axios request config, which stores
@@ -3003,6 +3054,7 @@ exports.invokeCeremonyComplete = invokeCeremonyComplete;
3003
3054
  exports.isBusinessAccountActionRequired = isBusinessAccountActionRequired;
3004
3055
  exports.isEvmCompatibleChain = isEvmCompatibleChain;
3005
3056
  exports.isRecoveredForwardMpcConnectionChurn = isRecoveredForwardMpcConnectionChurn;
3057
+ exports.normalizeAndValidatePrivateKey = normalizeAndValidatePrivateKey;
3006
3058
  exports.parseNamespacedVersion = parseNamespacedVersion;
3007
3059
  exports.prepareRawMessageSigningPayload = prepareRawMessageSigningPayload;
3008
3060
  exports.sanitizeBusinessAccountSignedIntent = sanitizeBusinessAccountSignedIntent;
package/index.esm.js CHANGED
@@ -594,6 +594,57 @@ function getEnvironmentFromUrl(url) {
594
594
  return ENVIRONMENT_ENUM.production;
595
595
  }
596
596
 
597
+ // secp256k1 group order n; ECDSA and BIP340 private keys must be in [1, n).
598
+ const SECP256K1_ORDER = BigInt('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141');
599
+ const PRIVATE_KEY_HEX_LENGTH = 64;
600
+ // A malformed key fails every ceremony attempt identically, so flag it
601
+ // non-retryable for callers wrapped in retryPromise (browser client).
602
+ const invalidPrivateKeyError = (message)=>{
603
+ const error = new Error(message);
604
+ error.isRetryable = false;
605
+ return error;
606
+ };
607
+ /**
608
+ * Validates a private key for `importPrivateKey` before any API call or MPC
609
+ * ceremony starts, and returns it normalized for the MPC importer (surrounding
610
+ * whitespace trimmed, optional `0x` prefix stripped).
611
+ *
612
+ * Every chain expects a 32-byte hex key at this layer — chain-specific input
613
+ * formats (WIF, base58, bech32, Stellar seed) are converted to hex by the chain
614
+ * clients beforehand. For secp256k1 chains (ECDSA, BIP340) the key is also
615
+ * range-checked against the curve order.
616
+ *
617
+ * Error messages report only the key's length and character class — never the
618
+ * key material itself.
619
+ */ const normalizeAndValidatePrivateKey = ({ privateKey, chainName, bitcoinConfig })=>{
620
+ const chainLabel = chainName ? ` for chain ${chainName}` : '';
621
+ if (typeof privateKey !== 'string') {
622
+ throw invalidPrivateKeyError(`Invalid private key${chainLabel}: expected a hex string, got ${typeof privateKey}`);
623
+ }
624
+ let normalized = privateKey.trim();
625
+ if (normalized.startsWith('0x') || normalized.startsWith('0X')) {
626
+ normalized = normalized.slice(2);
627
+ }
628
+ if (normalized.length !== PRIVATE_KEY_HEX_LENGTH) {
629
+ throw invalidPrivateKeyError(`Invalid private key${chainLabel}: expected ${PRIVATE_KEY_HEX_LENGTH} hex characters ` + `(32 bytes), got ${normalized.length}`);
630
+ }
631
+ if (!/^[0-9a-fA-F]+$/.test(normalized)) {
632
+ throw invalidPrivateKeyError(`Invalid private key${chainLabel}: expected ${PRIVATE_KEY_HEX_LENGTH} hex characters ` + `(32 bytes), got non-hex characters`);
633
+ }
634
+ const { signingAlgorithm } = getMPCChainConfig(chainName, bitcoinConfig);
635
+ const isSecp256k1Chain = signingAlgorithm === SigningAlgorithm.ECDSA || signingAlgorithm === SigningAlgorithm.BIP340;
636
+ if (isSecp256k1Chain) {
637
+ const keyValue = BigInt(`0x${normalized}`);
638
+ if (keyValue === 0n) {
639
+ throw invalidPrivateKeyError(`Invalid private key${chainLabel}: key cannot be zero`);
640
+ }
641
+ if (keyValue >= SECP256K1_ORDER) {
642
+ throw invalidPrivateKeyError(`Invalid private key${chainLabel}: key exceeds the secp256k1 curve order`);
643
+ }
644
+ }
645
+ return normalized;
646
+ };
647
+
597
648
  function _extends() {
598
649
  _extends = Object.assign || function assign(target) {
599
650
  for(var i = 1; i < arguments.length; i++){
@@ -1229,7 +1280,7 @@ const getRequiredExternalKeyShareId = (ks)=>{
1229
1280
  * before it is posted and surfaces in Datadog exactly as the recovery path does.
1230
1281
  */ const assertDynamicLocationsHaveExternalKeyShareId = (locations)=>locations.filter((location)=>location.location === BackupLocation.DYNAMIC).forEach((location)=>getRequiredExternalKeyShareId(location));
1231
1282
 
1232
- var version = "1.1.26";
1283
+ var version = "1.1.28";
1233
1284
 
1234
1285
  /**
1235
1286
  * Reads the Authorization header off an axios request config, which stores
@@ -2879,4 +2930,4 @@ const handleAxiosError = (error, message, context, /**
2879
2930
  throw new WalletApiError(status, resolvedMessage, extractServerErrorCode(error));
2880
2931
  };
2881
2932
 
2882
- export { AuthMode, BITCOIN_ADDRESS_TYPE_CONFIG, BITCOIN_DERIVATION_PATHS, BROWSER_SDK_ROUTE_PREFIX, BackupLocation, BitcoinAddressType, BitcoinNetwork, BusinessAccountClient, BusinessAccountMemberRole, BusinessAccountSignerType, CreateRoomPartiesOptions, DEFAULT_ED25519_VARIANT, DELEGATED_SHARE_COUNT, DYNAMIC_AUTH_BASE_API_URL_MAP, DYNAMIC_AUTH_DEV_BASE_API_URL, DYNAMIC_AUTH_PREPROD_BASE_API_URL, DYNAMIC_AUTH_PROD_BASE_API_URL, DYNAMIC_CLIENT_RELAY_REDCOAST_API_KEY_MAP, DYNAMIC_CLIENT_RELAY_REDCOAST_APP_ID_MAP, DYNAMIC_FORWARD_MPC_DEV_ENCLAVE_URL, DYNAMIC_FORWARD_MPC_ENCLAVE_ATTESTATION_CONFIG_MAP, DYNAMIC_FORWARD_MPC_ENCLAVE_URL_MAP, DYNAMIC_FORWARD_MPC_PREPROD_ENCLAVE_URL, DYNAMIC_FORWARD_MPC_PROD_ENCLAVE_URL, DYNAMIC_KEYSHARES_RELAY_MAP, DYNAMIC_KEYSHARES_RELAY_PREPROD_BASE_API_URL, DYNAMIC_KEYSHARES_RELAY_PROD_BASE_API_URL, DynamicApiClient, DynamicClientSessionSignature, DynamicElevatedAccessTokenHeader, DynamicForwardMPCHeader, DynamicMfaTokenHeader, DynamicRequestIdHeader, DynamicSessionPublicKeyHeader, DynamicTraceElapsedTimeHeader, DynamicTraceIdHeader, ENCRYPTED_SHARES_STORAGE_SUFFIX, ENVIRONMENT_ENUM, EVM_COMPATIBLE_CHAINS, FEATURE_FLAGS, IFRAME_DOMAIN_MAP, Logger, MIDNIGHT_DERIVATION_PATHS, MPC_CHAIN_CONFIG, MPC_CONFIG, MPC_RELAY_DEV_API_URL, MPC_RELAY_PREPROD_API_URL, MPC_RELAY_PROD_API_URL, MPC_RELAY_URL_MAP, NETWORK_ERROR_CODE, NETWORK_ERROR_STATUS, NoopLogger, PREPROD_RELAY_API_KEY, PREPROD_RELAY_APP_ID, PROD_RELAY_API_KEY, PROD_RELAY_APP_ID, RELAY_API_KEY_HEADER, RELAY_APP_ID_HEADER, SDK_NAMESPACE, SERVER_SDK_ROUTE_PREFIX, SOLANA_RPC_URL, SigningConsentRequiredError, SuccessEventType, ThresholdSignatureScheme, URL_PATTERNS, WalletApiError, WalletOperation, WalletReadyState, assertDynamicLocationsHaveExternalKeyShareId, buildForwardMpcEnclaveUrl, chain, chainEnumToVerifiedCredentialName, createRejectablePromise, createSigningIntent, extractServerErrorCode, formatNamespacedVersion, formatRawMessageForSigning, getBitcoinChainConfig, getClientThreshold, getDynamicServerThreshold, getEnvironmentFromUrl, getMPCChainConfig, getRequiredExternalKeyShareId, getReshareConfig, getServerWalletReshareConfig, getTSSConfig, getVersionNamespace, getVersionWithoutNamespace, handleAxiosError, invokeCeremonyComplete, isBusinessAccountActionRequired, isEvmCompatibleChain, isRecoveredForwardMpcConnectionChurn, parseNamespacedVersion, prepareRawMessageSigningPayload, sanitizeBusinessAccountSignedIntent, serializeError, serializeMessageForForwardMPC, verifiedCredentialNameToChainEnum };
2933
+ export { AuthMode, BITCOIN_ADDRESS_TYPE_CONFIG, BITCOIN_DERIVATION_PATHS, BROWSER_SDK_ROUTE_PREFIX, BackupLocation, BitcoinAddressType, BitcoinNetwork, BusinessAccountClient, BusinessAccountMemberRole, BusinessAccountSignerType, CreateRoomPartiesOptions, DEFAULT_ED25519_VARIANT, DELEGATED_SHARE_COUNT, DYNAMIC_AUTH_BASE_API_URL_MAP, DYNAMIC_AUTH_DEV_BASE_API_URL, DYNAMIC_AUTH_PREPROD_BASE_API_URL, DYNAMIC_AUTH_PROD_BASE_API_URL, DYNAMIC_CLIENT_RELAY_REDCOAST_API_KEY_MAP, DYNAMIC_CLIENT_RELAY_REDCOAST_APP_ID_MAP, DYNAMIC_FORWARD_MPC_DEV_ENCLAVE_URL, DYNAMIC_FORWARD_MPC_ENCLAVE_ATTESTATION_CONFIG_MAP, DYNAMIC_FORWARD_MPC_ENCLAVE_URL_MAP, DYNAMIC_FORWARD_MPC_PREPROD_ENCLAVE_URL, DYNAMIC_FORWARD_MPC_PROD_ENCLAVE_URL, DYNAMIC_KEYSHARES_RELAY_MAP, DYNAMIC_KEYSHARES_RELAY_PREPROD_BASE_API_URL, DYNAMIC_KEYSHARES_RELAY_PROD_BASE_API_URL, DynamicApiClient, DynamicClientSessionSignature, DynamicElevatedAccessTokenHeader, DynamicForwardMPCHeader, DynamicMfaTokenHeader, DynamicRequestIdHeader, DynamicSessionPublicKeyHeader, DynamicTraceElapsedTimeHeader, DynamicTraceIdHeader, ENCRYPTED_SHARES_STORAGE_SUFFIX, ENVIRONMENT_ENUM, EVM_COMPATIBLE_CHAINS, FEATURE_FLAGS, IFRAME_DOMAIN_MAP, Logger, MIDNIGHT_DERIVATION_PATHS, MPC_CHAIN_CONFIG, MPC_CONFIG, MPC_RELAY_DEV_API_URL, MPC_RELAY_PREPROD_API_URL, MPC_RELAY_PROD_API_URL, MPC_RELAY_URL_MAP, NETWORK_ERROR_CODE, NETWORK_ERROR_STATUS, NoopLogger, PREPROD_RELAY_API_KEY, PREPROD_RELAY_APP_ID, PROD_RELAY_API_KEY, PROD_RELAY_APP_ID, RELAY_API_KEY_HEADER, RELAY_APP_ID_HEADER, SDK_NAMESPACE, SERVER_SDK_ROUTE_PREFIX, SOLANA_RPC_URL, SigningConsentRequiredError, SuccessEventType, ThresholdSignatureScheme, URL_PATTERNS, WalletApiError, WalletOperation, WalletReadyState, assertDynamicLocationsHaveExternalKeyShareId, buildForwardMpcEnclaveUrl, chain, chainEnumToVerifiedCredentialName, createRejectablePromise, createSigningIntent, extractServerErrorCode, formatNamespacedVersion, formatRawMessageForSigning, getBitcoinChainConfig, getClientThreshold, getDynamicServerThreshold, getEnvironmentFromUrl, getMPCChainConfig, getRequiredExternalKeyShareId, getReshareConfig, getServerWalletReshareConfig, getTSSConfig, getVersionNamespace, getVersionWithoutNamespace, handleAxiosError, invokeCeremonyComplete, isBusinessAccountActionRequired, isEvmCompatibleChain, isRecoveredForwardMpcConnectionChurn, normalizeAndValidatePrivateKey, parseNamespacedVersion, prepareRawMessageSigningPayload, sanitizeBusinessAccountSignedIntent, serializeError, serializeMessageForForwardMPC, verifiedCredentialNameToChainEnum };
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@dynamic-labs-wallet/core",
3
- "version": "1.1.26",
3
+ "version": "1.1.28",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "dependencies": {
7
7
  "@dynamic-labs/sdk-api-core": "0.50.0",
8
- "@dynamic-labs-wallet/primitives": "1.1.26",
8
+ "@dynamic-labs-wallet/primitives": "1.1.28",
9
9
  "axios": "1.20.0",
10
10
  "uuid": "11.1.0"
11
11
  },
@@ -1,3 +1,4 @@
1
1
  export * from './constants.js';
2
2
  export * from './utils.js';
3
+ export * from './privateKey.js';
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mpc/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mpc/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC"}
@@ -0,0 +1,20 @@
1
+ import type { BitcoinConfig } from '../types.js';
2
+ /**
3
+ * Validates a private key for `importPrivateKey` before any API call or MPC
4
+ * ceremony starts, and returns it normalized for the MPC importer (surrounding
5
+ * whitespace trimmed, optional `0x` prefix stripped).
6
+ *
7
+ * Every chain expects a 32-byte hex key at this layer — chain-specific input
8
+ * formats (WIF, base58, bech32, Stellar seed) are converted to hex by the chain
9
+ * clients beforehand. For secp256k1 chains (ECDSA, BIP340) the key is also
10
+ * range-checked against the curve order.
11
+ *
12
+ * Error messages report only the key's length and character class — never the
13
+ * key material itself.
14
+ */
15
+ export declare const normalizeAndValidatePrivateKey: ({ privateKey, chainName, bitcoinConfig, }: {
16
+ privateKey: string;
17
+ chainName: string;
18
+ bitcoinConfig?: BitcoinConfig;
19
+ }) => string;
20
+ //# sourceMappingURL=privateKey.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"privateKey.d.ts","sourceRoot":"","sources":["../../src/mpc/privateKey.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAgBjD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,8BAA8B,8CAIxC;IACD,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B,KAAG,MAwCH,CAAC"}