Skip to content

Conversation

@callebtc
Copy link
Contributor

@callebtc callebtc commented Jan 3, 2026

Implements the correct KDF for V2 keysets (01-prefixed) as specified in the updated Keyset V2 version of NUT-13 (PR).

Changes:

  • Blinding factors are now reduced modulo SECP256K1_N to ensure valid private key scalars
  • Added optimization: single subtraction instead of full modulo (only ~2^-128 of HMAC outputs need reduction)
  • Added Bytes.toBigInt() and Bytes.fromBigInt() utility methods
  • Deprecated bytesToNumber() in favor of Bytes.toBigInt() for better performance

Modulo optimization: A 256-bit HMAC output only needs one subtraction to be < SECP256K1_N. Full modulo is ~10-20x more expensive than a single comparison and conditional subtraction.

@robwoodgate
Copy link
Collaborator

@callebtc - Can you rebase this to the development branch please

@robwoodgate
Copy link
Collaborator

robwoodgate commented Jan 3, 2026

@callebtc - this is generally an excellent idea. Previously we were leaning on noble curves to ensure modulo n with secp256k1.Point.Fn.fromBytes(), but having it explicit and optimized via a single subtraction is perfect.

It does, however, highlight the issue I raised here, where it was pointed out that BIP-32 does not appear to do modulo n on derived factors. Assuming we are committing to deviate from that and ensure legacy NUT-13 factors WILL always be mod n as per your linked PR.

That leaves just NUT-26 (P2BK) as the outlier... I originally specified it as mod n, but @aidenvalue said this was problematic in CDK, so it was relaxed to a "try again if > n-1". Your PR here makes it mod n. Are we able to commit to that now in CDK?


// Core Utils
export * from './utils/core';
export * from './utils';
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why is this export being widened?

@Egge21M
Copy link
Collaborator

Egge21M commented Jan 4, 2026

It does, however, highlight the issue I raised here, where it was pointed out that BIP-32 does not appear to do modulo n on derived factors. Assuming we are committing to deviate from that and ensure legacy NUT-13 factors WILL always be mod n as per your linked PR.

Personally I think for something like Cashu proofs skipping an index if it produces an invalid result is perfectly fine. That would be inline with BIP-32 and would not need any additional complexity.

Edit: On the other hand it requires counters to be adjusted somehow, which might be managed in a different layer of the app.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants