Skip to content

fix(keypairs): strip exact secp256k1 prefix, not all leading zeros (#290)#303

Open
satyakwok wants to merge 1 commit into
XRPLF:mainfrom
satyakwok:fix/secp256k1-prefix-strip-290
Open

fix(keypairs): strip exact secp256k1 prefix, not all leading zeros (#290)#303
satyakwok wants to merge 1 commit into
XRPLF:mainfrom
satyakwok:fix/secp256k1-prefix-strip-290

Conversation

@satyakwok

Copy link
Copy Markdown

Closes #290.

Summary

Secp256k1::sign used trim_start_matches(SECP256K1_PREFIX) where SECP256K1_PREFIX is defined as a single char '0'. That strips every leading '0' character from the hex-encoded key, not just the 2-char "00" prefix the XRPL secp256k1 encoding actually uses.

For a legitimate private key whose underlying 32 bytes start with 0x00 (~1-in-256 random keys; trivially constructible like scalar 1), the prefixed form is "0000…" — the over-strip removes both the prefix and the key's leading zeros, leaving a too-short string that SecretKey::from_str rejects. sign() then fails on a valid key.

Replace trim_start_matches with strip_prefix("00").unwrap_or(...) so exactly the 2-char prefix is removed and the actual key bytes are preserved. The SECP256K1_PREFIX: char = '0' public constant is left untouched (still pub) — only the consumer in sign changes.

Test

Adds secp256k1_sign_handles_private_key_with_leading_zero_bytes, which constructs the canonical 66-char form of scalar 1 ("00" + 62 zeros + "01") and verifies sign() succeeds. Fails on main (SecretKey::from_str errors on the over-stripped string).

Smoke gate

  • cargo build
  • cargo test --lib core::keypairs::algorithms — 7 passed, 0 failed.

…RPLF#290)

`Secp256k1::sign` used `trim_start_matches(SECP256K1_PREFIX)` where
`SECP256K1_PREFIX: char = '0'`. That strips *every* leading '0'
character from the hex-encoded key, not just the 2-char "00" prefix
the XRPL secp256k1 encoding actually uses.

For a legitimate private key whose underlying 32 bytes start with
0x00 (~1-in-256 random keys; trivially constructible like scalar 1),
the prefixed form is "0000…" — the over-strip removes both the
prefix and the key's leading zeros, leaving a too-short string that
`SecretKey::from_str` rejects. sign() then fails on a valid key.

Replace `trim_start_matches` with `strip_prefix("00").unwrap_or(...)`
so exactly the 2-char prefix is removed and the actual key bytes are
preserved. The `SECP256K1_PREFIX: char = '0'` constant is left
untouched (still `pub`) — only the consumer in `sign` changes.

Adds `secp256k1_sign_handles_private_key_with_leading_zero_bytes`,
which constructs the canonical 66-char form of scalar `1`
("00" + 62 zeros + "01") and verifies sign() succeeds on it.
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.

Wrong Secp256k1 Key Parsing

1 participant