A minimal and secure Go implementation of the SPAKE2 password-authenticated key exchange (PAKE) protocol using the Ristretto group.
This library allows two parties that share a low-entropy password to securely establish a shared secret and mutually authenticate without revealing the password, even over untrusted networks.
- SPAKE2 PAKE protocol
- Ristretto255 group
- Constant-size messages
- Mutual authentication via HMAC
- No password exposure or transmission
- Designed for networking and cryptographic projects
package spake
type Spake struct {
Role bool
}Represents a single SPAKE2 protocol instance.
-
Rolemust differ between the two peers:true→ initiatorfalse→ responder
All cryptographic state is stored internally.
Initializes the SPAKE2 exchange.
Behavior:
- Generates a fresh ephemeral scalar
- Derives a password scalar
- Computes the blinded public point
- Serializes the protocol message
Parameters:
password: shared secret password (raw bytes)
Returns:
- A 33-byte message to be sent to the peer
- An error if initialization fails
Usage:
msg, err := sp.Start(password)Completes the SPAKE2 key exchange.
Behavior:
- Validates peer message
- Removes password blinding
- Derives the shared secret
- Derives a MAC key via HKDF
Parameters:
remoteData: 33-byte message received from the peer
Returns:
- The raw shared secret bytes
- An error if validation or computation fails
Usage:
sharedSecret, err := sp.Finish(peerMsg)Generates the authentication MAC.
Behavior:
- Computes an HMAC over the protocol transcript
- Proves possession of the shared secret
Returns:
- A 32-byte MAC to send to the peer
Usage:
mac := sp.GetLetter()Verifies the peer’s authentication MAC.
Behavior:
- Recomputes the transcript MAC
- Performs constant-time comparison
Parameters:
letter: MAC received from the peer
Returns:
trueif authentication succeedsfalseotherwise
Usage:
ok := sp.CheckLetter(peerMAC)Generates a random Ristretto point encoded as base64.
Use cases:
- Testing
- Parameter generation
- Experimental extensions
Usage:
p := spake.GetRandomPoint()// Alice
a := &spake.Spake{Role: true}
msgA, _ := a.Start(password)
send(msgA)
// Bob
b := &spake.Spake{Role: false}
msgB, _ := b.Start(password)
send(msgB)
// Alice
secretA, _ := a.Finish(msgB)
macA := a.GetLetter()
send(macA)
// Bob
secretB, _ := b.Finish(msgA)
ok := b.CheckLetter(macA)Both secretA and secretB are identical if authentication succeeds.
- Password is never transmitted or derivable
- Resistant to passive and active network attacks
- No offline dictionary attacks without protocol interaction
- Mutual authentication guaranteed
- Constant-size messages
- Group: Ristretto255
- Hash: SHA-256
- Key Derivation: HKDF-SHA256
- Authentication: HMAC-SHA256
- Protocol versioning included in transcript
- Secure client-server authentication
- Encrypted tunnels
- Device pairing
- Password-based key exchange
- Cryptographic research and learning
- This implementation assumes both peers share the same password
- Roles must differ between peers
- One
Spakeinstance must not be reused