Overview
The Encoding module provides comprehensive functions for encoding and decoding elliptic curve points, keys, and signatures in various formats. It supports point compression, multiple serialization formats, and efficient conversion between different representations.
- Point compression and decompression
- Multiple serialization formats (binary, hex, base64)
- DER/PEM encoding for standards compliance
- Efficient memory usage and performance
- Constant-time operations for security
Point Compression
Point compression reduces the size of elliptic curve points by storing only the x-coordinate and a single bit indicating the y-coordinate's parity.
Compress Point
use forge_ec::{Point, encoding::compress_point};
fn compress_example() -> Result<(), Box> {
// Create a point (example coordinates)
let point = Point::new(
"0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798",
"0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"
)?;
// Compress the point (33 bytes instead of 65)
let compressed = compress_point(&point)?;
println!("Compressed point: {} bytes", compressed.len());
// Decompress back to original point
let decompressed = decompress_point(&compressed)?;
assert_eq!(point, decompressed);
Ok(())
}
Serialization
Serialize elliptic curve objects to binary formats for storage and transmission.
Binary Serialization
use forge_ec::{PrivateKey, PublicKey, encoding::{serialize, deserialize}};
fn serialization_example() -> Result<(), Box> {
// Generate a key pair
let private_key = PrivateKey::new();
let public_key = private_key.public_key();
// Serialize private key (32 bytes)
let private_bytes = serialize(&private_key)?;
println!("Private key: {} bytes", private_bytes.len());
// Serialize public key (compressed: 33 bytes, uncompressed: 65 bytes)
let public_bytes = serialize(&public_key)?;
println!("Public key: {} bytes", public_bytes.len());
// Deserialize back
let restored_private: PrivateKey = deserialize(&private_bytes)?;
let restored_public: PublicKey = deserialize(&public_bytes)?;
// Verify they match
assert_eq!(private_key.to_bytes(), restored_private.to_bytes());
assert_eq!(public_key.to_bytes(), restored_public.to_bytes());
Ok(())
}
Format Conversion
Convert between different encoding formats for interoperability.
Format Conversion Functions
use forge_ec::{PublicKey, encoding::{to_hex, from_hex, to_base64, from_base64}};
fn format_conversion_example() -> Result<(), Box> {
let public_key = PublicKey::from_hex(
"0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"
)?;
// Convert to different formats
let hex_string = to_hex(&public_key)?;
let base64_string = to_base64(&public_key)?;
println!("Hex: {}", hex_string);
println!("Base64: {}", base64_string);
// Convert back from formats
let from_hex_key: PublicKey = from_hex(&hex_string)?;
let from_base64_key: PublicKey = from_base64(&base64_string)?;
// Verify conversions are lossless
assert_eq!(public_key.to_bytes(), from_hex_key.to_bytes());
assert_eq!(public_key.to_bytes(), from_base64_key.to_bytes());
Ok(())
}
Base64 Encoding
Base64 encoding for text-safe representation of binary data.
use forge_ec::{Signature, encoding::base64};
fn base64_example() -> Result<(), Box> {
// Create a signature (example)
let signature = Signature::from_der(&signature_bytes)?;
// Encode to Base64
let base64_encoded = base64::encode(&signature)?;
println!("Base64 signature: {}", base64_encoded);
// Decode from Base64
let decoded_signature = base64::decode(&base64_encoded)?;
let restored_signature = Signature::from_bytes(&decoded_signature)?;
// Verify integrity
assert_eq!(signature.to_bytes(), restored_signature.to_bytes());
// URL-safe Base64 encoding
let url_safe_encoded = base64::encode_url_safe(&signature)?;
println!("URL-safe Base64: {}", url_safe_encoded);
Ok(())
}
Hex Encoding
Hexadecimal encoding for human-readable representation of binary data.
use forge_ec::{PrivateKey, encoding::hex};
fn hex_example() -> Result<(), Box> {
// Generate a private key
let private_key = PrivateKey::new();
// Encode to hex (lowercase)
let hex_lower = hex::encode(&private_key)?;
println!("Hex (lower): {}", hex_lower);
// Encode to hex (uppercase)
let hex_upper = hex::encode_upper(&private_key)?;
println!("Hex (upper): {}", hex_upper);
// Decode from hex (case-insensitive)
let decoded_key = hex::decode(&hex_lower)?;
let restored_key = PrivateKey::from_bytes(&decoded_key)?;
// Verify integrity
assert_eq!(private_key.to_bytes(), restored_key.to_bytes());
// With 0x prefix
let hex_with_prefix = hex::encode_with_prefix(&private_key)?;
println!("Hex with prefix: {}", hex_with_prefix);
Ok(())
}
DER Encoding
Distinguished Encoding Rules (DER) for standards-compliant encoding of cryptographic objects.
use forge_ec::{PublicKey, Signature, encoding::der};
fn der_example() -> Result<(), Box> {
let public_key = PublicKey::new();
// Encode public key to DER format
let der_encoded = der::encode_public_key(&public_key)?;
println!("DER encoded public key: {} bytes", der_encoded.len());
// Decode from DER
let decoded_key = der::decode_public_key(&der_encoded)?;
assert_eq!(public_key.to_bytes(), decoded_key.to_bytes());
// DER encoding for signatures
let signature = Signature::new(r_bytes, s_bytes)?;
let der_signature = der::encode_signature(&signature)?;
// This is compatible with OpenSSL and other standard libraries
println!("DER signature: {} bytes", der_signature.len());
Ok(())
}
Complete Examples
Comprehensive examples demonstrating real-world usage of the encoding module.
Key Storage and Retrieval
use forge_ec::{PrivateKey, PublicKey, encoding::{hex, base64}};
use std::fs;
fn key_storage_example() -> Result<(), Box> {
// Generate a key pair
let private_key = PrivateKey::new();
let public_key = private_key.public_key();
// Store private key securely (hex format)
let private_hex = hex::encode(&private_key)?;
fs::write("private_key.hex", private_hex)?;
// Store public key (base64 format for sharing)
let public_b64 = base64::encode(&public_key)?;
fs::write("public_key.b64", public_b64)?;
// Load keys back
let loaded_private_hex = fs::read_to_string("private_key.hex")?;
let loaded_private = PrivateKey::from_hex(&loaded_private_hex)?;
let loaded_public_b64 = fs::read_to_string("public_key.b64")?;
let loaded_public = PublicKey::from_base64(&loaded_public_b64)?;
// Verify keys match
assert_eq!(private_key.to_bytes(), loaded_private.to_bytes());
assert_eq!(public_key.to_bytes(), loaded_public.to_bytes());
println!("✅ Keys stored and loaded successfully");
Ok(())
}
Error Handling
Proper error handling for encoding and decoding operations.
use forge_ec::{PublicKey, encoding::{hex, EncodingError}};
fn error_handling_example() {
// Handle invalid hex input
match PublicKey::from_hex("invalid_hex_string") {
Ok(key) => println!("Key loaded: {:?}", key),
Err(EncodingError::InvalidHex(msg)) => {
eprintln!("Invalid hex format: {}", msg);
}
Err(EncodingError::InvalidLength { expected, actual }) => {
eprintln!("Invalid length: expected {}, got {}", expected, actual);
}
Err(EncodingError::InvalidPoint(msg)) => {
eprintln!("Invalid point: {}", msg);
}
Err(e) => eprintln!("Other error: {}", e),
}
// Handle invalid base64 input
match base64::decode("invalid_base64!@#") {
Ok(data) => println!("Decoded: {} bytes", data.len()),
Err(EncodingError::InvalidBase64(msg)) => {
eprintln!("Invalid base64: {}", msg);
}
Err(e) => eprintln!("Error: {}", e),
}
}
- Always validate input data before decoding
- Use constant-time comparison for sensitive data
- Clear sensitive data from memory after use
- Be aware of timing attacks in encoding operations