From db62f1d7a98d9d05086c54f44a37e45a0c270fdc Mon Sep 17 00:00:00 2001 From: Martin Minkov Date: Tue, 12 Mar 2024 09:48:16 -0700 Subject: [PATCH 1/4] feat(mina-signer): add derivePublicKeyUnsafe method Adds a `derivePublicKeyUnsafe` method which allows backwards compatability with the old client_sdk library, which allowed private keys to be out of the domain of the Pallas curve. We expose this function which takes the mod of the domain to ensure it's within the expected private key range. --- src/mina-signer/mina-signer.ts | 24 ++++++++++++++++++++++++ src/provable/curve-bigint.ts | 26 ++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/src/mina-signer/mina-signer.ts b/src/mina-signer/mina-signer.ts index c1356b52e0..fac90ba83d 100644 --- a/src/mina-signer/mina-signer.ts +++ b/src/mina-signer/mina-signer.ts @@ -99,6 +99,30 @@ class Client { return PublicKey.toBase58(publicKey); } + /** + * Derives the public key corresponding to a given private key, ensuring compatibility with keys from the older [client_sdk](https://www.npmjs.com/package/@o1labs/client-sdk) libraries by converting the private key into the domain of the Pallas curve if necessary. + * The function first converts the input private key (in Base58 format) to a format that is compatible with the domain of the Pallas curve by applying a modulus operation. This step ensures backward compatibility with older keys that may not directly fit the Pallas curve's domain. Once the private key is in the correct domain, it is used to derive the corresponding public key. + * @param privateKeyBase58 - The private key (in Base58 format) used to derive the corresponding public key. The key is expected to be out of the domain of the Pallas curve and will be converted to fit within the domain as part of this process. + * @returns {Json.PublicKey} The derived public key in Base58 format, corresponding to the input private key, now within the domain of the Pallas curve. + * @remarks + * This function is labeled as "unsafe" due to the modulus operation applied to ensure backward compatibility, which might not adhere to strict security protocols expected in [mina-signer](https://www.npmjs.com/package/mina-signer). It is primarily intended for use cases requiring interoperability with keys generated or managed by previous versions of the [client_sdk](https://www.npmjs.com/package/@o1labs/client-sdk) or other tools that may produce keys outside the Pallas curve's domain. + * It is an essential tool for migrating old keys for use with the current [mina-signer](https://www.npmjs.com/package/mina-signer) library, by allowing keys that would otherwise be rejected to be used effectively. + * + * @example + * ```ts + * // Assuming `oldPrivateKeyBase58` is a private key in Base58 format from an older client SDK + * const publicKeyBase58 = derivePublicKeyUnsafe(oldPrivateKeyBase58); + * console.log(publicKeyBase58); // Logs the derived public key in Base58 format + * ``` + */ + derivePublicKeyUnsafe(privateKeyBase58: Json.PrivateKey): Json.PublicKey { + let privateKey = PrivateKey.fromBase58( + PrivateKey.convertPrivateKeyToBase58WithMod(privateKeyBase58) + ); + let publicKey = PrivateKey.toPublicKey(privateKey); + return PublicKey.toBase58(publicKey); + } + /** * Signs an arbitrary list of field elements in a SNARK-compatible way. * The resulting signature can be verified in o1js as follows: diff --git a/src/provable/curve-bigint.ts b/src/provable/curve-bigint.ts index 5b1b0f6e36..cbade55f5d 100644 --- a/src/provable/curve-bigint.ts +++ b/src/provable/curve-bigint.ts @@ -143,4 +143,30 @@ const PrivateKey = { toPublicKey(key: PrivateKey) { return PublicKey.fromGroup(Group.scale(Group.generatorMina, key)); }, + convertPrivateKeyToBase58WithMod, }; + +const Bigint256 = BinableBigint(256, () => { + // no check supplied, allows any string of 256 bits +}); +const OutOfDomainKey = base58( + withVersionNumber(Bigint256, versionNumbers.scalar), + versionBytes.privateKey +); + +/** + * Converts a private key that is out of the domain of the Pallas curve to a private key that is in the domain by taking the modulus of the private key. + * This is done to keep backwards compatibility with the previous version of the [client_sdk](https://www.npmjs.com/package/@o1labs/client-sdk), which did the same thing when converting a private key to base58. + * @param keyBase58 - The private key that is out of the domain of the Pallas curve + * @returns The private key that is in the domain of the Pallas curve + * @remarks + * This function is particularly useful when migrating old keys to be used by the current [mina-signer](https://www.npmjs.com/package/mina-signer) library, + * which may reject keys that do not fit the domain of the Pallas curve. + * By performing a modulus operation on the key, it ensures that keys + * from the older client_sdk can be made compatible. + */ +function convertPrivateKeyToBase58WithMod(keyBase58: string): string { + let key = OutOfDomainKey.fromBase58(keyBase58); + key = mod(key, Fq.modulus); + return PrivateKey.toBase58(key); +} From c99342d0545444731be4970ee64d44b06178a264 Mon Sep 17 00:00:00 2001 From: Martin Minkov Date: Tue, 12 Mar 2024 09:50:24 -0700 Subject: [PATCH 2/4] chore(mina-signer/package.json): bump version from 3.0.4 to 3.0.5 for new release --- src/mina-signer/package-lock.json | 4 ++-- src/mina-signer/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mina-signer/package-lock.json b/src/mina-signer/package-lock.json index 4c7579b351..43dedd3ba2 100644 --- a/src/mina-signer/package-lock.json +++ b/src/mina-signer/package-lock.json @@ -1,12 +1,12 @@ { "name": "mina-signer", - "version": "3.0.4", + "version": "3.0.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "mina-signer", - "version": "3.0.4", + "version": "3.0.5", "license": "Apache-2.0", "dependencies": { "blakejs": "^1.2.1", diff --git a/src/mina-signer/package.json b/src/mina-signer/package.json index cd4e0aedb1..ac3f4c4b4a 100644 --- a/src/mina-signer/package.json +++ b/src/mina-signer/package.json @@ -1,7 +1,7 @@ { "name": "mina-signer", "description": "Node API for signing transactions on various networks for Mina Protocol", - "version": "3.0.4", + "version": "3.0.5", "type": "module", "scripts": { "build": "tsc -p ../../tsconfig.mina-signer.json", From 23bb3ae2c66ef937cf66cecb8476e13954523dad Mon Sep 17 00:00:00 2001 From: Martin Minkov Date: Tue, 12 Mar 2024 11:25:22 -0700 Subject: [PATCH 3/4] feat(mina-signer.ts): add convertPrivateKeyToBase58WithMod method for backwards compatibility with older keys This method allows older keys that do not fit the domain of the Pallas curve to be used by performing a modulus operation on the key. --- src/mina-signer/mina-signer.ts | 15 +++++++++++++++ src/provable/curve-bigint.ts | 11 ----------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/mina-signer/mina-signer.ts b/src/mina-signer/mina-signer.ts index fac90ba83d..9ec6c88cf4 100644 --- a/src/mina-signer/mina-signer.ts +++ b/src/mina-signer/mina-signer.ts @@ -123,6 +123,21 @@ class Client { return PublicKey.toBase58(publicKey); } + /** + * Converts a private key that is out of the domain of the Pallas curve to a private key in base58 format that is in the domain by taking the modulus of the private key. + * This is done to keep backwards compatibility with the previous version of the [client_sdk](https://www.npmjs.com/package/@o1labs/client-sdk), which did the same thing when converting a private key to base58. + * @param keyBase58 - The private key that is out of the domain of the Pallas curve + * @returns The private key that is in the domain of the Pallas curve + * @remarks + * This function is particularly useful when migrating old keys to be used by the current [mina-signer](https://www.npmjs.com/package/mina-signer) library, + * which may reject keys that do not fit the domain of the Pallas curve, + * by performing a modulus operation on the key, it ensures that keys + * from the older client_sdk can be made compatible. + */ + convertPrivateKeyToBase58WithMod(keyBase58: string): string { + return PrivateKey.convertPrivateKeyToBase58WithMod(keyBase58); + } + /** * Signs an arbitrary list of field elements in a SNARK-compatible way. * The resulting signature can be verified in o1js as follows: diff --git a/src/provable/curve-bigint.ts b/src/provable/curve-bigint.ts index cbade55f5d..a6a1b151bb 100644 --- a/src/provable/curve-bigint.ts +++ b/src/provable/curve-bigint.ts @@ -154,17 +154,6 @@ const OutOfDomainKey = base58( versionBytes.privateKey ); -/** - * Converts a private key that is out of the domain of the Pallas curve to a private key that is in the domain by taking the modulus of the private key. - * This is done to keep backwards compatibility with the previous version of the [client_sdk](https://www.npmjs.com/package/@o1labs/client-sdk), which did the same thing when converting a private key to base58. - * @param keyBase58 - The private key that is out of the domain of the Pallas curve - * @returns The private key that is in the domain of the Pallas curve - * @remarks - * This function is particularly useful when migrating old keys to be used by the current [mina-signer](https://www.npmjs.com/package/mina-signer) library, - * which may reject keys that do not fit the domain of the Pallas curve. - * By performing a modulus operation on the key, it ensures that keys - * from the older client_sdk can be made compatible. - */ function convertPrivateKeyToBase58WithMod(keyBase58: string): string { let key = OutOfDomainKey.fromBase58(keyBase58); key = mod(key, Fq.modulus); From 1247ad161e2194bc2a948992dcecb7b506c2f301 Mon Sep 17 00:00:00 2001 From: Martin Minkov Date: Tue, 12 Mar 2024 11:29:13 -0700 Subject: [PATCH 4/4] docs(mina-signer): adjust doc comments on deriving private keys from outside expected domain --- src/mina-signer/mina-signer.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/mina-signer/mina-signer.ts b/src/mina-signer/mina-signer.ts index 9ec6c88cf4..7b74bbccd9 100644 --- a/src/mina-signer/mina-signer.ts +++ b/src/mina-signer/mina-signer.ts @@ -100,12 +100,12 @@ class Client { } /** - * Derives the public key corresponding to a given private key, ensuring compatibility with keys from the older [client_sdk](https://www.npmjs.com/package/@o1labs/client-sdk) libraries by converting the private key into the domain of the Pallas curve if necessary. + * Derives the public key corresponding to a given private key. This function addresses compatibility with private keys generated by external tools that may produce keys outside the domain of the Pallas curve, that was previously accepted by the older [client_sdk](https://www.npmjs.com/package/@o1labs/client-sdk). * The function first converts the input private key (in Base58 format) to a format that is compatible with the domain of the Pallas curve by applying a modulus operation. This step ensures backward compatibility with older keys that may not directly fit the Pallas curve's domain. Once the private key is in the correct domain, it is used to derive the corresponding public key. * @param privateKeyBase58 - The private key (in Base58 format) used to derive the corresponding public key. The key is expected to be out of the domain of the Pallas curve and will be converted to fit within the domain as part of this process. * @returns {Json.PublicKey} The derived public key in Base58 format, corresponding to the input private key, now within the domain of the Pallas curve. * @remarks - * This function is labeled as "unsafe" due to the modulus operation applied to ensure backward compatibility, which might not adhere to strict security protocols expected in [mina-signer](https://www.npmjs.com/package/mina-signer). It is primarily intended for use cases requiring interoperability with keys generated or managed by previous versions of the [client_sdk](https://www.npmjs.com/package/@o1labs/client-sdk) or other tools that may produce keys outside the Pallas curve's domain. + * This function is labeled as "unsafe" due to the modulus operation applied to ensure backward compatibility, which might not adhere to strict security protocols expected in [mina-signer](https://www.npmjs.com/package/mina-signer). It is primarily intended for use cases requiring interoperability with keys managed by previous versions of the [client_sdk](https://www.npmjs.com/package/@o1labs/client-sdk) or other tools that may produce keys outside the Pallas curve's domain. * It is an essential tool for migrating old keys for use with the current [mina-signer](https://www.npmjs.com/package/mina-signer) library, by allowing keys that would otherwise be rejected to be used effectively. * * @example @@ -130,8 +130,7 @@ class Client { * @returns The private key that is in the domain of the Pallas curve * @remarks * This function is particularly useful when migrating old keys to be used by the current [mina-signer](https://www.npmjs.com/package/mina-signer) library, - * which may reject keys that do not fit the domain of the Pallas curve, - * by performing a modulus operation on the key, it ensures that keys + * which may reject keys that do not fit the domain of the Pallas curve, by performing a modulus operation on the key, it ensures that keys * from the older client_sdk can be made compatible. */ convertPrivateKeyToBase58WithMod(keyBase58: string): string {