diff --git a/node/pkg/tss/implementation.go b/node/pkg/tss/implementation.go index 3b8307cee3..68d78aaf67 100644 --- a/node/pkg/tss/implementation.go +++ b/node/pkg/tss/implementation.go @@ -76,6 +76,11 @@ type Configurations struct { // LeaderIdentity is used by the TSS engine protocol to determine who is responsible for telling // the other guardians about a new VAAv1. LeaderIdentity PEM // The public key of the leader in PEM format. + + // AllowedChainIDs is a map of chain IDs that the TSS signer is allowed to sign. + // If nil or empty, TSS is disabled for all chains. + // The key is the chain ID, and the value should be true for allowed chains. + AllowedChainIDs map[vaa.ChainID]bool } // GuardianStorage is a struct that holds the data needed for a guardian to participate in the TSS protocol @@ -164,6 +169,23 @@ func (t *Engine) beginTSSSign(vaaDigest []byte, chainID vaa.ChainID, consistency return fmt.Errorf("vaaDigest length is not 32 bytes") } + // Check if this chain ID is allowed for TSS signing + if len(t.AllowedChainIDs) > 0 { + if !t.AllowedChainIDs[chainID] { + t.logger.Info("skipping TSS signing for filtered chain ID", + zap.String("chainID", chainID.String()), + zap.String("digest", fmt.Sprintf("%x", vaaDigest)), + ) + return nil + } + } else { + t.logger.Info("TSS signing is disabled for all chains", + zap.String("chainID", chainID.String()), + zap.String("digest", fmt.Sprintf("%x", vaaDigest)), + ) + return nil + } + d := party.Digest{} copy(d[:], vaaDigest) diff --git a/sdk/vaa/structs.go b/sdk/vaa/structs.go index 1b4c42d7d0..aa0c7c6508 100644 --- a/sdk/vaa/structs.go +++ b/sdk/vaa/structs.go @@ -402,6 +402,11 @@ const ( // TSSVaaVersion uses a threshold signature scheme to sign the VAA struct. // As a result, a valid VAA would result in a single signature. TSSVaaVersion = 0x02 + + // The schnorr signature is consituted by: + // - r: 20 bytes + // - s: 32 bytes + SchnorrSigLength = 52 ) var SupportedVAAVersions = map[uint8]bool{VaaVersion1: true, TSSVaaVersion: true} @@ -474,27 +479,41 @@ func Unmarshal(data []byte) (*VAA, error) { return nil, fmt.Errorf("failed to read guardian set index: %w", err) } - lenSignatures, er := reader.ReadByte() - if er != nil { - return nil, fmt.Errorf("failed to read signature length") - } - - v.Signatures = make([]*Signature, lenSignatures) - for i := 0; i < int(lenSignatures); i++ { - index, err := reader.ReadByte() - if err != nil { - return nil, fmt.Errorf("failed to read validator index [%d]", i) + if v.Version == 1 { + lenSignatures, er := reader.ReadByte() + if er != nil { + return nil, fmt.Errorf("failed to read signature length") } + v.Signatures = make([]*Signature, lenSignatures) + for i := 0; i < int(lenSignatures); i++ { + index, err := reader.ReadByte() + if err != nil { + return nil, fmt.Errorf("failed to read validator index [%d]", i) + } + + signature := [65]byte{} + if n, err := reader.Read(signature[:]); err != nil || n != 65 { + return nil, fmt.Errorf("failed to read signature [%d]: %w", i, err) + } + + v.Signatures[i] = &Signature{ + Index: index, + Signature: signature, + } + } + } else if v.Version == 2 { + v.Signatures = make([]*Signature, 1) signature := [65]byte{} - if n, err := reader.Read(signature[:]); err != nil || n != 65 { - return nil, fmt.Errorf("failed to read signature [%d]: %w", i, err) + if n, err := reader.Read(signature[:SchnorrSigLength]); err != nil || n != SchnorrSigLength { + return nil, fmt.Errorf("failed to read schnorr signature: %w", err) } - - v.Signatures[i] = &Signature{ - Index: index, + v.Signatures[0] = &Signature{ + Index: 0, Signature: signature, } + } else { + return nil, fmt.Errorf("failed to read VAA version %d", v.Version) } return UnmarshalBody(data, reader, v) @@ -707,10 +726,27 @@ func (v *VAA) Marshal() ([]byte, error) { MustWrite(buf, binary.BigEndian, v.GuardianSetIndex) // Write signatures - MustWrite(buf, binary.BigEndian, uint8(len(v.Signatures))) // #nosec G115 -- There will never be 256 guardians - for _, sig := range v.Signatures { - MustWrite(buf, binary.BigEndian, sig.Index) - buf.Write(sig.Signature[:]) + switch v.Version { + case VaaVersion1: + MustWrite(buf, binary.BigEndian, uint8(len(v.Signatures))) // #nosec G115 -- There will never be 256 guardians + for _, sig := range v.Signatures { + MustWrite(buf, binary.BigEndian, sig.Index) + buf.Write(sig.Signature[:]) + } + case TSSVaaVersion: + if len(v.Signatures) != 1 { + panic(fmt.Errorf("tried to serialize v2 VAA with %d signatures", len(v.Signatures)).Error()) + } + + sig := v.Signatures[0] + zeroSlice := sig.Signature[SchnorrSigLength:] + if !bytes.Equal(zeroSlice, make([]byte, len(zeroSlice))) { + panic(fmt.Errorf("tried to serialize v2 VAA with invalid signature").Error()) + } + + buf.Write(sig.Signature[:SchnorrSigLength]) + default: + panic(fmt.Errorf("tried to serialize VAA version %d", v.Version).Error()) } // Write Body