Skip to content

Comments

feat: implement peer-id spec#3

Merged
g11tech merged 5 commits intomainfrom
peer_id
Aug 23, 2025
Merged

feat: implement peer-id spec#3
g11tech merged 5 commits intomainfrom
peer_id

Conversation

@GrapeBaBa
Copy link
Member

This pull request introduces a Zig implementation of the libp2p peer-id specification, including the core data structures, build configuration, and continuous integration setup. The most significant changes are the addition of the main PeerId logic, Zig build system files, documentation, and a GitHub Actions workflow for CI. These changes lay the foundation for a reusable Zig package that can generate, parse, and manipulate peer IDs compatible with libp2p.

Core PeerId implementation:

  • Added src/id.zig with a full implementation of the PeerId struct, supporting creation from public keys, multihash, bytes, base58 strings, and CIDs, as well as conversion and equality checks. Includes comprehensive unit tests for all major functionality.

Build system and dependencies:

  • Added build.zig and build.zig.zon to configure Zig package building, dependency management (zmultiformats and gremlin), documentation generation, and unit testing. [1] [2]

Documentation:

  • Updated README.md with project overview, prerequisites, build/test instructions, documentation generation, and usage guide for integrating the package into other Zig projects.

Protobuf schema for keys:

  • Added src/keys.proto to define the protobuf schema for public and private keys, supporting multiple key types (RSA, Ed25519, Secp256k1, ECDSA, Curve25519).

Continuous Integration:

  • Added .github/workflows/ci.yml to set up GitHub Actions for Zig version management, caching, formatting checks, unit testing, and release builds on push and pull request events.

Signed-off-by: Chen Kai <281165273grape@gmail.com>
Signed-off-by: Chen Kai <281165273grape@gmail.com>
Signed-off-by: Chen Kai <281165273grape@gmail.com>
Signed-off-by: Chen Kai <281165273grape@gmail.com>
Signed-off-by: Chen Kai <281165273grape@gmail.com>
Copilot AI review requested due to automatic review settings August 17, 2025 09:41
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR implements a Zig library for libp2p peer-id specification, providing core data structures for creating, parsing, and manipulating peer IDs compatible with libp2p networks.

  • Core PeerId implementation with support for multihash, CID, and base58 encoding/decoding
  • Protobuf-based public/private key structures with serialization support
  • Complete build system with dependencies, testing, and documentation generation

Reviewed Changes

Copilot reviewed 8 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/root.zig Module entry point exposing key types and PeerId functionality
src/keys.proto.zig Generated protobuf bindings for public/private key structures
src/keys.proto Protobuf schema defining key types and message structures
src/id.zig Core PeerId implementation with conversion, validation, and utility methods
build.zig.zon Package configuration with dependencies and metadata
build.zig Build system configuration with protobuf generation and module setup
README.md Documentation with build instructions and usage examples
.github/workflows/ci.yml CI pipeline for testing, formatting, and building

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

var peer_id_bytes: [32]u8 = undefined;
std.crypto.random.bytes(&peer_id_bytes);

const mh = try Multihash(64).wrap(MULTIHASH_IDENTITY_CODE, &peer_id_bytes);
Copy link

Copilot AI Aug 17, 2025

Choose a reason for hiding this comment

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

The random() function uses MULTIHASH_IDENTITY_CODE with a 32-byte random array, but identity multihash should only be used for keys <= 42 bytes that are actual protobuf-encoded public keys. Random bytes are not valid protobuf-encoded keys and should use SHA2-256 instead.

Suggested change
const mh = try Multihash(64).wrap(MULTIHASH_IDENTITY_CODE, &peer_id_bytes);
var digest: [32]u8 = undefined;
std.crypto.hash.sha2.Sha256.hash(&peer_id_bytes, &digest, .{});
const mh = try Multihash(64).wrap(MULTIHASH_SHA256_CODE, &digest);

Copilot uses AI. Check for mistakes.
Copy link
Member

Choose a reason for hiding this comment

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

i think this makes sense what do you say @GrapeBaBa ?

Copy link
Member Author

Choose a reason for hiding this comment

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

No, i don't get this comment, how is it related to protobuf?

Copy link
Member

Choose a reason for hiding this comment

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

what it might be saying is that the randomness in the bytes might not be enough so we need to use sha as randomizer oracle. wdyt @gballet ?

Copy link
Member Author

@GrapeBaBa GrapeBaBa Aug 23, 2025

Choose a reason for hiding this comment

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

this is only for testing, port from other impl, should not use it in real case. I think it is used to create a fake/mock peerid using MULTIHASH_IDENTITY_CODE approach, the real case should always use a public key

if (std.mem.startsWith(u8, s, "Qm") or std.mem.startsWith(u8, s, "1")) {
return try Self.fromBase58(allocator, s);
}

Copy link

Copilot AI Aug 17, 2025

Choose a reason for hiding this comment

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

The string parsing logic is incomplete. Base58btc encoded multihashes can start with characters other than 'Qm' or '1' depending on the hash algorithm and length. This will incorrectly reject valid base58btc peer IDs.

Suggested change
// Try to decode as base58btc multihash first
const decoded_len = multibase.MultiBaseCodec.Base58Btc.decodedLen(s);
var decoded_bytes = allocator.alloc(u8, decoded_len) catch null;
if (decoded_bytes) |bytes| {
defer allocator.free(bytes);
if (multibase.MultiBaseCodec.Base58Impl.decodeBtc(bytes, s)) |actual_decoded| {
// Try to parse as multihash
if (Multihash(64).fromBytes(actual_decoded)) |mh| {
return PeerId{ .multihash = mh };
} else |err| {
// Not a valid multihash, fall through to CID parsing
}
} else |err| {
// Not valid base58btc, fall through to CID parsing
}
}
// Try to parse as CID

Copilot uses AI. Check for mistakes.
Copy link
Member

Choose a reason for hiding this comment

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

does this makes sense @GrapeBaBa ?

Copy link
Member Author

Choose a reason for hiding this comment

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

No, https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md#string-representation only two valid prefix, Qm for MULTIHASH_SHA256_CODE and 1 for MULTIHASH_IDENTITY_CODE

.optimize = optimize,
});
const peer_id_module = peer_id_dep.module("peer_id");
root_module.addImport("peer_id", peer_id_module);
Copy link

Copilot AI Aug 17, 2025

Choose a reason for hiding this comment

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

The module name 'peer_id' doesn't match the module name 'peer-id' defined in build.zig line 29. This will cause a module not found error.

Suggested change
root_module.addImport("peer_id", peer_id_module);
const peer_id_dep = b.dependency("peer-id", .{
.target = target,
.optimize = optimize,
});
const peer_id_module = peer_id_dep.module("peer-id");
root_module.addImport("peer-id", peer_id_module);

Copilot uses AI. Check for mistakes.
try testing.expect(!peer1.eql(&peer3));
}

// test "PeerId from public key to CID complete flow" {
Copy link
Member

Choose a reason for hiding this comment

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

we don't need this test? @GrapeBaBa

Copy link
Member Author

Choose a reason for hiding this comment

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

This test actually works, but it introduced ssl dep. I don't find a easy way to exclude this ssl dep when I import this lib to zig-libp2p. It will cause a conflict because another dep lsquic also depends on ssl. I think i can make this test work without ssl later, so commented out right now.

Copy link
Member

Choose a reason for hiding this comment

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

can't we just use/link the dependency in the test step, but merging the PR for now

Copy link
Member

@g11tech g11tech left a comment

Choose a reason for hiding this comment

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

awesome work @GrapeBaBa !

@g11tech g11tech merged commit b8f98a4 into main Aug 23, 2025
1 check passed
@g11tech g11tech deleted the peer_id branch August 23, 2025 08:08
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.

2 participants