Skip to content
Merged
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
103 changes: 103 additions & 0 deletions examples_go/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# libzupt - Go Examples

This directory contains Go examples using the libzupt library through its C API
(`libzupt_cxx.h`, `zupt.h` and `zupt_keccak.h`), called via cgo.

## Prerequisites

- Go 1.21 or higher
- A C compiler supported by cgo (gcc/clang)
- CMake 3.15 or higher
- The built `libzupt.so` shared library (in `../build/`)

## Build

### Build the libzupt shared library (if not present in `../build/`):

```bash
cd ..
mkdir -p build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -DLIBZUPT_BUILD_TESTS=OFF -DLIBZUPT_BUILD_PYTHON=OFF
make -j$(nproc)
```

### Build the Go examples:

```bash
cd examples_go
./build.sh
```

This compiles the examples into a single `zupt_example` binary.

## Run the examples

Run all examples at once (default):

```bash
cd examples_go
LD_LIBRARY_PATH=../build ./zupt_example
```

Or run a single example:

```bash
LD_LIBRARY_PATH=../build ./zupt_example basic
LD_LIBRARY_PATH=../build ./zupt_example file
LD_LIBRARY_PATH=../build ./zupt_example keygen
LD_LIBRARY_PATH=../build ./zupt_example random
LD_LIBRARY_PATH=../build ./zupt_example secure_buffer
```

## Examples

1. **example_basic.go** - Basic encryption/decryption with memory data
2. **example_file.go** - Encrypting and decrypting files
3. **example_keygen.go** - Key generation and management
4. **example_random.go** - Generating random bytes and computing hashes
5. **example_secure_buffer.go** - Using SecureBuffer for zeroizing sensitive data

## API Reference

### KeyGenerator
- `GenerateKeyPair()` - Generate a new hybrid key pair
- `LoadKeyPair(filename)` - Load a key pair from file
- `LoadPublicKey(filename)` - Load a public key from file
- `ExportPublicKey(privFile, pubFile)` - Export public key from private key file
- `SaveKeyPair(keyPair, filename)` - Save a key pair to file

### Encryptor
- `Encrypt(data)` - Encrypt bytes in memory
- `EncryptSecure(buffer)` - Encrypt a SecureBuffer
- `EncryptFile(filename)` - Encrypt a file
- `HeaderSize()` - Size of encryption header

### Decryptor
- `Decrypt(ciphertext, encHeader)` - Decrypt bytes
- `DecryptSecure(ciphertext, encHeader)` - Decrypt to a SecureBuffer
- `DecryptFile(filename, encHeader)` - Decrypt a file

### SecureBuffer
- `NewSecureBuffer(data)` - Create from bytes
- `NewSecureBufferSize(size)` - Create empty buffer
- `Zeroize()` - Securely wipe memory
- `ToBytes()` - Convert to byte slice
- `String()` - Convert to string

### Helper Functions
- `RandomBytes(size)` - Generate cryptographically secure random bytes
- `Sha256(data)` - Compute SHA-256 hash
- `Sha3_512(data)` - Compute SHA3-512 hash
- `SecureWipe(data)` - Securely wipe memory
- `ReadFile(path)` / `WriteFile(path, data)` - File I/O through libzupt

### Constants
- `MLKEMPublicKeyBytes`, `MLKEMSecretKeyBytes`
- `MLKEMCiphertextBytes`, `MLKEMSSBytes`
- `X25519KeyBytes`
- `HybridPubKeySize`, `HybridPrivKeySize`, `HybridEncHeaderSize`
- `AESKeySize`, `AESNonceSize`, `HMACSize`

## License

SPDX-License-Identifier: MIT
52 changes: 52 additions & 0 deletions examples_go/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#!/bin/bash
# Build script for libzupt Go examples (cgo)
# Builds libzupt (if needed) and then compiles the Go examples

set -e

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$SCRIPT_DIR/.."
BUILD_DIR="$PROJECT_DIR/build"

echo "=== libzupt Go Examples Build Script ==="
echo ""

# Check for Go toolchain
if ! command -v go &> /dev/null; then
echo "ERROR: go not found."
echo " Install Go 1.21+ from: https://go.dev/dl/"
exit 1
fi

# Build libzupt shared library if needed
if [ ! -f "$BUILD_DIR/libzupt.so" ]; then
echo "Building libzupt (shared library)..."
cd "$PROJECT_DIR"
mkdir -p build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -DLIBZUPT_BUILD_TESTS=OFF -DLIBZUPT_BUILD_PYTHON=OFF >/dev/null 2>&1
make -j"$(nproc)" >/dev/null 2>&1
cd "$SCRIPT_DIR"
echo " libzupt built successfully."
echo ""
else
echo "libzupt shared library already built."
echo ""
fi

# Build the Go examples
echo "Building Go examples (cgo)..."
cd "$SCRIPT_DIR"
export CGO_ENABLED=1
export LD_LIBRARY_PATH="$BUILD_DIR:${LD_LIBRARY_PATH:-}"
go build -o zupt_example .

echo ""
echo "Build successful!"
echo ""
echo "To run an example:"
echo " LD_LIBRARY_PATH=../build ./zupt_example <basic|file|keygen|random|secure_buffer>"
echo ""
echo "Or run all examples at once (default):"
echo " LD_LIBRARY_PATH=../build ./zupt_example"
echo ""
82 changes: 82 additions & 0 deletions examples_go/example_basic.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package main

import (
"bytes"
"errors"
"fmt"
"strings"
)

func runExampleBasic() error {
sep := strings.Repeat("=", 60)
fmt.Println(sep)
fmt.Println("libzupt - Basic Encryption/Decryption Example")
fmt.Println(sep)
fmt.Println()

fmt.Println("1. Generating key pair...")
keygen := NewKeyGenerator()
keypair, err := keygen.GenerateKeyPair()
if err != nil {
return err
}
fmt.Printf(" Public key size: %d bytes\n", len(keypair.PublicKey))
fmt.Printf(" Secret key size: %d bytes\n", len(keypair.SecretKey))
fmt.Println()

encryptor, err := NewEncryptor(keypair.PublicKey)
if err != nil {
return err
}
decryptor, err := NewDecryptor(keypair.SecretKey)
if err != nil {
return err
}

message := []byte("Hello, Post-Quantum World! This is a secret message.")
fmt.Printf("2. Encrypting message: %s\n", message)
ciphertext, encHeader, err := encryptor.Encrypt(message)
if err != nil {
return err
}
fmt.Printf(" Ciphertext size: %d bytes\n", len(ciphertext))
fmt.Printf(" Header size: %d bytes\n", len(encHeader))
fmt.Println()

fmt.Println("3. Decrypting...")
decrypted, err := decryptor.Decrypt(ciphertext, encHeader)
if err != nil {
return err
}
fmt.Printf(" Decrypted: %s\n", decrypted)
fmt.Println()

if !bytes.Equal(decrypted, message) {
return errors.New("Decryption failed!")
}
fmt.Println("4. Verification: SUCCESS - Decrypted message matches original")
fmt.Println()

fmt.Println("5. Testing with wrong key...")
keygen2 := NewKeyGenerator()
keypair2, err := keygen2.GenerateKeyPair()
if err != nil {
return err
}
decryptorWrong, err := NewDecryptor(keypair2.SecretKey)
if err != nil {
return err
}

if _, err := decryptorWrong.Decrypt(ciphertext, encHeader); err != nil {
fmt.Printf(" Correctly rejected with error: %v\n", err)
} else {
fmt.Println(" ERROR: Should have failed!")
}
fmt.Println()

fmt.Println(sep)
fmt.Println("All examples passed!")
fmt.Println(sep)
return nil
}
92 changes: 92 additions & 0 deletions examples_go/example_file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package main

import (
"bytes"
"errors"
"fmt"
"os"
"path/filepath"
"strings"
)

func runExampleFile() error {
sep := strings.Repeat("=", 60)
fmt.Println(sep)
fmt.Println("libzupt - File Encryption/Decryption Example")
fmt.Println(sep)
fmt.Println()

fmt.Println("1. Generating key pair...")
keygen := NewKeyGenerator()
keypair, err := keygen.GenerateKeyPair()
if err != nil {
return err
}
fmt.Println(" Key pair generated")
fmt.Println()

encryptor, err := NewEncryptor(keypair.PublicKey)
if err != nil {
return err
}
decryptor, err := NewDecryptor(keypair.SecretKey)
if err != nil {
return err
}

tmpDir, err := os.MkdirTemp("", "zupt_example_")
if err != nil {
return err
}
defer os.RemoveAll(tmpDir)

testFile := filepath.Join(tmpDir, "example.txt")
content := "This is a secret text file.\n" +
"Line 2: Contains sensitive information.\n" +
"Line 3: End of file.\n"
original := []byte(content)
if err := os.WriteFile(testFile, original, 0o600); err != nil {
return err
}

fmt.Printf("2. Created test file: %s\n", testFile)
fmt.Printf(" Original content:\n%s", original)
fmt.Println()

fmt.Println("3. Encrypting file...")
ciphertext, encHeader, err := encryptor.EncryptFile(testFile)
if err != nil {
return err
}
fmt.Printf(" Ciphertext size: %d bytes\n", len(ciphertext))
fmt.Printf(" Header size: %d bytes\n", len(encHeader))
fmt.Println()

cipherFile := testFile + ".enc"
if err := os.WriteFile(cipherFile, ciphertext, 0o600); err != nil {
return err
}
fmt.Printf("4. Saved ciphertext to: %s\n", cipherFile)
fmt.Println()

fmt.Println("5. Decrypting file...")
decrypted, err := decryptor.DecryptFile(cipherFile, encHeader)
if err != nil {
return err
}
fmt.Printf(" Decrypted size: %d bytes\n", len(decrypted))
fmt.Printf(" Decrypted content:\n%s", decrypted)
fmt.Println()

if !bytes.Equal(decrypted, original) {
return errors.New("Decryption failed!")
}

fmt.Println("6. Cleaned up temporary files")
fmt.Println()

fmt.Println(sep)
fmt.Println("File encryption/decryption example passed!")
fmt.Println(sep)
return nil
}
Loading
Loading