Summary
When using an all-zero 32-byte key for both sealEvent() and unsealEvent(), the seal operation succeeds but unseal fails. This affects both Ed25519 private keys and symmetric channel keys.
Expected Behavior
Any 32-byte value should roundtrip successfully:
- Ed25519 internally clamps keys (masks bits, handles edge cases)
- Zero is a valid scalar on the curve (produces identity point as public key)
- Symmetric keys have no mathematical constraints
Actual Behavior
Counterexample from PBT:
{
channelKey: Uint8Array(32).fill(0), // all zeros
senderPrivateKey: Uint8Array(32).fill(0) // all zeros
}
Flow:
sealEvent(params) → Right({ data: Uint8Array, messageId: string }) ✅ succeeds
unsealEvent(data, channelKey) → Left(SealedEventError) ❌ fails
Reproduction
import { sealEvent, unsealEvent } from './sealed-event.fn.js'
import { SealedEventParams } from './sealed-event.schema.js'
const zeroKey = new Uint8Array(32) // all zeros
const params = new SealedEventParams({
content: 'test',
channelKey: zeroKey,
senderPrivateKey: zeroKey,
})
const sealed = sealEvent(params)
// sealed is Right
const unsealed = unsealEvent(sealed.right.data, zeroKey)
// unsealed is Left - decryption/signature verification fails
Code Path
sealEvent:
const ed25519Key = BctsEd25519PrivateKey.from(senderPrivateKey) // zero key
const derivedPublicKey = ed25519Key.publicKey().toData() // identity point
const privKey = SigningPrivateKey.newEd25519(ed25519Key)
const signed = envelope.sign(privKey) // succeeds
const salted = signed.addSalt()
const symmetricKey = SymmetricKey.fromData(channelKey) // zero key
const encrypted = salted.encrypt(symmetricKey) // succeeds
unsealEvent:
const encrypted = EnvelopeDecoder.tryFromCborData(data)
const symmetricKey = SymmetricKey.fromData(channelKey) // same zero key
const decrypted = encrypted.decrypt(symmetricKey) // likely fails here
const unwrapped = decrypted.unwrap() // or fails here on signature
Hypothesis
Either:
- SymmetricKey decryption with zero key fails (AES/ChaCha edge case)
- Signature verification fails because zero-derived public key (identity point) doesn't verify signatures correctly
The library may have assertions or checks that reject zero keys internally, even though they're mathematically valid.
Environment
- Library:
@bcts/components (Blockchain Commons Gordian Envelope)
- Ed25519 + X25519 + ECIES encryption
- Symmetric encryption (likely AES-256-GCM or ChaCha20-Poly1305)
Suggested Fix
Either:
- Accept zero keys and handle edge case correctly (preferred)
- Reject zero keys explicitly at
from() with clear error message (documented limitation)
Summary
When using an all-zero 32-byte key for both
sealEvent()andunsealEvent(), the seal operation succeeds but unseal fails. This affects both Ed25519 private keys and symmetric channel keys.Expected Behavior
Any 32-byte value should roundtrip successfully:
Actual Behavior
Counterexample from PBT:
Flow:
sealEvent(params)→Right({ data: Uint8Array, messageId: string })✅ succeedsunsealEvent(data, channelKey)→Left(SealedEventError)❌ failsReproduction
Code Path
sealEvent:
unsealEvent:
Hypothesis
Either:
The library may have assertions or checks that reject zero keys internally, even though they're mathematically valid.
Environment
@bcts/components(Blockchain Commons Gordian Envelope)Suggested Fix
Either:
from()with clear error message (documented limitation)