Skip to main content

Signing

ALX supports optional cryptographic signatures over Block identities and protocol requests. Signing does not modify contentHash, blockHash, or declared parent relationships. Core Block creation, validation, and Graph verification do not require signatures.

Signing Model​

ALX supports two signing mechanisms:

MechanismSignsReplay controls
Block AttestationA specific blockHash, as durable evidenceNone: no nonce and no expiry
Protocol RequestAn application action, payload hash, chain, and domainNonce and expiry

Block Attestations​

A Block Attestation contains five fields:

FieldDescription
blockHashIdentity of the attested Block.
attesterPublic identifier of the signer.
algorithmSigning suite: ed25519, p256, or eip712.
timestampSigner-supplied Unix timestamp authenticated by the signature.
signatureCryptographic signature over the attestation digest.

Attestation Digest​

The signer signs a 32-byte digest of four attestation fields. \0 is one zero byte (0x00), and || is byte concatenation. Changing algorithm, attester, blockHash, or timestamp without a new signature invalidates the attestation.

attestationDigest = keccak256(
UTF8("ALX-ATTESTATION-V1\0") ||
canonicalize({ algorithm, attester, blockHash, timestamp })
)

Signing Suites​

Ed25519 and P-256 are the portable suites: every implementation that claims the signing extension produces and verifies both identically, as the signing extension vectors require. The JavaScript SDK also supports an eip712 suite. The eip712 suite is outside portable signing-extension conformance and has no cross-language vectors.

SuiteSigning rule
ed25519Pure Ed25519 as defined by RFC 8032, with the 32-byte digest as the message. Public keys are 32 bytes and signatures are 64 bytes, each encoded as lowercase 0x-prefixed hexadecimal.
p256ECDSA over NIST P-256, with the 32-byte digest supplied directly as the prehash. Public keys use the 65-byte uncompressed SEC1 encoding. Signatures use the 64-byte compact encoding of r followed by s, with a low s value.

Signed Blocks​

A SignedBlock envelope contains exactly one complete Block in block and at least one attestation in attestations. The envelope also accepts a singular attestation field for compatibility; new envelopes use attestations. The envelope is not a core Block and has no protocol identity: adding or removing attestations leaves contentHash and blockHash unchanged, and a core Block that carries an attestation field fails Block validation.

The JavaScript SDK provides:

  • createSignedBlock(content, parentHashes, signer, timestamp?) creates a Block and returns it in a SignedBlock envelope with one attestation.
  • addAttestation(signedBlock, signer) appends an attestation.
  • validateSignedBlock(signedBlock, verifier) recomputes the enclosed Block's hashes and verifies every attestation. A Map from algorithm to verifier verifies an envelope that mixes suites.

The Ed25519 suite loads the optional peer dependency @noble/ed25519 (npm install @noble/ed25519). The following script creates and verifies a signed Block:

import {createSignedBlock, validateSignedBlock, Ed25519Signer, Ed25519Verifier} from '@alx-protocol/sdk';

// A 32-byte Ed25519 private key; keep a real key in a key store.
const privateKey = crypto.getRandomValues(new Uint8Array(32));
const signer = new Ed25519Signer(privateKey);

const signed = await createSignedBlock({type: 'review', status: 'approved'}, [], signer);
const result = await validateSignedBlock(signed, new Ed25519Verifier());

console.log(signed.attestations[0].algorithm, result.ok); // ed25519 true

Protocol Requests​

The JavaScript SDK signs EIP-712 ProtocolRequest messages for application operations. A Protocol Request binds a signer to an action, payload hash, chain, domain, nonce, and expiry. verifySignedProtocolPayload() checks the signature, expected signer, replay window, and previously used nonces. Protocol Requests are not part of portable signing-extension conformance, and no conformance vectors cover them.

Protocol Request Fields​

The JavaScript package signs under the EIP-712 domain name ALXProtocol, version 1, exported as PROTOCOL_SIGNING_DOMAIN_NAME and PROTOCOL_SIGNING_DOMAIN_VERSION. Verification binds to the exact domain, chain ID, verifying contract, signer, nonce state, and expiry of the target deployment; changing any of them invalidates the signature. A ProtocolRequest message has seven fields:

FieldTypeMeaning
actoraddressThe signing account
noncestringA single-use value
expiryuint256The expiry time in Unix seconds; validateReplayWindow() reports expired once it passes
chainIduint256The chain the request targets
domainstringAn application string, distinct from the EIP-712 signing domain
actionstringThe requested operation
payloadHashbytes32The hash of the request payload

Signature Verification​

Block Attestation verification recomputes the attestation digest and verifies the signature with the suite named by algorithm. Protocol Request verification reconstructs the EIP-712 typed data and domain, recovers the signer, and evaluates the nonce and expiry.

Signature verification establishes that a key signed a specific message. Signature verification does not establish authorship, ownership, authorization, approval, legal identity, or content accuracy. Trust Boundary lists each claim.

When to Use Signing​

Use Block Attestations for durable cryptographic evidence associated with a Block identity. Use Protocol Requests for signed operations that need request-specific authentication, nonce handling, expiry, or action binding.