Skip to content

Commit

Permalink
feat!: remove wrapped private key type
Browse files Browse the repository at this point in the history
BREAKING CHANGE:
Remove wrapped `StacksPrivateKey` type in favor of simple type alias for string/Uint8Array.
  • Loading branch information
janniks committed Nov 27, 2023
1 parent a342cc7 commit 41e90f0
Show file tree
Hide file tree
Showing 17 changed files with 248 additions and 281 deletions.
2 changes: 2 additions & 0 deletions packages/common/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ export type StacksNetworkName = (typeof StacksNetworks)[number];

// todo: do we want mocknet as well?

// todo: deduplicate magic variables

/** @ignore internal */
export const PRIVATE_KEY_COMPRESSED_LENGTH = 33;

Expand Down
11 changes: 6 additions & 5 deletions packages/encryption/src/keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
import base58 from 'bs58';
import { hashRipemd160 } from './hashRipemd160';
import { hashSha256Sync } from './sha2Hash';
import { PrivateKey } from '../../transactions/src';

const BITCOIN_PUBKEYHASH = 0x00;

Expand Down Expand Up @@ -96,7 +97,7 @@ export function publicKeyToBtcAddress(
* @ignore
* @returns a compressed public key
*/
export function getPublicKeyFromPrivate(privateKey: string | Uint8Array): string {
export function getPublicKeyFromPrivate(privateKey: PrivateKey): string {
const privateKeyBytes = privateKeyToBytes(privateKey);
// for backwards compatibility we always return a compressed public key, regardless of private key mode
return bytesToHex(nobleGetPublicKey(privateKeyBytes.slice(0, 32), true));
Expand All @@ -105,23 +106,23 @@ export function getPublicKeyFromPrivate(privateKey: string | Uint8Array): string
/**
* @ignore
*/
export function ecSign(messageHash: Uint8Array, hexPrivateKey: string | Uint8Array) {
return signSync(messageHash, privateKeyToBytes(hexPrivateKey).slice(0, 32), {
export function ecSign(messageHash: Uint8Array, privateKey: PrivateKey) {
return signSync(messageHash, privateKeyToBytes(privateKey).slice(0, 32), {
der: false,
});
}

/**
* @ignore
*/
export function isValidPrivateKey(privateKey: string | Uint8Array): boolean {
export function isValidPrivateKey(privateKey: PrivateKey): boolean {
return utils.isValidPrivateKey(privateKeyToBytes(privateKey));
}

/**
* @ignore
*/
export function compressPrivateKey(privateKey: string | Uint8Array): Uint8Array {
export function compressPrivateKey(privateKey: PrivateKey): Uint8Array {
const privateKeyBytes = privateKeyToBytes(privateKey);

return privateKeyBytes.length == PRIVATE_KEY_COMPRESSED_LENGTH
Expand Down
44 changes: 21 additions & 23 deletions packages/transactions/src/authorization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,22 @@ import {
StacksMessageType,
} from './constants';

import { cloneDeep, leftPadHex, txidFromData } from './utils';
import { BytesReader } from './bytesReader';
import { MessageSignature } from './common';
import { DeserializationError, SigningError, VerificationError } from './errors';
import {
createStacksPublicKey,
PrivateKey,
privateKeyToPublic,
publicKeyFromSignatureVrs,
publicKeyIsCompressed,
signWithKey,
StacksPublicKey,
} from './keys';
import {
TransactionAuthField,
serializeMessageSignature,
deserializeMessageSignature,
serializeMessageSignature,
TransactionAuthField,
} from './signature';
import {
addressFromPublicKeys,
Expand All @@ -30,20 +41,7 @@ import {
deserializeLPList,
serializeLPList,
} from './types';

import {
createStacksPublicKey,
getPublicKey,
isCompressed,
publicKeyFromSignatureVrs,
signWithKey,
StacksPrivateKey,
StacksPublicKey,
} from './keys';

import { MessageSignature } from './common';
import { DeserializationError, SigningError, VerificationError } from './errors';
import { BytesReader } from './bytesReader';
import { cloneDeep, leftPadHex, txidFromData } from './utils';

export function emptyMessageSignature(): MessageSignature {
return {
Expand Down Expand Up @@ -133,7 +131,7 @@ export function createSingleSigSpendingCondition(
1,
[createStacksPublicKey(pubKey)]
).hash160;
const keyEncoding = isCompressed(createStacksPublicKey(pubKey))
const keyEncoding = publicKeyIsCompressed(pubKey)
? PubKeyEncoding.Compressed
: PubKeyEncoding.Uncompressed;

Expand Down Expand Up @@ -276,7 +274,7 @@ export function deserializeMultiSigSpendingCondition(
for (const field of fields) {
switch (field.contents.type) {
case StacksMessageType.PublicKey:
if (!isCompressed(field.contents)) haveUncompressed = true;
if (!publicKeyIsCompressed(field.contents.data)) haveUncompressed = true;
break;
case StacksMessageType.MessageSignature:
if (field.pubKeyEncoding === PubKeyEncoding.Uncompressed) haveUncompressed = true;
Expand Down Expand Up @@ -363,7 +361,7 @@ function makeSigHashPostSign(
// * the signature
const hashLength = 32 + 1 + RECOVERABLE_ECDSA_SIG_LENGTH_BYTES;

const pubKeyEncoding = isCompressed(pubKey)
const pubKeyEncoding = publicKeyIsCompressed(pubKey.data)
? PubKeyEncoding.Compressed
: PubKeyEncoding.Uncompressed;

Expand All @@ -382,15 +380,15 @@ export function nextSignature(
authType: AuthType,
fee: IntegerType,
nonce: IntegerType,
privateKey: StacksPrivateKey
privateKey: PrivateKey
): {
nextSig: MessageSignature;
nextSigHash: string;
} {
const sigHashPreSign = makeSigHashPreSign(curSigHash, authType, fee, nonce);

const signature = signWithKey(privateKey, sigHashPreSign);
const publicKey = getPublicKey(privateKey);
const publicKey = createStacksPublicKey(privateKeyToPublic(privateKey));
const nextSigHash = makeSigHashPostSign(sigHashPreSign, publicKey, signature);

return {
Expand Down Expand Up @@ -491,7 +489,7 @@ function verifyMultiSig(

switch (field.contents.type) {
case StacksMessageType.PublicKey:
if (!isCompressed(field.contents)) haveUncompressed = true;
if (!publicKeyIsCompressed(field.contents.data)) haveUncompressed = true;
foundPubKey = field.contents;
break;
case StacksMessageType.MessageSignature:
Expand Down
55 changes: 24 additions & 31 deletions packages/transactions/src/builders.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import {
bytesToHex,
ClarityAbi,
hexToBytes,
IntegerType,
networkFrom,
STACKS_MAINNET,
Expand Down Expand Up @@ -37,14 +35,8 @@ import {
} from './constants';
import { validateContractCall } from './contract-abi';
import { estimateFee, getAbi, getNonce } from './fetch';
import {
createStacksPrivateKey,
getPublicKey,
pubKeyfromPrivKey,
publicKeyFromBytes,
publicKeyToAddress,
publicKeyToString,
} from './keys';

import { createStacksPublicKey, privateKeyToPublic, publicKeyToAddress } from './keys';
import {
createContractCallPayload,
createSmartContractPayload,
Expand Down Expand Up @@ -194,11 +186,11 @@ export async function makeSTXTokenTransfer(
): Promise<StacksTransaction> {
if ('senderKey' in txOptions) {
// txOptions is SignedTokenTransferOptions
const publicKey = publicKeyToString(getPublicKey(createStacksPrivateKey(txOptions.senderKey)));
const publicKey = privateKeyToPublic(txOptions.senderKey);
const options = omit(txOptions, 'senderKey');
const transaction = await makeUnsignedSTXTokenTransfer({ publicKey, ...options });

const privKey = createStacksPrivateKey(txOptions.senderKey);
const privKey = txOptions.senderKey;
const signer = new TransactionSigner(transaction);
signer.signOrigin(privKey);

Expand All @@ -211,13 +203,13 @@ export async function makeSTXTokenTransfer(
const signer = new TransactionSigner(transaction);
let pubKeys = txOptions.publicKeys;
for (const key of txOptions.signerKeys) {
const pubKey = pubKeyfromPrivKey(key);
pubKeys = pubKeys.filter(pk => pk !== bytesToHex(pubKey.data));
signer.signOrigin(createStacksPrivateKey(key));
const pubKey = privateKeyToPublic(key);
pubKeys = pubKeys.filter(pk => pk !== pubKey);
signer.signOrigin(key);
}

for (const key of pubKeys) {
signer.appendOrigin(publicKeyFromBytes(hexToBytes(key)));
signer.appendOrigin(createStacksPublicKey(key));
}

return transaction;
Expand Down Expand Up @@ -289,11 +281,12 @@ export async function makeContractDeploy(
): Promise<StacksTransaction> {
if ('senderKey' in txOptions) {
// txOptions is SignedContractDeployOptions
const publicKey = publicKeyToString(getPublicKey(createStacksPrivateKey(txOptions.senderKey)));

const publicKey = privateKeyToPublic(txOptions.senderKey);
const options = omit(txOptions, 'senderKey');
const transaction = await makeUnsignedContractDeploy({ publicKey, ...options });

const privKey = createStacksPrivateKey(txOptions.senderKey);
const privKey = txOptions.senderKey;
const signer = new TransactionSigner(transaction);
signer.signOrigin(privKey);

Expand All @@ -306,13 +299,13 @@ export async function makeContractDeploy(
const signer = new TransactionSigner(transaction);
let pubKeys = txOptions.publicKeys;
for (const key of txOptions.signerKeys) {
const pubKey = pubKeyfromPrivKey(key);
pubKeys = pubKeys.filter(pk => pk !== bytesToHex(pubKey.data));
signer.signOrigin(createStacksPrivateKey(key));
const pubKey = privateKeyToPublic(key);
pubKeys = pubKeys.filter(pk => pk !== pubKey);
signer.signOrigin(key);
}

for (const key of pubKeys) {
signer.appendOrigin(publicKeyFromBytes(hexToBytes(key)));
signer.appendOrigin(createStacksPublicKey(key));
}

return transaction;
Expand Down Expand Up @@ -531,11 +524,11 @@ export async function makeContractCall(
txOptions: SignedContractCallOptions | SignedMultiSigContractCallOptions
): Promise<StacksTransaction> {
if ('senderKey' in txOptions) {
const publicKey = publicKeyToString(getPublicKey(createStacksPrivateKey(txOptions.senderKey)));
const publicKey = privateKeyToPublic(txOptions.senderKey);
const options = omit(txOptions, 'senderKey');
const transaction = await makeUnsignedContractCall({ publicKey, ...options });

const privKey = createStacksPrivateKey(txOptions.senderKey);
const privKey = txOptions.senderKey;
const signer = new TransactionSigner(transaction);
signer.signOrigin(privKey);

Expand All @@ -547,13 +540,13 @@ export async function makeContractCall(
const signer = new TransactionSigner(transaction);
let pubKeys = txOptions.publicKeys;
for (const key of txOptions.signerKeys) {
const pubKey = pubKeyfromPrivKey(key);
pubKeys = pubKeys.filter(pk => pk !== bytesToHex(pubKey.data));
signer.signOrigin(createStacksPrivateKey(key));
const pubKey = privateKeyToPublic(key);
pubKeys = pubKeys.filter(pk => pk !== pubKey);
signer.signOrigin(key);
}

for (const key of pubKeys) {
signer.appendOrigin(publicKeyFromBytes(hexToBytes(key)));
signer.appendOrigin(createStacksPublicKey(key));
}

return transaction;
Expand Down Expand Up @@ -753,7 +746,7 @@ export async function sponsorTransaction(

const options = Object.assign(defaultOptions, sponsorOptions);

const sponsorPubKey = pubKeyfromPrivKey(options.sponsorPrivateKey);
const sponsorPubKey = privateKeyToPublic(options.sponsorPrivateKey);

if (sponsorOptions.fee == null) {
let txFee: bigint | number = 0;
Expand Down Expand Up @@ -787,14 +780,14 @@ export async function sponsorTransaction(

const sponsorSpendingCondition = createSingleSigSpendingCondition(
options.sponsorAddressHashmode,
publicKeyToString(sponsorPubKey),
sponsorPubKey,
options.sponsorNonce,
options.fee
);

options.transaction.setSponsor(sponsorSpendingCondition);

const privKey = createStacksPrivateKey(options.sponsorPrivateKey);
const privKey = options.sponsorPrivateKey;
const signer = TransactionSigner.createSponsorSigner(
options.transaction,
sponsorSpendingCondition
Expand Down

0 comments on commit 41e90f0

Please sign in to comment.