Repository navigation
node: updates serialize and deserialize for v2 VAAs #27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: schnorr
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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 constituted 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 == VaaVersion1 { | ||
| 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 == TSSVaaVersion { | ||
| 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,26 @@ 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[:]) | ||
| if v.Version == 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[:]) | ||
| } | ||
| } else if v.Version == TSSVaaVersion { | ||
| if len(v.Signatures) != 1 { | ||
| panic(fmt.Errorf("tried to serialize v2 VAA with %d signatures", len(v.Signatures)).Error()) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is better to return an error rather than panic here (and below, too).
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you know what kind of errors we should be returning? I never saw code for this so I don't know the best way to do it. |
||
| } | ||
|
|
||
| sig := v.Signatures[0] | ||
| zeroSlice := sig.Signature[SchnorrSigLength:] | ||
| if !bytes.Equal(zeroSlice, make([]byte, len(zeroSlice))) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure I follow this line.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The type definition for
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm a bit wary of changing the type definition. Maybe it's not terrible to do it but I'm a bit unsure it's viable. |
||
| panic(fmt.Errorf("tried to serialize v2 VAA with invalid signature").Error()) | ||
| } | ||
|
|
||
| buf.Write(sig.Signature[:SchnorrSigLength]) | ||
|
scnale marked this conversation as resolved.
Resolved
scnale marked this conversation as resolved.
Resolved
|
||
| } else { | ||
| panic(fmt.Errorf("tried to serialize VAA version %d", v.Version).Error()) | ||
| } | ||
|
|
||
| // Write Body | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not correct at the moment.
The output of the frost signature is common.SignatureData (which contains both S=32byte and R=33byte).
The processor translates it into a frost.Signature (65 byte), and stores it that way in the VAA (since we didn't export more than one signature verification function).
It is possible to convert the signature to the smart-contract format:
frostsig.ToContractSig()returns S, R, and Address(R).Does the VAA.Marshal() determine how signatures are passed to the smart contract?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey, yes, VAAs are the serialized format that gets submitted to smart contracts for verification.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I gather that we may be missing a conversion then, right?