signature

package
v7.2.21 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 19, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Claude thinking signature validation.

Spec reference: SIGNATURE-CHANNEL-SPEC.md

Encoding detection (Spec section 3)

Claude signatures use base64 encoding in one or two layers. The raw string's first character determines the encoding depth. This is mathematically equivalent to the spec's "decode first, check byte" approach:

  • E prefix: single-layer, payload[0] == 0x12, first 6 bits = 000100, base64 index 4 = E.
  • R prefix: double-layer, inner[0] == E (0x45), first 6 bits = 010001, base64 index 17 = R.

Valid signatures can be normalized to R-form (double-layer base64) before sending to the Antigravity backend.

Protobuf structure (Spec sections 4.1 and 4.2) in strict mode only

After base64 decoding to raw bytes, the first byte must be 0x12:

Top-level protobuf
|- Field 2 (bytes): container                    -> extractClaudeBytesField(payload, 2)
|  |- Field 1 (bytes): channel block             -> extractClaudeBytesField(container, 1)
|  |  |- Field 1 (varint): channel_id [required] -> routing_class (11 | 12)
|  |  |- Field 2 (varint): infra [optional]      -> infrastructure_class (aws=1 | google=2)
|  |  |- Field 3 (varint): version=2             -> skipped
|  |  |- Field 5 (bytes): ECDSA sig              -> skipped, per Spec section 11
|  |  |- Field 6 (bytes): model_text [optional]  -> schema_features
|  |  `- Field 7 (varint): unknown [optional]    -> schema_features
|  |- Field 2 (bytes): nonce 12B                 -> skipped
|  |- Field 3 (bytes): session 12B               -> skipped
|  |- Field 4 (bytes): SHA-384 48B               -> skipped
|  `- Field 5 (bytes): metadata                  -> skipped, per Spec section 11
`- Field 3 (varint): =1                          -> skipped

Output dimensions (Spec section 8)

routing_class:        routing_class_11 | routing_class_12 | unknown
infrastructure_class: infra_default (absent) | infra_aws (1) | infra_google (2) | infra_unknown
schema_features:      compact_schema (len 70-72, no f6/f7) | extended_model_tagged_schema (f6 exists) | unknown
legacy_route_hint:    only for ch=11, legacy_default_group | legacy_aws_group | legacy_vertex_direct/proxy

Compatibility

Verified against all confirmed spec samples (Anthropic Max 20x, Azure, Vertex, Bedrock) and legacy ch=11 signatures. Both single-layer (E) and double-layer (R) encodings are supported. Historical cache-mode modelGroup# prefixes are stripped.

Gemini thought signature validation notes.

The Antigravity Gemini request translator can preserve provider-compatible Gemini thought signatures and uses the skip sentinel only for synthetic or incompatible model parts.

Gemini 3 and later models can return thoughtSignature on model content parts. Function-call parts are the strict case: when a model functionCall is replayed with a following functionResponse, Gemini validates that the original functionCall part still carries its provider-issued thoughtSignature. Text or other non-functionCall parts may also carry a signature; those should be preserved when replaying native Gemini history, but they are not the primary validation gate.

Synthetic history and migration from other model families are different. If a functionCall part was not produced by Gemini API, there is no real signature to preserve. Gemini documents two bypass sentinels for that case:

  • "skip_thought_signature_validator"
  • "context_engineering_is_the_way_to_go"

This repo currently emits "skip_thought_signature_validator" for non-Claude Antigravity Gemini model parts that contain functionCall, thought, or an existing thoughtSignature. That is a request-shape compatibility policy, not a proof that the replaced signature was malformed.

This validator is intentionally more conservative than a decrypting verifier. Claude has a known E/R base64 envelope and a protobuf tree in this package. Gemini thought signatures are opaque provider state here, so local validation checks only the transport-level protobuf envelope and leaves the wrapped provider payload uninterpreted.

Validation tiers:

  • Sentinel tier: accept the documented bypass sentinels only when the model functionCall is synthetic, migrated, or otherwise not traceable to a prior Gemini model response in the same conversation.
  • Opaque-shape tier: for real Gemini signatures, require a non-empty string, bounded length, successful standard base64 decoding, and a known protobuf envelope when the caller needs provider compatibility. Observed samples currently include Gemini 3.x field-2 -> field-1 payloads and Gemini 2.5 repeated field-1 payloads. Base64 UUID payloads are classified separately and should be replaced with the bypass sentinel rather than replayed.
  • Replay tier: real validation means preserving the exact model part that came from Gemini, including its thoughtSignature, id/name/function args, part index, and ordering relative to sibling parallel function calls.
  • Tool pairing tier: functionResponse parts must match the preceding functionCall id/name and must not be interleaved between parallel calls. The valid shape is all model functionCalls first, then their responses.
  • Compatibility tier: GPT-compatible Gemini traffic stores the same state under tool_calls[].extra_content.google.thought_signature. If that path is translated back to native Gemini, the value must stay attached to the same assistant tool call.

Important non-goals:

  • Do not treat a Gemini thoughtSignature as a Claude signature. Similar base64 prefixes are not provenance.
  • Do not attach a signature to user functionResponse/tool-result parts.
  • Do not log complete signatures during validation failures; log only field paths, lengths, and redacted prefixes.
  • Do not preserve client-provided signatures across model/provider/session boundaries unless the request pipeline can prove they came from the same Gemini conversation state.

Index

Constants

View Source
const (
	MaxGeminiThoughtSignatureLen = 32 * 1024 * 1024

	GeminiSkipThoughtSignatureValidator = "skip_thought_signature_validator"
	GeminiContextEngineeringBypass      = "context_engineering_is_the_way_to_go"
)
View Source
const MaxClaudeThinkingSignatureLen = 32 * 1024 * 1024
View Source
const MaxGPTReasoningSignatureLen = 32 * 1024 * 1024

Variables

This section is empty.

Functions

func CompatibleAntigravityClaudeThinkingSignature added in v7.1.30

func CompatibleAntigravityClaudeThinkingSignature(rawSignature string) (string, bool)

CompatibleAntigravityClaudeThinkingSignature returns the double-layer R-form required by Antigravity Claude replay. It only accepts signatures that are strictly identifiable as Claude, so Gemini E-prefixed envelopes cannot slip through the looser Antigravity bypass normalization path.

func CompatibleSignatureForProvider

func CompatibleSignatureForProvider(targetProvider SignatureProvider, rawSignature string) (string, bool)

CompatibleSignatureForProvider returns a replayable provider-native signature for targetProvider. It strips this repo's provider prefix and normalizes Claude signatures to the format expected by the target when possible.

func CompatibleSignatureForProviderBlock

func CompatibleSignatureForProviderBlock(targetProvider SignatureProvider, rawSignature string, blockKind SignatureBlockKind) (string, bool)

CompatibleSignatureForProviderBlock returns a replayable provider-native signature for targetProvider when the source block kind is known.

func GeminiReplaySignatureOrBypass added in v7.1.30

func GeminiReplaySignatureOrBypass(rawSignature string, blockKind SignatureBlockKind) string

GeminiReplaySignatureOrBypass returns a Gemini-replayable thoughtSignature. Compatible Gemini signatures are normalized and preserved. Missing, unknown, or cross-provider signatures are replaced with Gemini's bypass sentinel.

func HasClaudeThinkingSignaturePrefix

func HasClaudeThinkingSignaturePrefix(rawSignature string) bool

HasClaudeThinkingSignaturePrefix reports whether rawSignature has the Claude E/R signature prefix after stripping an optional cache prefix.

func HasDecodableClaudeThinkingSignature

func HasDecodableClaudeThinkingSignature(rawSignature string) bool

HasDecodableClaudeThinkingSignature reports whether rawSignature has the Claude E/R shape and its expected base64 layer(s) can be decoded.

func IsGeminiThoughtSignatureBypass

func IsGeminiThoughtSignatureBypass(rawSignature string) bool

IsGeminiThoughtSignatureBypass reports whether rawSignature is one of Gemini's documented bypass sentinels for synthetic or migrated function-call history.

func IsSignatureCompatibleWithProvider

func IsSignatureCompatibleWithProvider(targetProvider SignatureProvider, rawSignature string) bool

func IsValidClaudeThinkingSignature

func IsValidClaudeThinkingSignature(rawSignature string, opts ...ClaudeSignatureValidationOptions) bool

IsValidClaudeThinkingSignature returns whether rawSignature is a valid Claude thinking signature under the requested validation options.

func IsValidGPTReasoningSignature

func IsValidGPTReasoningSignature(rawSignature string) bool

func IsValidGeminiThoughtSignature

func IsValidGeminiThoughtSignature(rawSignature string, opts ...GeminiThoughtSignatureValidationOptions) bool

IsValidGeminiThoughtSignature returns whether rawSignature has a valid local Gemini thought-signature shape under opts.

func NormalizeClaudeProviderNativeThinkingSignature added in v7.1.30

func NormalizeClaudeProviderNativeThinkingSignature(rawSignature string, opts ...ClaudeSignatureValidationOptions) (string, error)

NormalizeClaudeProviderNativeThinkingSignature strips any cache prefix, validates the signature, and returns the single-layer E-form expected by Claude-native providers.

func NormalizeClaudeThinkingSignature

func NormalizeClaudeThinkingSignature(rawSignature string, opts ...ClaudeSignatureValidationOptions) (string, error)

NormalizeClaudeThinkingSignature strips any cache prefix, validates the signature, and returns the double-layer R-form expected by Antigravity bypass mode.

func SanitizeGeminiRequestThoughtSignatures added in v7.1.30

func SanitizeGeminiRequestThoughtSignatures(payload []byte, contentsPath string) []byte

SanitizeGeminiRequestThoughtSignatures applies Gemini replay policy to a Gemini-shaped request. Model-turn functionCall, thought, and signed parts keep compatible Gemini signatures and use the bypass sentinel otherwise. User-turn functionResponse parts must not carry thoughtSignature fields.

func SignaturePayloadWithoutProviderPrefix

func SignaturePayloadWithoutProviderPrefix(rawSignature string) string

SignaturePayloadWithoutProviderPrefix strips this repo's provider cache prefix when present. The returned string is the value that should be replayed to an upstream provider.

func StripInvalidClaudeThinkingBlocks

func StripInvalidClaudeThinkingBlocks(payload []byte, opts ...ClaudeSignatureValidationOptions) []byte

StripInvalidClaudeThinkingBlocks removes Claude thinking blocks whose signatures are empty or not valid Claude thinking signatures after stripping an optional cache prefix, unless the validation options allow an empty thinking placeholder.

func StripInvalidClaudeThinkingBlocksAndEmptyMessages

func StripInvalidClaudeThinkingBlocksAndEmptyMessages(payload []byte, opts ...ClaudeSignatureValidationOptions) []byte

StripInvalidClaudeThinkingBlocksAndEmptyMessages also removes messages whose content becomes empty after invalid thinking blocks are removed.

func ValidateClaudeThinkingSignatures

func ValidateClaudeThinkingSignatures(inputRawJSON []byte, opts ...ClaudeSignatureValidationOptions) error

ValidateClaudeThinkingSignatures validates every thinking block signature in a Claude messages payload.

func ValidateGeminiFunctionCallPairing

func ValidateGeminiFunctionCallPairing(inputRawJSON []byte) error

ValidateGeminiFunctionCallPairing validates the replay shape around Gemini functionCall and functionResponse parts. It checks id/name pairing and prevents response parts from being interleaved inside the same content as function calls. It allows a final pending functionCall group because callers may validate a freshly returned model step before tool outputs exist.

func ValidateGeminiThoughtSignatures

func ValidateGeminiThoughtSignatures(inputRawJSON []byte, opts ...GeminiThoughtSignatureValidationOptions) error

ValidateGeminiThoughtSignatures validates thoughtSignature fields in a Gemini native payload. Function-call parts must have a valid signature. Other parts are optional, but if a thoughtSignature field is present it must be valid.

Types

type ClaudeMessagesSignatureSanitizeOptions

type ClaudeMessagesSignatureSanitizeOptions struct {
	TargetProvider                SignatureProvider
	TargetModel                   string
	DropEmptyMessages             bool
	DropToolSignatures            bool
	DropEmptyThinkingPlaceholders bool
}

type ClaudeSignatureTree

type ClaudeSignatureTree struct {
	EncodingLayers      int
	ChannelID           uint64
	Field2              *uint64
	RoutingClass        string
	InfrastructureClass string
	SchemaFeatures      string
	ModelText           string
	LegacyRouteHint     string
	HasField7           bool
}

ClaudeSignatureTree describes the protobuf fields currently used for Claude thinking signature routing.

func InspectClaudeDoubleLayerSignature

func InspectClaudeDoubleLayerSignature(sig string) (*ClaudeSignatureTree, error)

InspectClaudeDoubleLayerSignature decodes and inspects a double-layer Claude thinking signature.

func InspectClaudeSignaturePayload

func InspectClaudeSignaturePayload(payload []byte, encodingLayers int) (*ClaudeSignatureTree, error)

InspectClaudeSignaturePayload inspects the decoded Claude thinking signature protobuf payload.

func InspectClaudeSingleLayerSignature

func InspectClaudeSingleLayerSignature(sig string) (*ClaudeSignatureTree, error)

InspectClaudeSingleLayerSignature decodes and inspects a single-layer Claude thinking signature.

type ClaudeSignatureValidationOptions

type ClaudeSignatureValidationOptions struct {
	// PrefixOnly only checks for an optional cache prefix followed by an E/R
	// Claude signature prefix. Use it to preserve legacy shallow cleanup.
	PrefixOnly bool
	// Base64Only checks the optional cache prefix, E/R Claude signature prefix,
	// and base64 layers without validating the decoded Claude marker or protobuf
	// tree. Use it for conservative request cleanup.
	Base64Only bool
	// AllowEmptySignatureWithEmptyText preserves empty thinking placeholders with
	// no signature and no thinking/text payload during strip operations.
	AllowEmptySignatureWithEmptyText bool
	Strict                           bool
}

ClaudeSignatureValidationOptions controls how far Claude thinking signatures are inspected. The base validation always checks the cache prefix, base64 layers, and decoded 0x12 Claude payload marker. Strict mode additionally verifies the known protobuf tree used by Claude thinking signatures.

type GPTReasoningSignatureInfo

type GPTReasoningSignatureInfo struct {
	DecodedLen    int
	CiphertextLen int
}

func InspectGPTReasoningSignature

func InspectGPTReasoningSignature(rawSignature string) (*GPTReasoningSignatureInfo, error)

InspectGPTReasoningSignature validates the Fernet-like outer format used by GPT/Codex reasoning encrypted_content. This is only a transport-shape check; it does not prove decryptability.

type GeminiThoughtSignatureEnvelope

type GeminiThoughtSignatureEnvelope string
const (
	GeminiThoughtSignatureEnvelopeUnknown        GeminiThoughtSignatureEnvelope = "unknown"
	GeminiThoughtSignatureEnvelopeProtobufField1 GeminiThoughtSignatureEnvelope = "protobuf_field_1"
	GeminiThoughtSignatureEnvelopeProtobufField2 GeminiThoughtSignatureEnvelope = "protobuf_field_2"
	GeminiThoughtSignatureEnvelopeASCIIUUID      GeminiThoughtSignatureEnvelope = "ascii_uuid"
)

type GeminiThoughtSignatureInfo

type GeminiThoughtSignatureInfo struct {
	IsBypassSentinel  bool
	BypassSentinel    string
	DecodedLen        int
	FirstByte         byte
	HasObservedMarker bool
	KnownEnvelope     bool
	Envelope          GeminiThoughtSignatureEnvelope
	RecordCount       int
	OpaquePayloadLen  int
}

GeminiThoughtSignatureInfo describes the locally inspectable properties of an opaque Gemini thought signature.

func InspectGeminiThoughtSignature

func InspectGeminiThoughtSignature(rawSignature string, opts ...GeminiThoughtSignatureValidationOptions) (*GeminiThoughtSignatureInfo, error)

InspectGeminiThoughtSignature validates and inspects the local transport shape of a Gemini thought signature. It intentionally treats provider-issued signatures as opaque base64 payloads.

type GeminiThoughtSignatureValidationOptions

type GeminiThoughtSignatureValidationOptions struct {
	// AllowBypassSentinel accepts Gemini's documented synthetic-history bypass
	// sentinels. Keep this false when validating provider-issued signatures.
	AllowBypassSentinel bool
	// RequireKnownEnvelope requires the decoded payload to match one of the
	// protobuf envelopes observed in Gemini samples. This rejects opaque base64
	// values such as base64 UUIDs.
	RequireKnownEnvelope bool
	// RequireObservedMarker requires the decoded payload to start with 0x12.
	// Current Gemini 3.x samples show this marker, but Gemini 2.5 samples use a
	// different protobuf prefix, so this should be used only for narrow Gemini 3
	// experiments.
	RequireObservedMarker bool
}

GeminiThoughtSignatureValidationOptions controls how much local validation is applied to Gemini thought signatures. This validation checks only the opaque transport envelope; it does not prove that a signature came from Gemini or can be decrypted by Gemini.

type SignatureBlockKind

type SignatureBlockKind string
const (
	SignatureBlockKindUnknown            SignatureBlockKind = "unknown"
	SignatureBlockKindClaudeThinking     SignatureBlockKind = "claude_thinking"
	SignatureBlockKindGeminiModelPart    SignatureBlockKind = "gemini_model_part"
	SignatureBlockKindGeminiFunctionCall SignatureBlockKind = "gemini_function_call"
	SignatureBlockKindGPTReasoning       SignatureBlockKind = "gpt_reasoning"
)

type SignatureCompatibilityAction

type SignatureCompatibilityAction string
const (
	SignatureActionPreserve                SignatureCompatibilityAction = "preserve"
	SignatureActionDropBlock               SignatureCompatibilityAction = "drop_block"
	SignatureActionDropSignature           SignatureCompatibilityAction = "drop_signature"
	SignatureActionReplaceWithGeminiBypass SignatureCompatibilityAction = "replace_with_gemini_bypass"
	SignatureActionNoCompatibleReplacement SignatureCompatibilityAction = "no_compatible_replacement"
)

type SignatureCompatibilityDecision

type SignatureCompatibilityDecision struct {
	TargetProvider       SignatureProvider
	DetectedProvider     SignatureProvider
	BlockKind            SignatureBlockKind
	Compatible           bool
	Action               SignatureCompatibilityAction
	ReplacementSignature string
	NormalizedSignature  string
	Reason               string
}

func DecideSignatureCompatibility

func DecideSignatureCompatibility(targetProvider SignatureProvider, rawSignature string, blockKind SignatureBlockKind) SignatureCompatibilityDecision

DecideSignatureCompatibility returns the safe handling policy for replaying a signed block into targetProvider.

type SignatureProvider

type SignatureProvider string
const (
	SignatureProviderUnknown      SignatureProvider = "unknown"
	SignatureProviderClaude       SignatureProvider = "claude"
	SignatureProviderGemini       SignatureProvider = "gemini"
	SignatureProviderGeminiBypass SignatureProvider = "gemini_bypass"
	SignatureProviderGPT          SignatureProvider = "gpt"
)

func DetectSignatureProvider

func DetectSignatureProvider(rawSignature string) SignatureProvider

DetectSignatureProvider classifies the provider family that can replay rawSignature. It intentionally uses Claude strict validation before Gemini detection because Gemini 3 signatures also decode from an E-prefixed base64 string and can look Claude-like under shallow prefix checks.

func DetectSignatureProviderForBlock

func DetectSignatureProviderForBlock(rawSignature string, blockKind SignatureBlockKind) SignatureProvider

DetectSignatureProviderForBlock classifies rawSignature with block-kind context. UUID-shaped payloads are deliberately not classified as replay-safe provider signatures; callers targeting Gemini should replace them with the bypass sentinel.

func SignatureProviderFromCachePrefix

func SignatureProviderFromCachePrefix(prefix string) SignatureProvider

SignatureProviderFromCachePrefix maps this repo's explicit provider-prefix envelope to a provider family. This is intentionally stricter than SignatureProviderFromModelName so arbitrary model names such as "claude-cache#..." cannot be mistaken for trusted provider provenance.

func SignatureProviderFromModelName

func SignatureProviderFromModelName(modelName string) SignatureProvider

SignatureProviderFromModelName maps common model names to the provider family whose signed history can be safely replayed for that model.

func SplitSignatureProviderPrefix

func SplitSignatureProviderPrefix(rawSignature string) (SignatureProvider, string, bool)

type SignatureSanitizeReport

type SignatureSanitizeReport struct {
	TargetProvider     SignatureProvider
	Preserved          int
	DroppedBlocks      int
	DroppedSignatures  int
	ReplacedSignatures int
	Decisions          []SignatureCompatibilityDecision
}

func SanitizeClaudeMessagesForClaudeUpstream added in v7.1.30

func SanitizeClaudeMessagesForClaudeUpstream(payload []byte, targetModel string) ([]byte, SignatureSanitizeReport)

SanitizeClaudeMessagesForClaudeUpstream prepares a Claude /v1/messages body for native Claude upstreams. Invalid thinking blocks are dropped, valid thinking signatures are normalized to Claude provider-native E-form, and tool_use blocks keep only their tool-call payload.

func SanitizeClaudeMessagesSignaturesForModel

func SanitizeClaudeMessagesSignaturesForModel(payload []byte, targetModel string) ([]byte, SignatureSanitizeReport)

SanitizeClaudeMessagesSignaturesForModel removes or preserves Claude /v1/messages signed history according to the provider family implied by targetModel.

func SanitizeClaudeMessagesSignaturesForTarget

func SanitizeClaudeMessagesSignaturesForTarget(payload []byte, opts ClaudeMessagesSignatureSanitizeOptions) ([]byte, SignatureSanitizeReport)

SanitizeClaudeMessagesSignaturesForTarget applies provider-aware signature compatibility rules to Claude /v1/messages history. Compatible thinking signatures are preserved. Incompatible thinking blocks are removed so a user can continue a conversation after switching between Claude, GPT/Codex, and Gemini models.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL