Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add method to derive private keys outside the expected domain range #1499

Merged
merged 4 commits into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions src/mina-signer/mina-signer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,44 @@ class Client {
return PublicKey.toBase58(publicKey);
}

/**
* 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 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);
}

/**
* 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:
Expand Down
4 changes: 2 additions & 2 deletions src/mina-signer/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/mina-signer/package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
15 changes: 15 additions & 0 deletions src/provable/curve-bigint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,4 +143,19 @@ 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
);

function convertPrivateKeyToBase58WithMod(keyBase58: string): string {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should also expose this function on Client, because people need to use it when creating signatures with their out of domain private keys

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds good, done!

let key = OutOfDomainKey.fromBase58(keyBase58);
key = mod(key, Fq.modulus);
return PrivateKey.toBase58(key);
}
Loading