Skip to content

Invoke tx hash with proofFacts is incompatible with privacy implementation on Testnet #1601

@dhruvkelawala

Description

@dhruvkelawala

Version

  • local checkout: starknet-io/starknet.js
  • branch: beta
  • commit: 181c969c
  • package version on that branch: 10.0.0-beta.5

Summary

proofFacts are supported natively in the beta branch, but the current invoke tx-hash semantics appear incompatible with the StarkWare privacy-network / privacy-SDK fork semantics.

When we use the native beta.5 signing path for privacy transactions, the transaction payload includes proof_facts, but account validation fails with argent invalid owner sig. Regular transactions from the same account/signer still work.

Source references

1. Invoke tx hash implementation

In the beta branch source, proofFacts are appended as raw additional-data elements:

  • src/utils/hash/transactionHash/v3.ts:174-203
export function calculateInvokeTransactionHash(..., proofFacts?: BigNumberish[]): string {
  return calculateTransactionHashCommon(..., [
    poseidonHashMany(AToBI(accountDeploymentData)),
    poseidonHashMany(AToBI(compiledCalldata)),
    ...(proofFacts ? AToBI(proofFacts) : []),
  ]);
}

2. Public helper forwards proofFacts unchanged

  • src/utils/hash/transactionHash/index.ts:43-58
return v3calculateInvokeTransactionHash(..., args.proofFacts);

3. Default signer uses that path directly

  • src/signer/default.ts:43-60
msgHash = calculateInvokeTransactionHash({
  ...det,
  senderAddress: det.walletAddress,
  compiledCalldata,
  version: det.version,
  nonceDataAvailabilityMode: intDAM(det.nonceDataAvailabilityMode),
  feeDataAvailabilityMode: intDAM(det.feeDataAvailabilityMode),
});

4. Tests currently assert that raw-array semantics are expected

  • __tests__/utils/transactionHash.test.ts:22-69

These tests assert:

  • empty proofFacts == omitted proofFacts
  • non-empty proofFacts changes the hash
  • proofFacts order matters

That matches the current raw-array behavior.

Observed behavior against privacy-enabled network

Using the native starknet.js beta.5 signing path for a privacy tx:

  • the RPC payload contains proof_facts
  • the node rejects the signature during validate
  • regular non-privacy txs from the same account/signer succeed

Example validate failure:

Account validation failed: ... argent invalid owner sig

Why we think the tx-hash semantics are the issue

We tested both paths against the same privacy transaction flow:

  1. Native beta.5 path
  • proof_facts are present in the RPC payload
  • transaction is rejected with invalid signature
  1. Privacy-specific compatibility path
  • identical tx payload / signer / proof data
  • but tx hash is computed with:
    • poseidon(accountDeploymentData)
    • poseidon(compiledCalldata)
    • poseidon(proofFacts) as one additional element
  • transaction succeeds

So serialization is not the issue; the payload already includes proof_facts. The divergence appears to be in tx-hash/signature agreement.

Expected / question

Is this incompatibility with the StarkWare privacy fork intentional?

If yes, it would be helpful to document that native proofFacts support in upstream starknet.js is not compatible with privacy-network fork hash semantics.

If not, would you consider either:

  1. aligning the invoke hash behavior, or
  2. exposing a compatibility option / hash mode for networks that still expect the privacy-fork semantics?

Extra context

This surfaced while integrating @starkware-libs/starknet-privacy-sdk@0.14.2-RC.2 against a privacy-enabled network. The native upstream beta.5 code path was close, but not signature-compatible with that network’s validation rules.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions