Files

108 lines
2.5 KiB
Go

package mpc
import (
"crypto/ecdsa"
"crypto/elliptic"
"fmt"
"math/big"
"golang.org/x/crypto/sha3"
)
func VerifyWithPubKey(pubKey []byte, data []byte, sig []byte) (bool, error) {
if len(sig) != 64 {
return false, fmt.Errorf("invalid signature length: expected 64, got %d", len(sig))
}
pk, err := parsePublicKey(pubKey)
if err != nil {
return false, err
}
r := new(big.Int).SetBytes(sig[:32])
s := new(big.Int).SetBytes(sig[32:])
hash := sha3.New256()
hash.Write(data)
digest := hash.Sum(nil)
return ecdsa.Verify(pk, digest, r, s), nil
}
func parsePublicKey(pubKey []byte) (*ecdsa.PublicKey, error) {
curve := elliptic.P256()
// Use secp256k1 parameters manually since Go stdlib doesn't include it
curve = secp256k1Curve()
switch len(pubKey) {
case 65: // uncompressed: 0x04 || x || y
if pubKey[0] != 0x04 {
return nil, fmt.Errorf("invalid uncompressed pubkey prefix: %x", pubKey[0])
}
x := new(big.Int).SetBytes(pubKey[1:33])
y := new(big.Int).SetBytes(pubKey[33:65])
return &ecdsa.PublicKey{Curve: curve, X: x, Y: y}, nil
case 33: // compressed: 0x02/0x03 || x
x, y := decompressPoint(curve, pubKey)
if x == nil {
return nil, fmt.Errorf("failed to decompress pubkey")
}
return &ecdsa.PublicKey{Curve: curve, X: x, Y: y}, nil
default:
return nil, fmt.Errorf("invalid pubkey length: %d", len(pubKey))
}
}
func secp256k1Curve() elliptic.Curve {
return &secp256k1Params
}
var secp256k1Params = elliptic.CurveParams{
Name: "secp256k1",
BitSize: 256,
P: fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F"),
N: fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"),
B: big.NewInt(7),
Gx: fromHex("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"),
Gy: fromHex("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"),
}
func fromHex(s string) *big.Int {
i, _ := new(big.Int).SetString(s, 16)
return i
}
func decompressPoint(curve elliptic.Curve, compressed []byte) (*big.Int, *big.Int) {
if len(compressed) != 33 {
return nil, nil
}
prefix := compressed[0]
if prefix != 0x02 && prefix != 0x03 {
return nil, nil
}
x := new(big.Int).SetBytes(compressed[1:])
p := curve.Params().P
// y² = x³ + 7 (for secp256k1)
x3 := new(big.Int).Mul(x, x)
x3.Mul(x3, x)
x3.Add(x3, big.NewInt(7))
x3.Mod(x3, p)
y := new(big.Int).ModSqrt(x3, p)
if y == nil {
return nil, nil
}
// Check parity
if (y.Bit(0) == 1) != (prefix == 0x03) {
y.Sub(p, y)
}
return x, y
}