From 636a7dfd5b9402efabf447f7cdaef985f5adb616 Mon Sep 17 00:00:00 2001 From: Dmytro Vynnyk Date: Mon, 23 Dec 2024 12:58:32 +0100 Subject: [PATCH] Make PrivateKey and PublicKye methods sync --- README.md | 12 ++++---- migration-guide-v2-v5.md | 4 +-- src/types/Deploy.test.ts | 4 +-- src/types/Deploy.ts | 4 +-- src/types/Transaction.test.ts | 4 +-- src/types/Transaction.ts | 8 +++--- src/types/TransactionBuilder.md | 4 +-- src/types/keypair/PrivateKey.ts | 34 +++++++++++------------ src/types/keypair/PublicKey.ts | 8 +++--- src/types/keypair/ed25519/PrivateKey.ts | 13 +++++---- src/types/keypair/ed25519/PublicKey.ts | 4 +-- src/types/keypair/secp256k1/PrivateKey.ts | 12 +++++--- src/types/keypair/secp256k1/PublicKey.ts | 4 +-- 13 files changed, 61 insertions(+), 54 deletions(-) diff --git a/README.md b/README.md index 36061cc67..ebe641399 100644 --- a/README.md +++ b/README.md @@ -140,7 +140,7 @@ const transaction = new NativeTransferBuilder() .payment(100_000_000) .build(); -await transaction.sign(privateKey); +transaction.sign(privateKey); try { const result = await rpcClient.putTransaction(transaction); @@ -194,7 +194,7 @@ deployHeader.account = senderKey.publicKey; deployHeader.chainName = 'casper-test'; const deploy = Deploy.makeDeploy(deployHeader, payment, session); -await deploy.sign(senderKey); +deploy.sign(senderKey); const result = await rpcClient.putDeploy(deploy); @@ -226,7 +226,7 @@ const deploy = makeCsprTransferDeploy({ transferAmount: '2500000000' // 2.5 CSPR }); -await deploy.sign(privateKey); +deploy.sign(privateKey); const rpcHandler = new HttpHandler('http://:7777/rpc'); const rpcClient = new RpcClient(rpcHandler); @@ -263,7 +263,7 @@ const deploy = makeAuctionManagerDeploy({ amount: '500000000000' // 500 CSPR }); -await deploy.sign(privateKey); +deploy.sign(privateKey); const rpcHandler = new HttpHandler('http://:7777/rpc'); const rpcClient = new RpcClient(rpcHandler); @@ -300,7 +300,7 @@ const deploy = await makeCep18TransferDeploy({ paymentAmount: '3000000000' // 3 CSPR }); -await deploy.sign(privateKey); +deploy.sign(privateKey); const rpcHandler = new HttpHandler('http://:7777/rpc'); const rpcClient = new RpcClient(rpcHandler); @@ -339,7 +339,7 @@ const deploy = await makeNftTransferDeploy({ tokenId: 234 }); -await deploy.sign(privateKey); +deploy.sign(privateKey); const rpcHandler = new HttpHandler('http://:7777/rpc'); const rpcClient = new RpcClient(rpcHandler); diff --git a/migration-guide-v2-v5.md b/migration-guide-v2-v5.md index 956ff2eda..22ce3f347 100644 --- a/migration-guide-v2-v5.md +++ b/migration-guide-v2-v5.md @@ -257,7 +257,7 @@ const transactionPayload = TransactionV1Payload.build({ const transaction = TransactionV1.makeTransactionV1( transactionPayload ); -await transaction.sign(privateKey); +transaction.sign(privateKey); ``` 6. **Submit Transaction**: @@ -301,7 +301,7 @@ const transaction = new NativeTransferBuilder() .payment(100_000_000) .build(); -await transaction.sign(privateKey); +transaction.sign(privateKey); try { const result = await rpcClient.putTransaction(transaction); diff --git a/src/types/Deploy.test.ts b/src/types/Deploy.test.ts index 20f347689..f6ceee2d4 100644 --- a/src/types/Deploy.test.ts +++ b/src/types/Deploy.test.ts @@ -60,8 +60,8 @@ describe('Deploy', () => { const payment = ExecutableDeployItem.standardPayment(paymentAmount); let deploy = Deploy.makeDeploy(deployHeader, payment, executableDeployItem); - await deploy.sign(senderKey); - await deploy.sign(recipientKey); + deploy.sign(senderKey); + deploy.sign(recipientKey); const json = Deploy.toJson(deploy); diff --git a/src/types/Deploy.ts b/src/types/Deploy.ts index 50bb6b47c..59dfc46b9 100644 --- a/src/types/Deploy.ts +++ b/src/types/Deploy.ts @@ -268,8 +268,8 @@ export class Deploy { * * @param keys The private key used to sign the deploy. */ - public async sign(keys: PrivateKey): Promise { - const signatureBytes = await keys.signAndAddAlgorithmBytes( + public sign(keys: PrivateKey): void { + const signatureBytes = keys.signAndAddAlgorithmBytes( this.hash.toBytes() ); const signature = new HexBytes(signatureBytes); diff --git a/src/types/Transaction.test.ts b/src/types/Transaction.test.ts index 222888715..00a8d93b7 100644 --- a/src/types/Transaction.test.ts +++ b/src/types/Transaction.test.ts @@ -76,7 +76,7 @@ describe('Test Transaction', () => { }); const transaction = TransactionV1.makeTransactionV1(transactionPayload); - await transaction.sign(keys); + transaction.sign(keys); const transactionPaymentAmount = transaction.payload.fields.args.args .get('amount')! @@ -108,7 +108,7 @@ describe('Test Transaction', () => { .payment(100_000_000) .build(); - await transaction.sign(sender); + transaction.sign(sender); const transactionV1 = transaction.getTransactionV1()!; const transactionPaymentAmount = transactionV1.payload.fields.args.args diff --git a/src/types/Transaction.ts b/src/types/Transaction.ts index 62df32486..ddd4d0203 100644 --- a/src/types/Transaction.ts +++ b/src/types/Transaction.ts @@ -169,8 +169,8 @@ export class TransactionV1 { * Signs the transaction using the provided private key. * @param keys The private key to sign the transaction. */ - async sign(keys: PrivateKey): Promise { - const signatureBytes = await keys.signAndAddAlgorithmBytes( + sign(keys: PrivateKey): void { + const signatureBytes = keys.signAndAddAlgorithmBytes( this.hash.toBytes() ); const signature = new HexBytes(signatureBytes); @@ -493,8 +493,8 @@ export class Transaction { * Signs the transaction using the provided private key. * @param key The private key to sign the transaction. */ - async sign(key: PrivateKey): Promise { - const signatureBytes = await key.signAndAddAlgorithmBytes( + sign(key: PrivateKey): void { + const signatureBytes = key.signAndAddAlgorithmBytes( this.hash.toBytes() ); this.setSignature(signatureBytes, key.publicKey); diff --git a/src/types/TransactionBuilder.md b/src/types/TransactionBuilder.md index d98e3de61..df699f81c 100644 --- a/src/types/TransactionBuilder.md +++ b/src/types/TransactionBuilder.md @@ -157,7 +157,7 @@ const transaction = new NativeTransferBuilder() .payment(100_000_000) .build(); -await transaction.sign(sender); +transaction.sign(sender); // Create a contract call const contractCallTransaction = new ContractCallBuilder() @@ -169,5 +169,5 @@ const contractCallTransaction = new ContractCallBuilder() .chainName('casper-net-1') .build(); -await contractCallTransaction.sign(sender); +contractCallTransaction.sign(sender); ``` diff --git a/src/types/keypair/PrivateKey.ts b/src/types/keypair/PrivateKey.ts index d181108f9..55b81ef59 100644 --- a/src/types/keypair/PrivateKey.ts +++ b/src/types/keypair/PrivateKey.ts @@ -11,7 +11,7 @@ import { KeyAlgorithm } from './Algorithm'; */ export interface PrivateKeyInternal { /** Retrieves the public key bytes. */ - publicKeyBytes(): Promise; + publicKeyBytes(): Uint8Array; toBytes(): Uint8Array; /** @@ -19,7 +19,7 @@ export interface PrivateKeyInternal { * @param message - The message to sign. * @returns A promise resolving to the signature bytes. */ - sign(message: Uint8Array): Promise; + sign(message: Uint8Array): Uint8Array; /** Converts the private key to PEM format. */ toPem(): string; @@ -76,8 +76,8 @@ export class PrivateKey { * @param msg - The message to sign. * @returns A promise resolving to the signature bytes. */ - public async sign(msg: Uint8Array): Promise { - return await this.priv.sign(msg); + public sign(msg: Uint8Array): Uint8Array { + return this.priv.sign(msg); } /** @@ -85,8 +85,8 @@ export class PrivateKey { * @param msg - The message to sign. * @returns A promise resolving to the signature bytes with the algorithm byte. */ - public async signAndAddAlgorithmBytes(msg: Uint8Array): Promise { - const signature = await this.priv.sign(msg); + public signAndAddAlgorithmBytes(msg: Uint8Array): Uint8Array { + const signature = this.priv.sign(msg); const algBytes = Uint8Array.of(this.alg); return concat([algBytes, signature]); } @@ -105,9 +105,9 @@ export class PrivateKey { * @param algorithm - The cryptographic algorithm to use. * @returns A promise resolving to a new PrivateKey instance. */ - public static async generate(algorithm: KeyAlgorithm): Promise { - const priv = await PrivateKeyFactory.createPrivateKey(algorithm); - const pubBytes = await priv.publicKeyBytes(); + public static generate(algorithm: KeyAlgorithm): PrivateKey { + const priv = PrivateKeyFactory.createPrivateKey(algorithm); + const pubBytes = priv.publicKeyBytes(); const algBytes = Uint8Array.of(algorithm); const pub = PublicKey.fromBuffer(concat([algBytes, pubBytes])); return new PrivateKey(algorithm, pub, priv); @@ -139,15 +139,15 @@ export class PrivateKey { * @param algorithm - The cryptographic algorithm to use. * @returns A promise resolving to a PrivateKey instance. */ - public static async fromHex( + public static fromHex( key: string, algorithm: KeyAlgorithm - ): Promise { - const priv = await PrivateKeyFactory.createPrivateKeyFromHex( + ): PrivateKey { + const priv = PrivateKeyFactory.createPrivateKeyFromHex( key, algorithm ); - const pubBytes = await priv.publicKeyBytes(); + const pubBytes = priv.publicKeyBytes(); const algBytes = Uint8Array.of(algorithm); const pub = PublicKey.fromBuffer(concat([algBytes, pubBytes])); return new PrivateKey(algorithm, pub, priv); @@ -165,9 +165,9 @@ class PrivateKeyFactory { * @returns A promise resolving to a PrivateKeyInternal instance. * @throws Error if the algorithm is unsupported. */ - public static async createPrivateKey( + public static createPrivateKey( algorithm: KeyAlgorithm - ): Promise { + ): PrivateKeyInternal { switch (algorithm) { case KeyAlgorithm.ED25519: return Ed25519PrivateKey.generate(); @@ -206,10 +206,10 @@ class PrivateKeyFactory { * @returns A promise resolving to a PrivateKeyInternal instance. * @throws Error if the algorithm is unsupported. */ - public static async createPrivateKeyFromHex( + public static createPrivateKeyFromHex( key: string, algorithm: KeyAlgorithm - ): Promise { + ): PrivateKeyInternal { switch (algorithm) { case KeyAlgorithm.ED25519: return Ed25519PrivateKey.fromHex(key); diff --git a/src/types/keypair/PublicKey.ts b/src/types/keypair/PublicKey.ts index d385c0f21..208d9e806 100644 --- a/src/types/keypair/PublicKey.ts +++ b/src/types/keypair/PublicKey.ts @@ -50,7 +50,7 @@ interface PublicKeyInternal { * @param sig - The signature to verify. * @returns A promise that resolves to a boolean indicating the validity of the signature. */ - verifySignature(message: Uint8Array, sig: Uint8Array): Promise; + verifySignature(message: Uint8Array, sig: Uint8Array): boolean; } /** @@ -233,15 +233,15 @@ export class PublicKey { * @returns A promise that resolves to a boolean indicating the validity of the signature. * @throws Error if the signature or public key is empty, or if the signature is invalid. */ - async verifySignature( + verifySignature( message: Uint8Array, sig: Uint8Array - ): Promise { + ): boolean { if (sig.length <= 1) throw ErrEmptySignature; if (!this.key) throw ErrEmptyPublicKey; const sigWithoutAlgByte = sig.slice(1); - const signature = await this.key.verifySignature( + const signature = this.key.verifySignature( message, sigWithoutAlgByte ); diff --git a/src/types/keypair/ed25519/PrivateKey.ts b/src/types/keypair/ed25519/PrivateKey.ts index b3d74e489..81ef8fdd9 100644 --- a/src/types/keypair/ed25519/PrivateKey.ts +++ b/src/types/keypair/ed25519/PrivateKey.ts @@ -1,5 +1,8 @@ import * as ed25519 from '@noble/ed25519'; import { PrivateKeyInternal } from "../PrivateKey"; +import { sha512 } from '@noble/hashes/sha512'; + +ed25519.utils.sha512Sync = (...m) => sha512(ed25519.utils.concatBytes(...m)); /** * Represents an Ed25519 private key, supporting key generation, signing, and PEM encoding. @@ -24,7 +27,7 @@ export class PrivateKey implements PrivateKeyInternal { * Generates a new random Ed25519 private key. * @returns A promise that resolves to a new PrivateKey instance. */ - static async generate(): Promise { + static generate(): PrivateKey { const keyPair = ed25519.utils.randomPrivateKey(); return new PrivateKey(keyPair); } @@ -33,8 +36,8 @@ export class PrivateKey implements PrivateKeyInternal { * Retrieves the byte array of the associated public key. * @returns A promise that resolves to the public key bytes. */ - async publicKeyBytes(): Promise { - return ed25519.getPublicKey(this.key); + publicKeyBytes(): Uint8Array { + return ed25519.sync.getPublicKey(this.key); } toBytes(): Uint8Array { @@ -46,8 +49,8 @@ export class PrivateKey implements PrivateKeyInternal { * @param message - The message to sign. * @returns A promise that resolves to the signature bytes. */ - async sign(message: Uint8Array): Promise { - return ed25519.sign(message, this.key); + sign(message: Uint8Array): Uint8Array { + return ed25519.sync.sign(message, this.key); } /** diff --git a/src/types/keypair/ed25519/PublicKey.ts b/src/types/keypair/ed25519/PublicKey.ts index 217416ad3..823c44ef9 100644 --- a/src/types/keypair/ed25519/PublicKey.ts +++ b/src/types/keypair/ed25519/PublicKey.ts @@ -38,8 +38,8 @@ export class PublicKey { verifySignature( message: Uint8Array, signature: Uint8Array - ): Promise { - return ed25519.verify(signature, message, this.key); + ): boolean { + return ed25519.sync.verify(signature, message, this.key); } /** diff --git a/src/types/keypair/secp256k1/PrivateKey.ts b/src/types/keypair/secp256k1/PrivateKey.ts index 7c5a15aee..277e18dc1 100644 --- a/src/types/keypair/secp256k1/PrivateKey.ts +++ b/src/types/keypair/secp256k1/PrivateKey.ts @@ -1,7 +1,11 @@ import * as secp256k1 from '@noble/secp256k1'; import { sha256 } from '@noble/hashes/sha256'; +import { hmac } from '@noble/hashes/hmac'; import { PrivateKeyInternal } from "../PrivateKey"; +secp256k1.utils.hmacSha256Sync = (k, ...m) => + hmac(sha256, k, secp256k1.utils.concatBytes(...m)); + /** PEM prefix for a private key. */ const PemPrivateKeyPrefix = '-----BEGIN PRIVATE KEY-----'; @@ -28,7 +32,7 @@ export class PrivateKey implements PrivateKeyInternal { * Generates a new random secp256k1 private key. * @returns A promise that resolves to a new PrivateKey instance. */ - static async generate(): Promise { + static generate(): PrivateKey { const privateKey = secp256k1.utils.randomPrivateKey(); return new PrivateKey(privateKey); } @@ -37,7 +41,7 @@ export class PrivateKey implements PrivateKeyInternal { * Retrieves the byte array of the public key in compressed format. * @returns A promise that resolves to the compressed public key bytes. */ - async publicKeyBytes(): Promise { + publicKeyBytes(): Uint8Array { return secp256k1.getPublicKey(this.key, true); } @@ -59,9 +63,9 @@ export class PrivateKey implements PrivateKeyInternal { * @param message - The message to sign. * @returns A promise that resolves to the signature bytes in compact format. */ - async sign(message: Uint8Array): Promise { + sign(message: Uint8Array): Uint8Array { const hash = sha256(message); - return await secp256k1.sign(hash, this.key, { der: false }); + return secp256k1.signSync(hash, this.key, { der: false }); } /** diff --git a/src/types/keypair/secp256k1/PublicKey.ts b/src/types/keypair/secp256k1/PublicKey.ts index b0832da8a..9f402bec2 100644 --- a/src/types/keypair/secp256k1/PublicKey.ts +++ b/src/types/keypair/secp256k1/PublicKey.ts @@ -36,10 +36,10 @@ export class PublicKey { * @param signature - The signature to verify. Supports both raw (64-byte R || S) and DER formats. * @returns A promise that resolves to `true` if the signature is valid, or `false` otherwise. */ - async verifySignature( + verifySignature( message: Uint8Array, signature: Uint8Array - ): Promise { + ): boolean { let compactSignature: Uint8Array; if (signature.length === 64) {