Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/bot-assignment-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden the runner
uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
with:
egress-policy: audit

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/bot-inactivity-unassign-phase1.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8

- name: Harden the runner
uses: step-security/harden-runner@df199fb7be9f65074067a9eb93f12bb4c5547cf2
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76
with:
egress-policy: audit

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/bot-office-hours.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden the runner
uses: step-security/harden-runner@df199fb7be9f65074067a9eb93f12bb4c5547cf2
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76
with:
egress-policy: audit

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/bot-verified-commits.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:

steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@df199fb7be9f65074067a9eb93f12bb4c5547cf2 # v2.13.3
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
with:
egress-policy: audit

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/bot-workflows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@df199fb7be9f65074067a9eb93f12bb4c5547cf2 # v2.13.3
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
with:
egress-policy: audit

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/examples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@df199fb7be9f65074067a9eb93f12bb4c5547cf2 # v2.13.3
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
with:
egress-policy: audit

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/merge-conflict-bot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:

steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@df199fb7be9f65074067a9eb93f12bb4c5547cf2 # v2.13.3
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
with:
egress-policy: audit

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pr-check-changelog.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
fetch-depth: 0

- name: Harden the runner
uses: step-security/harden-runner@df199fb7be9f65074067a9eb93f12bb4c5547cf2 # v2.13.3
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
with:
egress-policy: audit

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pr-check-title.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
statuses: write
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@df199fb7be9f65074067a9eb93f12bb4c5547cf2 # v2.13.3
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
with:
egress-policy: audit

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pr-inactivity-reminder-bot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:

steps:
- name: Harden the runner
uses: step-security/harden-runner@df199fb7be9f65074067a9eb93f12bb4c5547cf2 # v2.13.3
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
with:
egress-policy: audit
- name: Checkout repository
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
id-token: write
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@df199fb7be9f65074067a9eb93f12bb4c5547cf2 # v2.13.3
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
with:
egress-policy: audit

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:

steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@df199fb7be9f65074067a9eb93f12bb4c5547cf2 # v2.13.3
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
with:
egress-policy: audit

Expand Down
8 changes: 5 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,21 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.
## [Unreleased]

### Added

- Modularized `transfer_transaction_fungible` example by introducing `account_balance_query()` & `transfer_transaction()`.Renamed `transfer_tokens()` → `main()`
- Phase 2 of the inactivity-unassign bot:Automatically detects stale open pull requests (no commit activity for 21+ days), comments with a helpful InactivityBot message, closes the stale PR, and unassigns the contributor from the linked issue.
- Added **str**() to CustomFixedFee and updated examples and tests accordingly.
- Added `__str__()` to CustomFixedFee and updated examples and tests accordingly.
- Added unit tests for `crypto_utils` (#993)
- Added a github template for good first issues
- Added `.github/workflows/bot-assignment-check.yml` to limit non-maintainers to 2 concurrent issue assignments.
- Added all missing fields to **str**() method and updated `test_tokem_info.py`
- Added all missing fields to `__str__()` method and updated `test_tokem_info.py`
- Add examples/tokens/token_create_transaction_pause_key.py example demonstrating token pause/unpause behavior and pause key usage (#833)
- Added `docs/sdk_developers/training/transaction_lifecycle.md` to explain the typical lifecycle of executing a transaction using the Hedera Python SDK.
- Add inactivity bot workflow to unassign stale issue assignees (#952)
- Made custom fraction fee end to end
- feat: AccountCreateTransaction now supports both PrivateKey and PublicKey [#939](https://github.com/hiero-ledger/hiero-sdk-python/issues/939)
- Added Acceptance Criteria section to Good First Issue template for better contributor guidance (#997)
- Added __str__() to CustomRoyaltyFee and updated examples and tests accordingly (#986)
- Added `__str__()` to CustomRoyaltyFee and updated examples and tests accordingly (#986)
- Restore bug and feature request issue templates (#996)(https://github.com/hiero-ledger/hiero-sdk-python/issues/996)
- Support selecting specific node account ID(s) for queries and transactions and added `Network._get_node()` with updated execution flow (#362)
- Add TLS support with two-stage control (`set_transport_security()` and `set_verify_certificates()`) for encrypted connections to Hedera networks. TLS is enabled by default for hosted networks (mainnet, testnet, previewnet) and disabled for local networks (solo, localhost) (#855)
Expand Down
88 changes: 88 additions & 0 deletions tests/unit/test_crypto_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
"""Unit tests for crypto_utils module."""
from cryptography.hazmat.primitives.asymmetric import ec
import pytest

from hiero_sdk_python.utils.crypto_utils import (
compress_point_unchecked,
compress_with_cryptography,
decompress_point,
keccak256,
)

pytestmark = pytest.mark.unit


Comment on lines +11 to +14
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

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

Missing pytest import and pytestmark = pytest.mark.unit marker. All other unit test files in this codebase include these. Add:

import pytest

pytestmark = pytest.mark.unit

after the imports and before the first test function.

Suggested change
import pytest
pytestmark = pytest.mark.unit

Copilot uses AI. Check for mistakes.
def test_keccak256():
"""Test keccak256 hashing."""
# Known vector: empty string -> c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470
assert keccak256(b"").hex() == "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"

# "hello" -> 1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8
assert keccak256(b"hello").hex() == "1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"

Comment on lines +15 to +22
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

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

Missing test coverage for error handling in keccak256. The function raises RuntimeError when the pycryptodome library is not available (see crypto_utils.py line 24). Consider adding a test case to verify this behavior or at least document that it's tested elsewhere.

Copilot uses AI. Check for mistakes.
# "Transfer" -> 461a29a8a7db848c0827103038dd4776114eb182e0717208d0a793574936353d
assert keccak256(b"Transfer").hex() == "f099cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"


def test_compress_point_unchecked():
"""Test point compression logic."""
# Use cryptography to generate a valid point
priv = ec.generate_private_key(ec.SECP256K1())
pub = priv.public_key()
nums = pub.public_numbers()
x = nums.x
y = nums.y

compressed = compress_point_unchecked(x, y)
assert len(compressed) == 33

# Verify expected prefix
expected_prefix = 0x03 if y % 2 else 0x02
assert compressed[0] == expected_prefix
assert int.from_bytes(compressed[1:], "big") == x


def test_decompress_point():
"""Test point decompression logic."""
priv = ec.generate_private_key(ec.SECP256K1())
pub = priv.public_key()
nums = pub.public_numbers()

# Create valid compressed point
compressed = compress_point_unchecked(nums.x, nums.y)

# Test decompression
x, y = decompress_point(compressed)
assert x == nums.x
assert y == nums.y

# Test uncompressed 65-byte format (0x04 + x + y)
uncompressed = b'\x04' + nums.x.to_bytes(32, 'big') + nums.y.to_bytes(32, 'big')
x2, y2 = decompress_point(uncompressed)
assert x2 == nums.x
assert y2 == nums.y

Comment on lines +45 to +64
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

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

Missing test coverage for error handling in decompress_point. The function raises ValueError when the input is not a valid compressed or uncompressed point (see crypto_utils.py line 51). Consider adding a test case like:

def test_decompress_point_invalid_format():
    \"\"\"Test that invalid point format raises ValueError.\"\"\"
    with pytest.raises(ValueError, match="Not recognized as compressed or uncompressed SEC1 point"):
        decompress_point(b"invalid")

Copilot uses AI. Check for mistakes.
# Test invalid length
with pytest.raises(ValueError, match="Not recognized"):
decompress_point(b'\x04' * 10)

# Test invalid prefix
with pytest.raises(ValueError, match="Not recognized"):
# 0x05 is invalid prefix for 33-byte point
invalid_point = b'\x05' + nums.x.to_bytes(32, 'big')
decompress_point(invalid_point)


def test_compress_with_cryptography():
"""Test compression using cryptography library."""
priv = ec.generate_private_key(ec.SECP256K1())
pub = priv.public_key()
nums = pub.public_numbers()

# Create uncompressed
uncompressed = b'\x04' + nums.x.to_bytes(32, 'big') + nums.y.to_bytes(32, 'big')

compressed_via_lib = compress_with_cryptography(uncompressed)
compressed_manual = compress_point_unchecked(nums.x, nums.y)

assert compressed_via_lib == compressed_manual
Loading