Files
zeekay 1362566d34 Merge github/main into the hardening branch
Both sides carried work. Ours is the security pass: the stableswap amp=0
and empty-pool halts, the wei-per-swap leak, uint256 truncation in math,
three verifiers that returned a verdict without verifying, the cgo/non-cgo
consensus split in cggmp21, and the starkfri soundness floor. Theirs is
the fhe parameter set, the mldsa crafted-length refusal, and the naming
sweep.

Resolved per hunk rather than by side. Where both fixed one defect the
better fix survives alone, never two guards for one bug.
2026-08-28 20:13:25 -07:00

99 lines
3.3 KiB
Go

// Package threshold demonstrates CGGMP21 and FROST threshold signature precompiles.
package threshold
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
"github.com/luxfi/geth/common"
"github.com/luxfi/precompile/cggmp21"
"github.com/luxfi/precompile/examples"
"github.com/luxfi/precompile/frost"
)
type AllThresholdDemos struct{}
func (d AllThresholdDemos) Name() string { return "threshold" }
func (d AllThresholdDemos) Run() []examples.Result {
var all []examples.Result
all = append(all, CGGMP21Demo()...)
all = append(all, FROSTDemo()...)
return all
}
// CGGMP21Demo exercises the CGGMP21 ECDSA threshold verify precompile (0x0800..03).
func CGGMP21Demo() []examples.Result {
// Generate a standard ECDSA key pair -- CGGMP21 verification is standard ECDSA
priv, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
pub := &priv.PublicKey
msg := []byte("Lux precompile CGGMP21 demo")
hash := sha256.Sum256(msg)
r, s, _ := ecdsa.Sign(rand.Reader, priv, hash[:])
// Uncompressed public key: 0x04 || x(32) || y(32) = 65 bytes
pubKey := make([]byte, 65)
pubKey[0] = 0x04
copy(pubKey[1:33], examples.PadLeft(pub.X.Bytes(), 32))
copy(pubKey[33:65], examples.PadLeft(pub.Y.Bytes(), 32))
// Signature: r(32) || s(32) || v(1) = 65 bytes
sig := make([]byte, 65)
copy(sig[0:32], examples.PadLeft(r.Bytes(), 32))
copy(sig[32:64], examples.PadLeft(s.Bytes(), 32))
sig[64] = 0 // v = 0
// Input: threshold(4) + totalSigners(4) + pubkey(65) + hash(32) + sig(65)
input := make([]byte, 0, 4+4+65+32+65)
input = append(input, examples.Uint32BE(2)...) // threshold = 2
input = append(input, examples.Uint32BE(3)...) // total signers = 3
input = append(input, pubKey...)
input = append(input, hash[:]...)
input = append(input, sig...)
return []examples.Result{
examples.CallPrecompileResult(
"CGGMP21 ECDSA Threshold Verify",
cggmp21.CGGMP21VerifyPrecompile,
cggmp21.ContractCGGMP21VerifyAddress,
input,
func(out []byte) bool { return examples.LastByte32IsOne(out) },
),
}
}
// FROSTDemo exercises the FROST EdDSA threshold verify precompile (0x0800..02).
func FROSTDemo() []examples.Result {
// FROST verification is Schnorr on Ed25519.
// We use the precompile's input format but with minimal viable data.
// Full FROST signing ceremony is complex -- test input parsing.
hash := sha256.Sum256([]byte("Lux precompile FROST demo"))
// Construct minimal input that will reach the verification path
input := make([]byte, 0, frost.MinInputSize)
input = append(input, examples.Uint32BE(2)...) // threshold
input = append(input, examples.Uint32BE(3)...) // total signers
input = append(input, make([]byte, 32)...) // pubkey (zeros = will fail verify)
input = append(input, hash[:]...) // message hash
input = append(input, make([]byte, 64)...) // signature (zeros)
r := examples.CallPrecompileResult(
"FROST Schnorr Threshold (parse)",
frost.FROSTVerifyPrecompile,
common.HexToAddress("0x0800000000000000000000000000000000000002"),
input,
func(out []byte) bool { return true }, // expect error or fail result
)
// FROST with zero pubkey will fail verification, not crash
if r.Error != nil || !examples.LastByte32IsOne(r.Output) {
r.Pass = true // expected: invalid sig gives non-1 result
r.Error = nil
}
return []examples.Result{r}
}