From fca288035500e9f8f826180c47fdab0b197aa042 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 14 Nov 2025 14:39:45 +0000 Subject: [PATCH] feat: add 100% docstring coverage Adds comprehensive docstrings and runnable examples to all public APIs in the `crypt`, `enchantrix`, and `trix` packages. This change is intended to bring the project's documentation to a production-ready standard and to provide high-quality, verifiable examples for the official Go documentation website. --- pkg/crypt/crypt.go | 24 ++++- pkg/crypt/examples_test.go | 170 ++++++++++++++++++++++++++++++++ pkg/enchantrix/enchantrix.go | 3 + pkg/enchantrix/examples_test.go | 44 +++++++++ pkg/enchantrix/sigils.go | 7 ++ pkg/trix/examples_test.go | 93 +++++++++++++++++ pkg/trix/trix.go | 25 +++-- 7 files changed, 357 insertions(+), 9 deletions(-) create mode 100644 pkg/crypt/examples_test.go create mode 100644 pkg/enchantrix/examples_test.go create mode 100644 pkg/trix/examples_test.go diff --git a/pkg/crypt/crypt.go b/pkg/crypt/crypt.go index bf1e059..02dd66c 100644 --- a/pkg/crypt/crypt.go +++ b/pkg/crypt/crypt.go @@ -17,12 +17,14 @@ import ( ) // Service is the main struct for the crypt service. +// It provides methods for hashing, checksums, and encryption. type Service struct { rsa *rsa.Service pgp *pgp.Service } // NewService creates a new crypt Service and initialises its embedded services. +// It returns a new Service. func NewService() *Service { return &Service{ rsa: rsa.NewService(), @@ -34,11 +36,16 @@ func NewService() *Service { type HashType string const ( - LTHN HashType = "lthn" + // LTHN is a custom quasi-salted hashing algorithm. + LTHN HashType = "lthn" + // SHA512 is the SHA-512 hashing algorithm. SHA512 HashType = "sha512" + // SHA256 is the SHA-256 hashing algorithm. SHA256 HashType = "sha256" - SHA1 HashType = "sha1" - MD5 HashType = "md5" + // SHA1 is the SHA-1 hashing algorithm. + SHA1 HashType = "sha1" + // MD5 is the MD5 hashing algorithm. + MD5 HashType = "md5" ) // --- Hashing --- @@ -54,6 +61,7 @@ func (s *Service) IsHashAlgo(algo string) bool { } // Hash computes a hash of the payload using the specified algorithm. +// It returns the hash as a hex-encoded string. func (s *Service) Hash(lib HashType, payload string) string { switch lib { case LTHN: @@ -78,6 +86,7 @@ func (s *Service) Hash(lib HashType, payload string) string { // --- Checksums --- // Luhn validates a number using the Luhn algorithm. +// It is typically used to validate credit card numbers. func (s *Service) Luhn(payload string) bool { payload = strings.ReplaceAll(payload, " ", "") if len(payload) <= 1 { @@ -106,6 +115,7 @@ func (s *Service) Luhn(payload string) bool { } // Fletcher16 computes the Fletcher-16 checksum. +// It is a fast checksum algorithm that is more reliable than a simple sum. func (s *Service) Fletcher16(payload string) uint16 { data := []byte(payload) var sum1, sum2 uint16 @@ -117,6 +127,7 @@ func (s *Service) Fletcher16(payload string) uint16 { } // Fletcher32 computes the Fletcher-32 checksum. +// It provides better error detection than Fletcher-16. func (s *Service) Fletcher32(payload string) uint32 { data := []byte(payload) if len(data)%2 != 0 { @@ -133,6 +144,7 @@ func (s *Service) Fletcher32(payload string) uint32 { } // Fletcher64 computes the Fletcher-64 checksum. +// It provides the best error detection of the Fletcher algorithms. func (s *Service) Fletcher64(payload string) uint64 { data := []byte(payload) if len(data)%4 != 0 { @@ -186,36 +198,42 @@ func (s *Service) ensurePGP() { } // GeneratePGPKeyPair creates a new PGP key pair. +// It returns the public and private keys in PEM format. func (s *Service) GeneratePGPKeyPair(name, email, comment string) (publicKey, privateKey []byte, err error) { s.ensurePGP() return s.pgp.GenerateKeyPair(name, email, comment) } // EncryptPGP encrypts data with a public key. +// It returns the encrypted data. func (s *Service) EncryptPGP(publicKey, data []byte) ([]byte, error) { s.ensurePGP() return s.pgp.Encrypt(publicKey, data) } // DecryptPGP decrypts data with a private key. +// It returns the decrypted data. func (s *Service) DecryptPGP(privateKey, ciphertext []byte) ([]byte, error) { s.ensurePGP() return s.pgp.Decrypt(privateKey, ciphertext) } // SignPGP creates a detached signature for a message. +// It returns the signature. func (s *Service) SignPGP(privateKey, data []byte) ([]byte, error) { s.ensurePGP() return s.pgp.Sign(privateKey, data) } // VerifyPGP verifies a detached signature for a message. +// It returns an error if the signature is invalid. func (s *Service) VerifyPGP(publicKey, data, signature []byte) error { s.ensurePGP() return s.pgp.Verify(publicKey, data, signature) } // SymmetricallyEncryptPGP encrypts data with a passphrase. +// It returns the encrypted data. func (s *Service) SymmetricallyEncryptPGP(passphrase, data []byte) ([]byte, error) { s.ensurePGP() if len(passphrase) == 0 { diff --git a/pkg/crypt/examples_test.go b/pkg/crypt/examples_test.go new file mode 100644 index 0000000..75610b0 --- /dev/null +++ b/pkg/crypt/examples_test.go @@ -0,0 +1,170 @@ +package crypt_test + +import ( + "fmt" + "log" + + "github.com/Snider/Enchantrix/pkg/crypt" +) + +func ExampleService_Hash() { + cryptService := crypt.NewService() + payload := "Enchantrix" + + hashTypes := []crypt.HashType{ + crypt.LTHN, + crypt.MD5, + crypt.SHA1, + crypt.SHA256, + crypt.SHA512, + } + + fmt.Printf("Payload to hash: \"%s\"\n", payload) + for _, hashType := range hashTypes { + hash := cryptService.Hash(hashType, payload) + fmt.Printf(" - %-6s: %s\n", hashType, hash) + } + // Output: + // Payload to hash: "Enchantrix" + // - lthn : 331f24f86375846ac8d0d06cfb80cb2877e8900548a88d4ac8d39177cd854dab + // - md5 : 7c54903a10f058a93fd1f21ea802cb27 + // - sha1 : 399f776c4b97e558a2c4f319b223dd481c6d43f1 + // - sha256: 2ae653f74554abfdb2343013925f5184a0f05e4c2e0c3881448fc80caeb667c2 + // - sha512: 9638018a9720b5d83fba7f3899e4ba5ab78018781f9c600f0c0738ff8ccf1ea54e1c783ee8778542b70aa26283d87ce88784b2df5697322546d3b8029c4b6797 +} + +func ExampleService_Luhn() { + cryptService := crypt.NewService() + luhnPayloadGood := "49927398716" + luhnPayloadBad := "49927398717" + fmt.Printf("Luhn Checksum:\n") + fmt.Printf(" - Payload '%s' is valid: %v\n", luhnPayloadGood, cryptService.Luhn(luhnPayloadGood)) + fmt.Printf(" - Payload '%s' is valid: %v\n", luhnPayloadBad, cryptService.Luhn(luhnPayloadBad)) + // Output: + // Luhn Checksum: + // - Payload '49927398716' is valid: true + // - Payload '49927398717' is valid: false +} + +func ExampleService_Fletcher16() { + cryptService := crypt.NewService() + fletcherPayload := "abcde" + fmt.Printf("Fletcher16 Checksum (Payload: \"%s\"): %d\n", fletcherPayload, cryptService.Fletcher16(fletcherPayload)) + // Output: + // Fletcher16 Checksum (Payload: "abcde"): 51440 +} + +func ExampleService_Fletcher32() { + cryptService := crypt.NewService() + fletcherPayload := "abcde" + fmt.Printf("Fletcher32 Checksum (Payload: \"%s\"): %d\n", fletcherPayload, cryptService.Fletcher32(fletcherPayload)) + // Output: + // Fletcher32 Checksum (Payload: "abcde"): 4031760169 +} + +func ExampleService_Fletcher64() { + cryptService := crypt.NewService() + fletcherPayload := "abcde" + fmt.Printf("Fletcher64 Checksum (Payload: \"%s\"): %d\n", fletcherPayload, cryptService.Fletcher64(fletcherPayload)) + // Output: + // Fletcher64 Checksum (Payload: "abcde"): 14467467625952928454 +} + +func ExampleService_GeneratePGPKeyPair() { + cryptService := crypt.NewService() + publicKey, privateKey, err := cryptService.GeneratePGPKeyPair("test", "test@example.com", "test key") + if err != nil { + log.Fatalf("Failed to generate PGP key pair: %v", err) + } + fmt.Printf("PGP public key is not empty: %v\n", len(publicKey) > 0) + fmt.Printf("PGP private key is not empty: %v\n", len(privateKey) > 0) + // Output: + // PGP public key is not empty: true + // PGP private key is not empty: true +} + +func ExampleService_EncryptPGP() { + cryptService := crypt.NewService() + publicKey, _, err := cryptService.GeneratePGPKeyPair("test", "test@example.com", "test key") + if err != nil { + log.Fatalf("Failed to generate PGP key pair: %v", err) + } + message := []byte("This is a secret message for PGP.") + ciphertext, err := cryptService.EncryptPGP(publicKey, message) + if err != nil { + log.Fatalf("Failed to encrypt with PGP: %v", err) + } + fmt.Printf("PGP ciphertext is not empty: %v\n", len(ciphertext) > 0) + // Output: + // PGP ciphertext is not empty: true +} + +func ExampleService_DecryptPGP() { + cryptService := crypt.NewService() + publicKey, privateKey, err := cryptService.GeneratePGPKeyPair("test", "test@example.com", "test key") + if err != nil { + log.Fatalf("Failed to generate PGP key pair: %v", err) + } + message := []byte("This is a secret message for PGP.") + ciphertext, err := cryptService.EncryptPGP(publicKey, message) + if err != nil { + log.Fatalf("Failed to encrypt with PGP: %v", err) + } + decrypted, err := cryptService.DecryptPGP(privateKey, ciphertext) + if err != nil { + log.Fatalf("Failed to decrypt with PGP: %v", err) + } + fmt.Printf("Decrypted message: %s\n", decrypted) + // Output: + // Decrypted message: This is a secret message for PGP. +} + +func ExampleService_SignPGP() { + cryptService := crypt.NewService() + _, privateKey, err := cryptService.GeneratePGPKeyPair("test", "test@example.com", "test key") + if err != nil { + log.Fatalf("Failed to generate PGP key pair: %v", err) + } + message := []byte("This is a message to be signed.") + signature, err := cryptService.SignPGP(privateKey, message) + if err != nil { + log.Fatalf("Failed to sign with PGP: %v", err) + } + fmt.Printf("PGP signature is not empty: %v\n", len(signature) > 0) + // Output: + // PGP signature is not empty: true +} + +func ExampleService_VerifyPGP() { + cryptService := crypt.NewService() + publicKey, privateKey, err := cryptService.GeneratePGPKeyPair("test", "test@example.com", "test key") + if err != nil { + log.Fatalf("Failed to generate PGP key pair: %v", err) + } + message := []byte("This is a message to be signed.") + signature, err := cryptService.SignPGP(privateKey, message) + if err != nil { + log.Fatalf("Failed to sign with PGP: %v", err) + } + err = cryptService.VerifyPGP(publicKey, message, signature) + if err != nil { + fmt.Println("PGP signature verification failed.") + } else { + fmt.Println("PGP signature verified successfully.") + } + // Output: + // PGP signature verified successfully. +} + +func ExampleService_SymmetricallyEncryptPGP() { + cryptService := crypt.NewService() + passphrase := []byte("my secret passphrase") + message := []byte("This is a symmetric secret.") + ciphertext, err := cryptService.SymmetricallyEncryptPGP(passphrase, message) + if err != nil { + log.Fatalf("Failed to symmetrically encrypt with PGP: %v", err) + } + fmt.Printf("Symmetric PGP ciphertext is not empty: %v\n", len(ciphertext) > 0) + // Output: + // Symmetric PGP ciphertext is not empty: true +} diff --git a/pkg/enchantrix/enchantrix.go b/pkg/enchantrix/enchantrix.go index bb0f114..dd12743 100644 --- a/pkg/enchantrix/enchantrix.go +++ b/pkg/enchantrix/enchantrix.go @@ -1,8 +1,11 @@ package enchantrix // Sigil defines the interface for a data transformer. +// A Sigil is a reversible or irreversible transformation of a byte slice. type Sigil interface { + // In transforms the data. In(data []byte) ([]byte, error) + // Out reverses the transformation. Out(data []byte) ([]byte, error) } diff --git a/pkg/enchantrix/examples_test.go b/pkg/enchantrix/examples_test.go new file mode 100644 index 0000000..1863a12 --- /dev/null +++ b/pkg/enchantrix/examples_test.go @@ -0,0 +1,44 @@ +package enchantrix_test + +import ( + "fmt" + "log" + + "github.com/Snider/Enchantrix/pkg/enchantrix" +) + +func ExampleTransmute() { + data := []byte("Hello, World!") + sigils := []enchantrix.Sigil{ + &enchantrix.ReverseSigil{}, + &enchantrix.HexSigil{}, + } + transformed, err := enchantrix.Transmute(data, sigils) + if err != nil { + log.Fatalf("Transmute failed: %v", err) + } + fmt.Printf("Transformed data: %s\n", transformed) + // Output: + // Transformed data: 21646c726f57202c6f6c6c6548 +} + +func ExampleNewSigil() { + sigil, err := enchantrix.NewSigil("base64") + if err != nil { + log.Fatalf("Failed to create sigil: %v", err) + } + data := []byte("Hello, World!") + encoded, err := sigil.In(data) + if err != nil { + log.Fatalf("Sigil In failed: %v", err) + } + fmt.Printf("Encoded data: %s\n", encoded) + decoded, err := sigil.Out(encoded) + if err != nil { + log.Fatalf("Sigil Out failed: %v", err) + } + fmt.Printf("Decoded data: %s\n", decoded) + // Output: + // Encoded data: SGVsbG8sIFdvcmxkIQ== + // Decoded data: Hello, World! +} diff --git a/pkg/enchantrix/sigils.go b/pkg/enchantrix/sigils.go index d63c475..2fc3110 100644 --- a/pkg/enchantrix/sigils.go +++ b/pkg/enchantrix/sigils.go @@ -22,6 +22,7 @@ import ( ) // ReverseSigil is a Sigil that reverses the bytes of the payload. +// It is a symmetrical Sigil, meaning that the In and Out methods perform the same operation. type ReverseSigil struct{} // In reverses the bytes of the data. @@ -42,6 +43,7 @@ func (s *ReverseSigil) Out(data []byte) ([]byte, error) { } // HexSigil is a Sigil that encodes/decodes data to/from hexadecimal. +// The In method encodes the data, and the Out method decodes it. type HexSigil struct{} // In encodes the data to hexadecimal. @@ -65,6 +67,7 @@ func (s *HexSigil) Out(data []byte) ([]byte, error) { } // Base64Sigil is a Sigil that encodes/decodes data to/from base64. +// The In method encodes the data, and the Out method decodes it. type Base64Sigil struct{} // In encodes the data to base64. @@ -88,6 +91,7 @@ func (s *Base64Sigil) Out(data []byte) ([]byte, error) { } // GzipSigil is a Sigil that compresses/decompresses data using gzip. +// The In method compresses the data, and the Out method decompresses it. type GzipSigil struct { writer io.Writer } @@ -126,6 +130,7 @@ func (s *GzipSigil) Out(data []byte) ([]byte, error) { } // JSONSigil is a Sigil that compacts or indents JSON data. +// The Out method is a no-op. type JSONSigil struct{ Indent bool } // In compacts or indents the JSON data. @@ -147,6 +152,7 @@ func (s *JSONSigil) Out(data []byte) ([]byte, error) { } // HashSigil is a Sigil that hashes the data using a specified algorithm. +// The In method hashes the data, and the Out method is a no-op. type HashSigil struct { Hash crypto.Hash } @@ -211,6 +217,7 @@ func (s *HashSigil) Out(data []byte) ([]byte, error) { } // NewSigil is a factory function that returns a Sigil based on a string name. +// It is the primary way to create Sigil instances. func NewSigil(name string) (Sigil, error) { switch name { case "reverse": diff --git a/pkg/trix/examples_test.go b/pkg/trix/examples_test.go new file mode 100644 index 0000000..6c5a6a8 --- /dev/null +++ b/pkg/trix/examples_test.go @@ -0,0 +1,93 @@ +package trix_test + +import ( + "fmt" + "log" + + "github.com/Snider/Enchantrix/pkg/crypt" + "github.com/Snider/Enchantrix/pkg/trix" +) + +func ExampleEncode() { + t := &trix.Trix{ + Header: map[string]interface{}{"author": "Jules"}, + Payload: []byte("Hello, Trix!"), + } + encoded, err := trix.Encode(t, "TRIX", nil) + if err != nil { + log.Fatalf("Encode failed: %v", err) + } + fmt.Printf("Encoded data is not empty: %v\n", len(encoded) > 0) + // Output: + // Encoded data is not empty: true +} + +func ExampleDecode() { + t := &trix.Trix{ + Header: map[string]interface{}{"author": "Jules"}, + Payload: []byte("Hello, Trix!"), + } + encoded, err := trix.Encode(t, "TRIX", nil) + if err != nil { + log.Fatalf("Encode failed: %v", err) + } + decoded, err := trix.Decode(encoded, "TRIX", nil) + if err != nil { + log.Fatalf("Decode failed: %v", err) + } + fmt.Printf("Decoded payload: %s\n", decoded.Payload) + fmt.Printf("Decoded header: %v\n", decoded.Header) + // Output: + // Decoded payload: Hello, Trix! + // Decoded header: map[author:Jules] +} + +func ExampleTrix_Pack() { + t := &trix.Trix{ + Payload: []byte("secret message"), + InSigils: []string{"base64", "reverse"}, + } + err := t.Pack() + if err != nil { + log.Fatalf("Pack failed: %v", err) + } + fmt.Printf("Packed payload: %s\n", t.Payload) + // Output: + // Packed payload: =U2ZhN3cl1GI0VmcjV2c +} + +func ExampleTrix_Unpack() { + t := &trix.Trix{ + Payload: []byte("=U2ZhN3cl1GI0VmcjV2c"), + OutSigils: []string{"base64", "reverse"}, + } + err := t.Unpack() + if err != nil { + log.Fatalf("Unpack failed: %v", err) + } + fmt.Printf("Unpacked payload: %s\n", t.Payload) + // Output: + // Unpacked payload: secret message +} + +func ExampleTrix_Pack_checksum() { + t := &trix.Trix{ + Header: map[string]interface{}{}, + Payload: []byte("secret message"), + InSigils: []string{"base64", "reverse"}, + ChecksumAlgo: crypt.SHA256, + } + encoded, err := trix.Encode(t, "TRIX", nil) + if err != nil { + log.Fatalf("Encode failed: %v", err) + } + decoded, err := trix.Decode(encoded, "TRIX", nil) + if err != nil { + log.Fatalf("Decode failed: %v", err) + } + fmt.Printf("Decoded payload: %s\n", decoded.Payload) + fmt.Printf("Checksum verified: %v\n", decoded.Header["checksum"] != nil) + // Output: + // Decoded payload: secret message + // Checksum verified: true +} diff --git a/pkg/trix/trix.go b/pkg/trix/trix.go index df4c1a1..660ae21 100644 --- a/pkg/trix/trix.go +++ b/pkg/trix/trix.go @@ -13,20 +13,29 @@ import ( ) const ( - Version = 2 + // Version is the current version of the .trix file format. + Version = 2 + // MaxHeaderSize is the maximum allowed size for the header. MaxHeaderSize = 16 * 1024 * 1024 // 16 MB ) var ( + // ErrInvalidMagicNumber is returned when the magic number is incorrect. ErrInvalidMagicNumber = errors.New("trix: invalid magic number") - ErrInvalidVersion = errors.New("trix: invalid version") - ErrMagicNumberLength = errors.New("trix: magic number must be 4 bytes long") - ErrNilSigil = errors.New("trix: sigil cannot be nil") - ErrChecksumMismatch = errors.New("trix: checksum mismatch") - ErrHeaderTooLarge = errors.New("trix: header size exceeds maximum allowed") + // ErrInvalidVersion is returned when the version is incorrect. + ErrInvalidVersion = errors.New("trix: invalid version") + // ErrMagicNumberLength is returned when the magic number is not 4 bytes long. + ErrMagicNumberLength = errors.New("trix: magic number must be 4 bytes long") + // ErrNilSigil is returned when a sigil is nil. + ErrNilSigil = errors.New("trix: sigil cannot be nil") + // ErrChecksumMismatch is returned when the checksum does not match. + ErrChecksumMismatch = errors.New("trix: checksum mismatch") + // ErrHeaderTooLarge is returned when the header size exceeds the maximum allowed. + ErrHeaderTooLarge = errors.New("trix: header size exceeds maximum allowed") ) // Trix represents the structure of a .trix file. +// It contains a header, a payload, and optional sigils for data transformation. type Trix struct { Header map[string]interface{} Payload []byte @@ -36,6 +45,7 @@ type Trix struct { } // Encode serializes a Trix struct into the .trix binary format. +// It returns the encoded data as a byte slice. func Encode(trix *Trix, magicNumber string, w io.Writer) ([]byte, error) { if len(magicNumber) != 4 { return nil, ErrMagicNumberLength @@ -99,6 +109,7 @@ func Encode(trix *Trix, magicNumber string, w io.Writer) ([]byte, error) { } // Decode deserializes the .trix binary format into a Trix struct. +// It returns the decoded Trix struct. // Note: Sigils are not stored in the format and must be re-attached by the caller. func Decode(data []byte, magicNumber string, r io.Reader) (*Trix, error) { if len(magicNumber) != 4 { @@ -176,6 +187,7 @@ func Decode(data []byte, magicNumber string, r io.Reader) (*Trix, error) { } // Pack applies the In method of all attached sigils to the payload. +// It modifies the Trix struct in place. func (t *Trix) Pack() error { for _, sigilName := range t.InSigils { sigil, err := enchantrix.NewSigil(sigilName) @@ -191,6 +203,7 @@ func (t *Trix) Pack() error { } // Unpack applies the Out method of all sigils in reverse order. +// It modifies the Trix struct in place. func (t *Trix) Unpack() error { sigilNames := t.OutSigils if len(sigilNames) == 0 {