Metadata-Version: 2.4
Name: totp-rs
Version: 2.0.0
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Zero-Clause BSD (0BSD)
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: 3.15
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Rust
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
License-File: LICENSE-THIRD-PARTY.md
License-File: LICENSE.md
Summary: RFC 6238 time-based one-time password implementation
Keywords: 2fa,auth,hmac,otp,rfc6238,totp
Author-email: Kamil Monicz <kamil@monicz.dev>
License-Expression: 0BSD
Requires-Python: >=3.11
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Issues, https://github.com/Zaczero/pkgs/issues
Project-URL: Repository, https://github.com/Zaczero/pkgs/tree/main/totp-rs

# totp-rs

Generate and verify time-based one-time passwords in Python, backed by Rust.
Supports [RFC 6238](https://datatracker.ietf.org/doc/html/rfc6238) with SHA-1,
SHA-256, or SHA-512. Python 3.11+.

## Installation

```sh
pip install totp-rs
```

## Usage

```py
from totp_rs import totp_generate, totp_verify

# Example secret; provision a unique random secret for each account.
secret = b'12345678901234567890'
code = totp_generate(secret)
print(code)  # Changes with the current time.
valid = totp_verify(secret, code, window=1)
```

Secrets may be raw bytes or Base32 text. `window=1` accepts the previous,
current, or next time step to allow for clock drift. Choose the algorithm,
number of digits, and step length to match the authenticator.

<a id="inputs-and-errors"></a>
<a id="mutually-exclusive-time-inputs"></a>

## Explicit timestamps

Pass `time` for a fixed Unix timestamp, or `time_window` for a counter directly;
the two are mutually exclusive. This example reproduces the RFC's SHA-1 test
vector:

```py
from totp_rs import totp_generate

code = totp_generate(b'12345678901234567890', digits=8, time=59)
print(code)  # 94287082
```

Timestamps must be finite and fit signed 64-bit whole seconds after flooring;
negative timestamps are supported. Deriving a counter requires a positive
step length. An explicit `time_window` uses the supplied counter directly and
ignores the step length and origin.

Verification compares code bytes in constant time, but validation and the drift
search can return early. The library does not store replay state or rate-limit
attempts; enforce those in your application.

## Benchmarks

**About 4.8–58× faster than PyOTP** at generating and verifying six-digit codes
with SHA-1, SHA-256, and SHA-512, by median time on this workstation.

<picture>
  <source media="(prefers-color-scheme: dark)" srcset="benchmarks/results-dark.svg">
  <img src="https://raw.githubusercontent.com/Zaczero/pkgs/totp-rs/2.0.0/totp-rs/benchmarks/results.svg" alt="Median time for four TOTP generation and verification operations with SHA-1, SHA-256, and SHA-512. Error bars show 95% bootstrap intervals across worker-process means.">
</picture>

| Algorithm / implementation | Generate current code | Verify current | Verify previous step | Reject incorrect |
| --- | ---: | ---: | ---: | ---: |
| SHA-1 · totp-rs 2.0.0 | 396 ns | 455 ns | 509 ns | 592 ns |
| SHA-1 · PyOTP 2.10.0 | 10.9 µs | 23.0 µs | 11.3 µs | 34.5 µs |
| SHA-256 · totp-rs 2.0.0 | 436 ns | 459 ns | 550 ns | 651 ns |
| SHA-256 · PyOTP 2.10.0 | 11.0 µs | 23.3 µs | 12.4 µs | 37.1 µs |
| SHA-512 · totp-rs 2.0.0 | 1.82 µs | 1.73 µs | 2.47 µs | 3.16 µs |
| SHA-512 · PyOTP 2.10.0 | 13.2 µs | 24.6 µs | 11.8 µs | 35 µs |

Median time per call on CPython 3.15.0 and a shared Ryzen 9 5950X workstation
running Linux 7.2.9. Both use the same Base32 secret, timestamp, 30-second
period, and ±1 window.

[Full results](https://raw.githubusercontent.com/Zaczero/pkgs/totp-rs/2.0.0/totp-rs/benchmarks/results.md) · Raw PyPerf results:
[totp-rs](https://raw.githubusercontent.com/Zaczero/pkgs/totp-rs/2.0.0/totp-rs/benchmarks/totp-rs.json), [PyOTP](https://raw.githubusercontent.com/Zaczero/pkgs/totp-rs/2.0.0/totp-rs/benchmarks/pyotp.json) ·
[Benchmark source](https://raw.githubusercontent.com/Zaczero/pkgs/totp-rs/2.0.0/totp-rs/benchmark.py)

## API reference and support

See the [`totp_time_window`, `totp_generate`, and `totp_verify` reference](https://github.com/Zaczero/pkgs/blob/main/totp-rs/python/totp_rs/_lib.pyi)
for parameters, defaults, and errors.

[Issues and questions](https://github.com/Zaczero/pkgs/issues) ·
[Private security reports](https://github.com/Zaczero/pkgs/security/advisories/new) ·
[Premium support](https://monicz.dev/#get-in-touch)

