Skip to content

Conversation

lla-dane
Copy link
Contributor

@lla-dane lla-dane commented Oct 1, 2025

Tracks: multiformats/multiaddr#181
WIP PR implementing garlic64 and garlic32 codec support in py-multiaddr.

Garlic64 go implementation:

var TranscoderGarlic64 = NewTranscoderFromFunctions(garlic64StB, garlic64BtS, garlic64Validate)

// i2p uses an alternate character set for base64 addresses. This returns an appropriate encoder.
var garlicBase64Encoding = base64.NewEncoding("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-~")

func garlic64StB(s string) ([]byte, error) {
	garlicHostBytes, err := garlicBase64Encoding.DecodeString(s)
	if err != nil {
		return nil, fmt.Errorf("failed to decode base64 i2p addr: %s %s", s, err)
	}

	if err := garlic64Validate(garlicHostBytes); err != nil {
		return nil, err
	}
	return garlicHostBytes, nil
}

func garlic64BtS(b []byte) (string, error) {
	if err := garlic64Validate(b); err != nil {
		return "", err
	}
	addr := garlicBase64Encoding.EncodeToString(b)
	return addr, nil
}

func garlic64Validate(b []byte) error {
	// A garlic64 address will always be greater than 386 bytes long when encoded.
	if len(b) < 386 {
		return fmt.Errorf("failed to validate garlic addr: %s not an i2p base64 address. len: %d", b, len(b))
	}
	return nil
}

Garlic-32 go implementation:

var TranscoderGarlic32 = NewTranscoderFromFunctions(garlic32StB, garlic32BtS, garlic32Validate)

var garlicBase32Encoding = base32.NewEncoding("abcdefghijklmnopqrstuvwxyz234567")

func garlic32StB(s string) ([]byte, error) {
	for len(s)%8 != 0 {
		s += "="
	}
	garlicHostBytes, err := garlicBase32Encoding.DecodeString(s)
	if err != nil {
		return nil, fmt.Errorf("failed to decode base32 garlic addr: %s, err: %v len: %v", s, err, len(s))
	}

	if err := garlic32Validate(garlicHostBytes); err != nil {
		return nil, err
	}
	return garlicHostBytes, nil
}

func garlic32BtS(b []byte) (string, error) {
	if err := garlic32Validate(b); err != nil {
		return "", err
	}
	return strings.TrimRight(garlicBase32Encoding.EncodeToString(b), "="), nil
}

func garlic32Validate(b []byte) error {
	// an i2p address with encrypted leaseset has len >= 35 bytes
	// all other addresses will always be exactly 32 bytes
	// https://geti2p.net/spec/b32encrypted
	if len(b) < 35 && len(b) != 32 {
		return fmt.Errorf("failed to validate garlic addr: %s not an i2p base32 address. len: %d", b, len(b))
	}
	return nil
}

- Added the general test-suite for garlic64 in test_protocols.py
@lla-dane lla-dane changed the title Add garlic64 and garlic32 encoding in py-multiaddr WIP: Add garlic64 and garlic32 encoding in py-multiaddr Oct 1, 2025
@lla-dane
Copy link
Contributor Author

lla-dane commented Oct 1, 2025

@acul71 @seetadev: Added the test-cases for garlic-multiaddrs in test_multiaddr.py file. Please take a look if this is enough for the test_suite of garlic64.

Now adding garlic32 in this PR only.

- Added the general test-suite in test_protocols.py
- Added the garlic32 addrs test cases in test_multiaddr.py
@lla-dane
Copy link
Contributor Author

lla-dane commented Oct 1, 2025

@seetadev @acul71: Added the garlic32 codec also. Please take a look if anything else remains for the test-suite or implementation of garlic32/64.

@lla-dane lla-dane changed the title WIP: Add garlic64 and garlic32 encoding in py-multiaddr Add garlic64 and garlic32 encoding in py-multiaddr Oct 1, 2025
@lla-dane
Copy link
Contributor Author

lla-dane commented Oct 2, 2025

Added the newsfragment file here also.

@seetadev
Copy link
Contributor

seetadev commented Oct 2, 2025

@lla-dane : Great, thank you so much Abhinav. Appreciate your efforts.

We plan to test this important addition in some of the py-libp2p examples (locally) before we do the final review + merge.

Copy link
Contributor

@acul71 acul71 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

APPROVED - Excellent Implementation

Both garlic64 and garlic32 protocols are fully implemented and working correctly.

Key Findings:

  • Garlic64: Perfect match with Go reference implementation
  • Garlic32: Perfect match with Go reference implementation
  • Protocol Registration: Correct codes (446, 447)
  • Test Coverage: Comprehensive (291 tests passing)
  • Go Compatibility: Exact algorithmic match

Implementation Quality:

  • Custom Base64 encoding with characters (garlic64)
  • Base32 encoding with proper validation (garlic32)
  • Excellent error handling and edge case coverage
  • Production-ready code with proper documentation

Ready for merge! 🚀

Copy link
Contributor

@acul71 acul71 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

APPROVED - Excellent Implementation

Both garlic64 and garlic32 protocols are fully implemented and working correctly.

Key Findings:

  • Garlic64: Perfect match with Go reference implementation
  • Garlic32: Perfect match with Go reference implementation
  • Protocol Registration: Correct codes (446, 447)
  • Test Coverage: Comprehensive (291 tests passing)
  • Go Compatibility: Exact algorithmic match

Implementation Quality:

  • Custom Base64 encoding with dash-tilde characters (garlic64)
  • Base32 encoding with proper validation (garlic32)
  • Excellent error handling and edge case coverage
  • Production-ready code with proper documentation

Ready for merge! 🚀

@acul71
Copy link
Contributor

acul71 commented Oct 4, 2025

📄 I2P Usage in libp2p Projects - Research Summary

Based on online research, here's what I found about libp2p projects that use I2P:

❌ Limited Real-World Usage

Current Status:

  • No official libp2p I2P support: The official libp2p documentation doesn't mention I2P integration
  • No active implementations: No major libp2p projects currently use I2P in production
  • Limited community adoption: Very few examples of libp2p + I2P integration

🔍 Specific Findings:

1. js-libp2p-i2p Project:

  • Repository: js-libp2p-i2p (mentioned in search results)
  • Status: Appears to be a JavaScript implementation for I2P transport
  • Purpose: Provides I2P transport for JavaScript libp2p applications

2. IPFS I2P Discussions:

  • GitHub Issue: ipfs/notes/issues/124 - Discussion about I2P integration with IPFS
  • Status: Discussion/exploration phase, not implemented
  • Focus: Enhancing IPFS with anonymous networking capabilities

3. Community Interest:

  • Proxy Protocol Discussion: libp2p/go-libp2p/issues/1065
  • Status: Exploring proxy support that could enable I2P integration
  • Timeline: Ongoing discussions, no concrete implementation

🎯 Why Limited Adoption?

Technical Challenges:

  • Complex Integration: I2P requires specialized routing and encryption
  • Performance Overhead: Garlic routing adds latency and complexity
  • Network Dependencies: Requires I2P network infrastructure
  • Limited Documentation: Few examples and guides available

Ecosystem Factors:

  • Tor Dominance: Tor is more widely adopted for anonymous networking
  • Development Focus: libp2p community focuses on core protocols
  • Use Case Specificity: I2P is niche compared to standard networking

🚀 Future Potential

Emerging Interest:

  • Privacy Enhancement: Growing demand for anonymous networking
  • Censorship Resistance: Need for bypassing network restrictions
  • Research Projects: Academic and experimental implementations
  • Community Discussions: Active exploration of I2P integration

📊 Current Reality

Production Usage:

  • Very Limited: No major libp2p projects use I2P currently
  • Experimental Only: Mostly research and proof-of-concept projects
  • Community Driven: Small, specialized implementations
  • Future Potential: Growing interest but no mainstream adoption

Summary

While the technical capability exists (as demonstrated by the garlic64/garlic32 protocol support we just reviewed), real-world libp2p projects using I2P are extremely rare. The integration is more theoretical than practical at this point.


This research was conducted to understand the current state of I2P adoption in libp2p projects and provide context for the garlic64/garlic32 protocol implementation.

- Combined garlic64/garlic32 tests with ipcidr tests
- Updated imports to include all required codecs
- Maintained all test functionality from both branches
@acul71
Copy link
Contributor

acul71 commented Oct 4, 2025

Hi @lla-dane thanks for your PR.
I've forgot to say that when a new protocol is added, some doc/examples about the usage is needed.
Take a look at https://multiaddr.readthedocs.io/en/latest/examples.html
files are in

/home/luca/Informatica/Learning/PNL_Launchpad_Curriculum/Libp2p/py-multiaddr/
├── docs/
│   ├── examples.rst                    # Main examples documentation
│   ├── index.rst                      # Main documentation index
│   └── _build/html/                   # Built HTML documentation
└── examples/
    ├── dns/
    │   └── dns_examples.py            # DNS resolution examples
    ├── dnsaddr/
    │   └── dnsaddr.py                 # DNSADDR examples
    ├── quic/
    │   └── simple_quic_usage.py     # QUIC protocol examples
    ├── thin_waist/
    │   └── thin_waist_example.py     # Thin waist address examples
    └── decapsulate/
        └── decapsulate_example.py    # Decapsulate examples

run make docs to preview

Same for ipcidr #95 (you can open a new PR)

@lla-dane
Copy link
Contributor Author

lla-dane commented Oct 7, 2025

Will do this in a coming PR.

@seetadev
Copy link
Contributor

seetadev commented Oct 8, 2025

@lla-dane : Great, thanks Abhinav. Doing a final review + merge. The PR looks great, overall. Appreciate your efforts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants