Skip to content

crypto,consensus: add entity type to verifier and register assembler certs - #1241

Open
HagarMeir wants to merge 4 commits into
hyperledger:mainfrom
HagarMeir:crypto-verifier-assembler-entity
Open

HagarMeir wants to merge 4 commits into
hyperledger:mainfrom
HagarMeir:crypto-verifier-assembler-entity

Conversation

@HagarMeir

Copy link
Copy Markdown
Contributor

What

Adds an EntityType dimension to the crypto verifier and registers the assembler signing certificates (pinned in shared config by #1216) in the consenter's verifier, so a follow-up can verify assembler→consensus messages.

This lays the verifier groundwork for the signature verification of AssemblerDecisionReport that was deliberately deferred in #1214 (the signing scheme was not yet defined there; verifyCE only rejected unsigned reports).

Why

The verifier map was keyed by (shard, party), which cannot represent assemblers: unlike batchers they are not part of a shard, and unlike consenters they had no reserved key. An EntityType (batcher/consenter/assembler) is added to the key so non-sharded entities can be told apart even when they share the reserved ShardIDConsensus value — {EntityConsenter, ShardIDConsensus, party} and {EntityAssembler, ShardIDConsensus, party} are distinct.

Changes

  • node/crypto/verifier.go — new EntityType uint8 enum (EntityBatcher/EntityConsenter/EntityAssembler) with String(); ShardPartyKey → VerifierKey gains an Entity field; VerifySignature, AddPublicKeyToVerifier, and ParsePublicKeyFromPEM take the typed entity (the old entityType string was only used for logs).
  • Config plumbing — node/config: AssemblerInfo.PublicKey and ConsenterNodeConfig.Assemblers; config: ExtractAssemblers populates PublicKey from AssemblerConfig.SignCert, and ExtractConsenterConfig sets Assemblers.
  • node/consensus/consensus_builder.go — buildVerifier takes the assemblers and registers them under EntityAssembler at ShardIDConsensus.
  • Interface ripple — SigVerifier.VerifySignature in node/consensus and node/batcher take the entity (consenter sig → Consenter; BAF/complaint/batch primary sig → Batcher); counterfeiter mock regenerated; test/utils updated.

Deliberately deferred

Testing

  • New TestVerifySignatureEntity (TDD): an assembler key verifies its signature, a wrong-entity lookup at the same shard/party does not collide.
  • Green: node/crypto, config, node/config, node/batcher (-race), and the node/consensus/consensus_test.go suite (-race).
  • go build ./..., go vet ./..., goimports, gofumpt clean.

Refs #1214

🤖 Generated with Claude Code

@HagarMeir
HagarMeir force-pushed the crypto-verifier-assembler-entity branch from 8ddb556 to 1b7eb4f Compare September 22, 2026 11:12
@tock-ibm

Copy link
Copy Markdown
Contributor

Automated code review (/code-review)

Ran a /code-review pass over this PR. No correctness bugs found — go build/go vet clean, the crypto/config/node-config tests pass, and every register/verify entity pairing is consistent (batcher↔EntityBatcher, consenter↔EntityConsenter; block metadata is verified as EntityConsenter, which is correct). The items below are robustness/design observations for reviewer consideration, not blockers.

1. ExtractAssemblers widens the panic surface — config/config.go:652 (low severity)

Putting GetPublicKeyFromCertificate inside the shared ExtractAssemblers makes address-only / TLS-only callers depend on the assembler SignCert:

  • ExtractAssemblerAddresses (config/config.go:1065) — block-puller/sync path, uses only Endpoint/TLSCACerts
  • extractClientConfigFromAssemblerConfig (node/assembler/utils.go:58) — TLS-CA setup, uses only TLSCACerts

If a party has a non-nil AssemblerConfig with an empty/malformed SignCert PEM (partial/incrementally-authored config, or a reconfig that adds a party before its assembler cert is set), GetPublicKeyFromCertificate panics (pem.Decode(nil) → block == nil). Note this mirrors the existing ExtractConsenters behavior for the consenter SignCert, and #1216 pins these certs into shared config, so a valid config block should always carry one — this bites only on malformed/partial config.

2. Assembler verifier plumbing is currently inert — node/consensus/consensus_builder.go:245 (by design)

No production code calls VerifySignature(EntityAssembler, ...) yet. Per the PR description this is deliberate: it is the verifier groundwork for the AssemblerDecisionReport signature verification deferred in #1214, landing in a follow-up. Flagging only so reviewers are aware the EntityAssembler registration and the ConsenterNodeConfig.Assemblers plumbing have no consumer within this PR.

3. EntityType zero value silently means "batcher" — node/crypto/verifier.go:27 (footgun)

iota makes EntityBatcher = 0, so a zero-valued EntityType (e.g. a VerifierKey{} constructed without setting Entity) resolves against batcher keys rather than surfacing a clear "key does not exist" error. All current call sites pass an explicit entity, so this is a latent footgun rather than a live bug. Reserving EntityUnknown = 0 (shifting the real entities to iota + 1) would make accidental zero values fail loudly and makes the String() default branch reachable.

Assisted by Claude Code.

@HagarMeir
HagarMeir force-pushed the crypto-verifier-assembler-entity branch 4 times, most recently from e2fa3ed to a8d2415 Compare September 24, 2026 09:47
Comment thread node/crypto/verifier.go Outdated
type ShardPartyKey struct {
Shard types.ShardID
Party types.PartyID
// EntityType identifies the kind of node a public key belongs to. It is part of the verifier key

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@DorKatzelnick is using similar data structure here: #1225

Lets put Role (=EntityType) and Entity (Role + party + shard) somewhere central, possibly i common/types?

Comment thread node/crypto/verifier.go Outdated
Comment on lines 22 to 50
// so that entities which are not part of a shard (consenters and assemblers) can be told apart
// even though they share the reserved ShardIDConsensus value.
type EntityType uint8

const (
EntityUnknown EntityType = iota
EntityBatcher
EntityConsenter
EntityAssembler
)

func (e EntityType) String() string {
switch e {
case EntityBatcher:
return "batcher"
case EntityConsenter:
return "consenter"
case EntityAssembler:
return "assembler"
default:
return fmt.Sprintf("unknown entity (%d)", uint8(e))
}
}

type VerifierKey struct {
Entity EntityType
Shard types.ShardID
Party types.PartyID
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Lets move all of this to somewhere common, and include the router as well.

HagarMeir and others added 4 commits September 28, 2026 11:30
…certs

The verifier map was keyed by (shard, party), which cannot represent
assemblers: unlike batchers they are not part of a shard, and unlike
consenters they had no reserved key. Commit hyperledger#1216 pinned the assembler's
signing certificate in the shared config, so the consenter can now hold
the assembler public keys.

Add an EntityType (batcher/consenter/assembler) to the verifier key so
non-sharded entities can be told apart even when they share the reserved
ShardIDConsensus value. VerifySignature and the key builders now take the
entity explicitly; consenters and batchers keep their existing lookups.

Plumb the assembler signing certs through: AssemblerInfo gains a public
key, ConsenterNodeConfig gains the assemblers list, and the consenter's
buildVerifier registers each assembler under EntityAssembler.

This only registers the assembler keys and makes them addressable. The
actual verification of assembler->consensus messages (the signing scheme
deferred in hyperledger#1214) lands in a follow-up.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Hagar Meir <hagar.meir@ibm.com>
Signed-off-by: Hagar Meir <hagar.meir@ibm.com>
Signed-off-by: Hagar Meir <hagar.meir@ibm.com>
Replace the crypto-local EntityType and VerifierKey with the shared
types.NodeRole and types.NodeIdentity so the verifier keys on the same
node-identity abstraction used elsewhere. Consenters and assemblers are
still keyed under ShardIDConsensus and disambiguated by role.

Regenerate the batcher SigVerifier mock and update call sites in
consensus, batcher, and test/utils accordingly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Hagar Meir <hagar.meir@ibm.com>
@HagarMeir
HagarMeir force-pushed the crypto-verifier-assembler-entity branch from 09f20e1 to d6bc22a Compare September 28, 2026 09:06
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