Files
zeekay ac01b821e8 pq: per-primitive flags, unified Op enum, package-level Active
Aligns the standalone luxfi/pq library to the same per-primitive model
the geth core/vm gate now uses. One way only: the same eight Forbid*
flags, the same sixteen Op constants, the same family errors.

Profile now has 8 fields (one per cryptographic primitive family)
instead of the prior 7 categorical flags. Op renamed from Op uint16
with mixed-case names to Op uint8 with namespace-qualified names
(OpEcrecover, OpBn256Pairing, etc.). Canonical encoding bumped to
version 2; new pinned hashes:

  strict:     9efdbf424085b0557866c22b0a4e0c48e2ed90c8c9e3f699d17a3e0783cb2128
  permissive: 256f4daa37543549e06bd101aab7f21a9b9dff46d322a9392e6b035cf4f0f638

API surface (the smallest possible):

  type Profile struct { 8 Forbid* fields }
  func Strict() / Permissive() *Profile
  func (p *Profile) Forbids(op Op) bool
  func (p *Profile) Encode() [16]byte
  func (p *Profile) Hash() [32]byte
  func DecodeProfile([16]byte) (*Profile, bool)

  type Op uint8 — 16 stable identifiers
  var Err*Forbidden — 8 family errors

  func SetActive(*Profile)        — package-level state, atomic
  func Active() *Profile
  func Refuse(Op) error           — reads Active
  func RefuseUnder(*Profile, Op)  — context-free

  const EnvVar = "QUASAR_STRICT_PQ"
  func FromEnv() *Profile

Dropped concepts: context binding (WithProfile/FromContext), MustRefuse,
Violation type, categorical Forbid* flags, Op uint16 with mixed cases.

20 unit tests; vet clean.
2026-05-11 16:29:11 -07:00

71 lines
1.8 KiB
Go

package pq
import "fmt"
// Op names a classical cryptographic primitive a profile may refuse.
// Op values are categorical at the precompile level: Byzantium and
// Istanbul variants of the same operation report the same Op.
//
// Stable identifiers. Append-only.
type Op uint8
// The complete set of recognised operations.
const (
OpUnknown Op = iota
// Asymmetric signatures.
OpEcrecover // ecrecover (0x01)
OpP256Verify // p256Verify (0x100, RIP-7212)
// Hash / compression.
OpSHA256 // 0x02
OpRIPEMD160 // 0x03
OpBlake2F // 0x09 (Blake2b compression — not BLAKE3)
// alt_bn128 (BN254).
OpBn256Add // 0x06
OpBn256ScalarMul // 0x07
OpBn256Pairing // 0x08
// BLS12-381 (EIP-2537).
OpBLS12381G1Add // 0x0b
OpBLS12381G1MSM // 0x0c
OpBLS12381G2Add // 0x0d
OpBLS12381G2MSM // 0x0e
OpBLS12381Pairing // 0x0f
OpBLS12381MapG1 // 0x10
OpBLS12381MapG2 // 0x11
// Polynomial commitment.
OpKZGPointEval // 0x0a (Cancun)
)
var opName = map[Op]string{
OpUnknown: "unknown",
OpEcrecover: "ecrecover",
OpP256Verify: "p256Verify",
OpSHA256: "sha256",
OpRIPEMD160: "ripemd160",
OpBlake2F: "blake2F",
OpBn256Add: "bn256Add",
OpBn256ScalarMul: "bn256ScalarMul",
OpBn256Pairing: "bn256Pairing",
OpBLS12381G1Add: "bls12381G1Add",
OpBLS12381G1MSM: "bls12381G1MSM",
OpBLS12381G2Add: "bls12381G2Add",
OpBLS12381G2MSM: "bls12381G2MSM",
OpBLS12381Pairing: "bls12381Pairing",
OpBLS12381MapG1: "bls12381MapG1",
OpBLS12381MapG2: "bls12381MapG2",
OpKZGPointEval: "kzgPointEvaluation",
}
// String returns the canonical name of an op. Unknown values render
// as "Op(0xNN)" so failures in unfamiliar callers stay identifiable.
func (o Op) String() string {
if s, ok := opName[o]; ok {
return s
}
return fmt.Sprintf("Op(0x%02x)", uint8(o))
}