Skip to content

Commit

Permalink
refactor!: Remove wrapper type for message signatures
Browse files Browse the repository at this point in the history
  • Loading branch information
janniks committed Sep 17, 2024
1 parent 088c326 commit 4128a88
Show file tree
Hide file tree
Showing 16 changed files with 89 additions and 90 deletions.
11 changes: 11 additions & 0 deletions .github/MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- [Stacks Network](#stacks-network)
- [Impacts](#impacts)
- [Fetch Methods](#fetch-methods)
- [Reducing Wrapper Types](#reducing-wrapper-types)
- [StacksNodeApi](#stacksnodeapi)
- [StacksNetwork to StacksNodeApi](#stacksnetwork-to-stacksnodeapi)
- [Clarity Representation](#clarity-representation)
Expand Down Expand Up @@ -36,6 +37,7 @@

- The `@stacks/network` `new StacksNetwork()` objects were removed. Instead `@stacks/network` now exports the objects `STACKS_MAINNET`, `STACKS_TESNET`, and `STACKS_DEVNET`, which are static (and shouldn't be changed for most use-cases). [Read more...](#stacks-network)
- Most `fetch` (aka networking) methods were renamed to indicate they send HTTP requests. The new methods are named `fetchXyz` and are compatible with the old `Xyz` interfaces. [Read more...](#fetch-methods)
- Reducing wrapper types, which create annoyances for the developer, rather than being able to use values directly. [Read more...](#reducing-wrapper-types)
- The `ClarityType` enum was replaced by a human-readable version. The previous (wire format compatible) enum is still available as `ClarityWireType`. [Read more...](#clarity-representation)
- The previous post-conditions types and `create..` methods were replaced with a human-readable representation. [Read more...](#post-conditions)
- `StacksTransaction.serialize` and other `serializeXyz` methods were changed to return `string` (hex-encoded) instead of `Uint8Array`. Compatible `serializeXzyBytes` methods were added to ease the migration. [Read more...](#serialize-methods)
Expand Down Expand Up @@ -83,6 +85,15 @@ The following methods were renamed:
`broadcastTransaction` wasn't renamed to highlight the uniqueness of the method.
Namely, the node/API it is sent to will "broadcast" the transaction to the mempool.

### Reducing Wrapper Types

With this release we are aiming to reduce unnecessary "wrapper" types, which are used in the internals of the codebase, but shouldn't be pushed onto the user/developer.

This breaks the signatures of many functions:

- `signMessageHashRsv`, `signWithKey` now return the message signature as a `string` directly.
- `nextSignature`, `nextVerification`, `publicKeyFromSignatureVrs`, `publicKeyFromSignatureRsv` now take in the message signature as a `string`.

### StacksNodeApi

The new `StacksNodeApi` class lets you interact with a Stacks node or API.
Expand Down
8 changes: 4 additions & 4 deletions packages/bns/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ApiParam, IntegerType, intToBigInt, utf8ToBytes } from '@stacks/common';
import { ApiParam, IntegerType, PublicKey, intToBigInt, utf8ToBytes } from '@stacks/common';
import { StacksNetwork } from '@stacks/network';
import {
ClarityType,
Expand Down Expand Up @@ -55,7 +55,7 @@ export interface PriceFunction {
export interface BnsContractCallOptions {
functionName: string;
functionArgs: ClarityValue[];
publicKey: string;
publicKey: PublicKey;
network: StacksNetwork;
postConditions?: PostCondition[];
}
Expand Down Expand Up @@ -480,7 +480,7 @@ export interface PreorderNameOptions {
/** amount of STX to burn for the registration */
stxToBurn: IntegerType;
/** the private key to sign the transaction */
publicKey: string;
publicKey: PublicKey;
/** the Stacks blockchain network to use */
network: StacksNetwork;
}
Expand Down Expand Up @@ -541,7 +541,7 @@ export interface RegisterNameOptions {
fullyQualifiedName: string;
salt: string;
zonefile: string;
publicKey: string;
publicKey: PublicKey;
network: StacksNetwork;
}

Expand Down
4 changes: 3 additions & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
"prepublishOnly": "npm run test && NODE_ENV=production npm run build",
"start": "tsc -b tsconfig.build.json --watch --verbose",
"test": "jest",
"test:watch": "jest --watch --coverage=false"
"test:watch": "jest --watch --coverage=false",
"typecheck": "tsc --noEmit",
"typecheck:watch": "npm run typecheck -- --watch"
},
"dependencies": {
"@scure/bip32": "1.1.3",
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ async function migrateSubdomains(network: CLINetworkAdapter, args: string[]): Pr
const sig = signWithKey(account.dataPrivateKey, hash);

// https://docs.stacks.co/build-apps/references/bns#subdomain-lifecycle
subDomainOp.signature = sig.data;
subDomainOp.signature = sig;

payload.subdomains_list.push(subDomainOp);
}
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/tests/cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,7 @@ describe('Subdomain Migration', () => {
const hash = crypto.createHash('sha256').update(textToSign).digest('hex');
const sig = signWithKey(privateKey, hash);

subDomainOp.signature = sig.data; // Assign signature to subDomainOp
subDomainOp.signature = sig; // Assign signature to subDomainOp

// Verify that the generated signature is valid
const pubKey = publicKeyFromSignatureVrs(hash, sig);
Expand Down
2 changes: 1 addition & 1 deletion packages/stacking/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ export function signPox4SignatureHash({
return signStructuredData({
...pox4SignatureMessage({ topic, poxAddress, rewardCycle, period, network, maxAmount, authId }),
privateKey,
}).data;
});
}

/**
Expand Down
20 changes: 9 additions & 11 deletions packages/transactions/src/authorization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
intToBigInt,
intToBytes,
PrivateKey,
PublicKey,
writeUInt16BE,
} from '@stacks/common';
import { BytesReader } from './BytesReader';
Expand Down Expand Up @@ -117,7 +118,7 @@ export function createSpendingCondition(

export function createSingleSigSpendingCondition(
hashMode: SingleSigHashMode,
pubKey: string,
pubKey: PublicKey,
nonce: IntegerType,
fee: IntegerType
): SingleSigSpendingCondition {
Expand Down Expand Up @@ -365,11 +366,8 @@ export function makeSigHashPreSign(
return txidFromData(hexToBytes(sigHash));
}

function makeSigHashPostSign(
curSigHash: string,
pubKey: PublicKeyWire,
signature: MessageSignatureWire
): string {
/** @internal */
function makeSigHashPostSign(curSigHash: string, pubKey: PublicKeyWire, signature: string): string {
// new hash combines the previous hash and all the new data this signature will add. This
// includes:
// * the public key compression flag
Expand All @@ -380,7 +378,7 @@ function makeSigHashPostSign(
? PubKeyEncoding.Compressed
: PubKeyEncoding.Uncompressed;

const sigHash = curSigHash + leftPadHex(pubKeyEncoding.toString(16)) + signature.data;
const sigHash = curSigHash + leftPadHex(pubKeyEncoding.toString(16)) + signature;

const sigHashBytes = hexToBytes(sigHash);
if (sigHashBytes.byteLength > hashLength) {
Expand All @@ -397,7 +395,7 @@ export function nextSignature(
nonce: IntegerType,
privateKey: PrivateKey
): {
nextSig: MessageSignatureWire;
nextSig: string;
nextSigHash: string;
} {
const sigHashPreSign = makeSigHashPreSign(curSigHash, authType, fee, nonce);
Expand All @@ -418,7 +416,7 @@ export function nextVerification(
fee: IntegerType,
nonce: IntegerType,
pubKeyEncoding: PubKeyEncoding,
signature: MessageSignatureWire
signature: string
) {
const sigHashPreSign = makeSigHashPreSign(initialSigHash, authType, fee, nonce);

Expand Down Expand Up @@ -465,7 +463,7 @@ function verifySingleSig(
condition.fee,
condition.nonce,
condition.keyEncoding,
condition.signature
condition.signature.data
);

// address version arg doesn't matter for signer hash generation
Expand Down Expand Up @@ -508,7 +506,7 @@ function verifyMultiSig(
condition.fee,
condition.nonce,
field.pubKeyEncoding,
field.contents
field.contents.data
);

if (isSequentialMultiSig(condition.hashMode)) {
Expand Down
54 changes: 30 additions & 24 deletions packages/transactions/src/builders.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ApiOpts, ApiParam, IntegerType } from '@stacks/common';
import { ApiOpts, ApiParam, IntegerType, PrivateKey, PublicKey } from '@stacks/common';
import {
STACKS_MAINNET,
STACKS_TESTNET,
Expand Down Expand Up @@ -28,8 +28,14 @@ import {
SingleSigHashMode,
} from './constants';
import { ClarityAbi, validateContractCall } from './contract-abi';
import { fetchFeeEstimate, fetchAbi, fetchNonce } from './fetch';
import { createStacksPublicKey, privateKeyToPublic, publicKeyToAddress } from './keys';
import { fetchAbi, fetchFeeEstimate, fetchNonce } from './fetch';
import {
createStacksPublicKey,
privateKeyToHex,
privateKeyToPublic,
publicKeyToAddress,
publicKeyToHex,
} from './keys';
import { postConditionToWire } from './postcondition';
import { PostCondition } from './postcondition-types';
import { TransactionSigner } from './signer';
Expand All @@ -56,7 +62,7 @@ export interface UnsignedMultiSigOptions {
/** The minimum required signatures N (in a N of M multi-sig) */
numSignatures: number;
/** The M public-keys (in a N of M multi-sig), which together form the address of the multi-sig account */
publicKeys: string[];
publicKeys: PublicKey[];
/**
* The `address` of the multi-sig account.
* - If NOT provided, the public-key order is taken AS IS.
Expand All @@ -69,7 +75,7 @@ export interface UnsignedMultiSigOptions {
}

export type SignedMultiSigOptions = UnsignedMultiSigOptions & {
signerKeys: string[];
signerKeys: PrivateKey[];
};

/**
Expand All @@ -95,11 +101,11 @@ export type TokenTransferOptions = {
} & ApiParam;

export interface UnsignedTokenTransferOptions extends TokenTransferOptions {
publicKey: string;
publicKey: PublicKey;
}

export interface SignedTokenTransferOptions extends TokenTransferOptions {
senderKey: string;
senderKey: PrivateKey;
}

export type UnsignedMultiSigTokenTransferOptions = TokenTransferOptions & UnsignedMultiSigOptions;
Expand Down Expand Up @@ -151,12 +157,12 @@ export async function makeUnsignedSTXTokenTransfer(

const publicKeys = options.address
? sortPublicKeysForAddress(
options.publicKeys,
options.publicKeys.map(publicKeyToHex),
options.numSignatures,
hashMode,
createAddress(options.address).hash160
)
: options.publicKeys;
: options.publicKeys.map(publicKeyToHex);

spendingCondition = createMultiSigSpendingCondition(
hashMode,
Expand Down Expand Up @@ -226,8 +232,8 @@ export async function makeSTXTokenTransfer(

mutatingSignAppendMultiSig(
transaction,
txOptions.publicKeys.slice(),
txOptions.signerKeys,
txOptions.publicKeys.map(publicKeyToHex).slice(),
txOptions.signerKeys.map(privateKeyToHex),
txOptions.address
);

Expand Down Expand Up @@ -262,11 +268,11 @@ export interface BaseContractDeployOptions {

export interface UnsignedContractDeployOptions extends BaseContractDeployOptions {
/** a hex string of the public key of the transaction sender */
publicKey: string;
publicKey: PublicKey;
}

export interface SignedContractDeployOptions extends BaseContractDeployOptions {
senderKey: string;
senderKey: PrivateKey;
}

/** @deprecated Use {@link SignedContractDeployOptions} or {@link UnsignedContractDeployOptions} instead. */
Expand Down Expand Up @@ -307,8 +313,8 @@ export async function makeContractDeploy(

mutatingSignAppendMultiSig(
transaction,
txOptions.publicKeys.slice(),
txOptions.signerKeys,
txOptions.publicKeys.map(publicKeyToHex).slice(),
txOptions.signerKeys.map(privateKeyToHex),
txOptions.address
);

Expand Down Expand Up @@ -357,12 +363,12 @@ export async function makeUnsignedContractDeploy(

const publicKeys = options.address
? sortPublicKeysForAddress(
options.publicKeys,
options.publicKeys.map(publicKeyToHex),
options.numSignatures,
hashMode,
createAddress(options.address).hash160
)
: options.publicKeys;
: options.publicKeys.map(publicKeyToHex);

spendingCondition = createMultiSigSpendingCondition(
hashMode,
Expand Down Expand Up @@ -440,11 +446,11 @@ export interface ContractCallOptions {
}

export interface UnsignedContractCallOptions extends ContractCallOptions {
publicKey: string;
publicKey: PrivateKey;
}

export interface SignedContractCallOptions extends ContractCallOptions {
senderKey: string;
senderKey: PublicKey;
}

export type UnsignedMultiSigContractCallOptions = ContractCallOptions & UnsignedMultiSigOptions;
Expand Down Expand Up @@ -514,12 +520,12 @@ export async function makeUnsignedContractCall(

const publicKeys = options.address
? sortPublicKeysForAddress(
options.publicKeys,
options.publicKeys.map(publicKeyToHex),
options.numSignatures,
hashMode,
createAddress(options.address).hash160
)
: options.publicKeys;
: options.publicKeys.map(publicKeyToHex);

spendingCondition = createMultiSigSpendingCondition(
hashMode,
Expand Down Expand Up @@ -594,8 +600,8 @@ export async function makeContractCall(

mutatingSignAppendMultiSig(
transaction,
txOptions.publicKeys.slice(),
txOptions.signerKeys,
txOptions.publicKeys.map(publicKeyToHex).slice(),
txOptions.signerKeys.map(privateKeyToHex),
txOptions.address
);

Expand All @@ -610,7 +616,7 @@ export interface SponsorOptionsOpts {
/** the origin-signed transaction */
transaction: StacksTransaction;
/** the sponsor's private key */
sponsorPrivateKey: string;
sponsorPrivateKey: PrivateKey;
/** the transaction fee amount to sponsor */
fee?: IntegerType;
/** the nonce of the sponsor account */
Expand Down
Loading

0 comments on commit 4128a88

Please sign in to comment.