Implementation of a Password-Authenticated Key Exchange (PAKE) protocol using elliptic curve cryptography and Zero-Knowledge Proofs.
Config(curve: Curves, serverId: str)Parameters:
curve- Elliptic curve to use (P256, P384, P521, or FOURQ)serverId- Unique identifier for the server
Example:
config = Config(curve=Curves.P256, serverId="server123")Generate registration request without transmitting the password.
Process:
- Computes
t = H(username || password) mod n - Derives password verifier
pi = H(t) mod n(raisesValueErrorifpi == 0) - Creates public commitment
T = G * t
Returns: RegistrationRequest(pi, T) to send to server
Example:
client = OwlClient(config)
reg_request = await client.register("alice", "password123")Initialize authentication by generating ephemeral secrets and Zero-Knowledge Proofs.
Process:
- Re-derives
tandpifrom credentials - Generates random secrets
x1,x2 - Computes
X1 = G * x1,X2 = G * x2 - Creates ZKPs proving knowledge of
x1andx2
Returns: AuthInitRequest(X1, X2, PI1, PI2) to send to server
Example:
auth_request = await client.authInit("alice", "password123")Complete authentication and derive shared session key.
Process:
- Verifies server's Zero-Knowledge Proofs
- Verifies X₄ ≠ identity element
- Computes shared secret point:
K = (beta - X4*(x2*pi)) * x2 - Derives session key:
k = H(K) - Includes Π₄ in transcript hash for full protocol compliance
- Generates proof of password knowledge:
r = x1 - (t * h) mod n - Clears ephemeral secrets from memory after computation
Returns:
finishRequest- Final message to send to serverkey- 32-byte session keykc- Key confirmation for mutual verification
Example:
result = await client.authFinish(server_response)
session_key = result.key # Use this for encryptionclient.register_sync(username, password) # RegistrationRequest
client.authInit_sync(username, password) # AuthInitRequest
client.authFinish_sync(response) # AuthFinishResultConvenience methods that call asyncio.run() internally. Use when running outside an async context.
Process registration and generate server credentials.
Process:
- Generates server secret
x3 - Computes
X3 = G * x3 - Creates ZKP proving knowledge of
x3
Returns: UserCredentials to store in database
Example:
server = OwlServer(config)
credentials = await server.register(client_request)
database.save("alice", credentials)OwlServer.authInit(username: str, request: AuthInitRequest, credentials: UserCredentials) -> AuthInitResult
Process authentication initialization with ZKP verification.
Process:
- Verifies client's ZKPs (PI1, PI2)
- Verifies X₂ ≠ identity element
- Generates ephemeral secret
x4 - Computes shared component:
beta = (X1+X2+X3) * (pi*x4) - Creates ZKPs for
X4andbeta
Returns:
response- Message to send to clientinitial- State to store forauthFinish()
Example:
credentials = database.get("alice")
result = await server.authInit("alice", client_request, credentials)
session.store(result.initial)OwlServer.authFinish(username: str, request: AuthFinishRequest, initial: AuthInitialValues) -> AuthFinishResult
Verify password and derive shared session key.
Process:
- Verifies client's alpha ZKP
- Derives shared key:
K = (alpha - X2*(x4*pi)) * x4 - Verifies password:
G*r + T*h == X1 - Generates session key:
k = H(K)
Returns:
key- 32-byte session key (matches client's)kc- Key confirmation for mutual verification
Example:
result = await server.authFinish(username, client_request, initial)
if isinstance(result, AuthenticationFailure):
return "Invalid password"
session_key = result.keyserver.register_sync(request) # UserCredentials
server.authInit_sync(username, request, credentials) # AuthInitResult | ZKPVerificationFailure
server.authFinish_sync(username, request, initial) # AuthFinishResult | AuthenticationFailure | ZKPVerificationFailureConvenience methods that call asyncio.run() internally.
Constant-time comparison of key confirmation values using hmac.compare_digest. Prevents timing side-channel attacks.
Parameters:
my_kc_test- The expected key confirmation string computed locallyreceived_kc- The key confirmation string received from the other party
Returns: True if the values match
Example:
from owl_crypto_py import OwlCommon
client_ok = OwlCommon.verifyKeyConfirmation(client_result.kcTest, server_result.kc)
server_ok = OwlCommon.verifyKeyConfirmation(server_result.kcTest, client_result.kc)
if client_ok and server_ok:
print("Mutual authentication confirmed")Elliptic curve point with cryptographic operations.
Key Methods:
# Scalar multiplication (main operation for key derivation)
result = point.multiply(scalar) # Returns scalar * point
# Point addition (for combining public keys)
sum = point1.add(point2)
# Point subtraction (for computing shared secrets)
diff = point1.subtract(point2)
# Serialization for network transmission
hex_str = point.to_hex()
point = Point.from_hex(hex_str, curve)Create Zero-Knowledge Proof that proves knowledge of x where X = G*x, without revealing x.
Process:
- Generates random nonce
v - Computes commitment
V = G * v - Computes challenge
h = H(G, V, X, prover) - Computes response
r = v - x*h mod n
Returns: ZKP(h, r) that can be verified by anyone
Verify Zero-Knowledge Proof without learning the secret.
Verification:
- Reconstructs commitment:
V = G*r + X*h - Recomputes challenge:
h' = H(G, V, X, prover) - Checks if
h == h'
Returns: True if proof is valid