Skip to content
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

types: Fix PolicyTypeUnlockConditions validation #176

Merged
merged 1 commit into from
Jul 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 21 additions & 10 deletions types/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,20 +177,31 @@ func (p SpendPolicy) Verify(height uint64, medianTimestamp time.Time, sigHash Ha
case PolicyTypeUnlockConditions:
if err := verify(PolicyAbove(p.Timelock)); err != nil {
return err
} else if p.SignaturesRequired > 255 {
return fmt.Errorf("too many signatures required (%v > 255)", p.SignaturesRequired)
}
n := uint8(p.SignaturesRequired)
of := make([]SpendPolicy, len(p.PublicKeys))
for i, pk := range p.PublicKeys {
if pk.Algorithm != SpecifierEd25519 {
return fmt.Errorf("unsupported algorithm %v", pk.Algorithm)
} else if len(pk.Key) != len(PublicKey{}) {
return fmt.Errorf("invalid Ed25519 key length %v", len(pk.Key))
if p.SignaturesRequired == 0 || p.SignaturesRequired > uint64(len(p.PublicKeys[i:])) || p.SignaturesRequired > uint64(len(sigs)) {
break
}
of[i] = PolicyPublicKey(*(*PublicKey)(pk.Key))
switch pk.Algorithm {
case SpecifierEntropy:
return errors.New("policy uses an entropy public key")
case SpecifierEd25519:
var epk PublicKey
copy(epk[:], pk.Key)
if epk.VerifyHash(sigHash, sigs[0]) {
sigs = sigs[1:]
p.SignaturesRequired--
}
default:
// all other algorithms are considered valid by default
sigs = sigs[1:]
p.SignaturesRequired--
}
}
if p.SignaturesRequired == 0 {
return nil
}
return verify(PolicyThreshold(n, of))
return errors.New("threshold not reached")
default:
panic("invalid policy type") // developer error
}
Expand Down
29 changes: 29 additions & 0 deletions types/policy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,16 @@ func TestPolicyVerify(t *testing.T) {
[]Signature{key.SignHash(sigHash)},
false,
},
{
"exceed threshold with keys",
PolicyThreshold(1, []SpendPolicy{
PolicyPublicKey(pk),
PolicyPublicKey(pk),
}),
11,
[]Signature{key.SignHash(sigHash), key.SignHash(sigHash)},
false,
},
{
"lower threshold, neither valid",
PolicyThreshold(1, []SpendPolicy{
Expand Down Expand Up @@ -177,6 +187,15 @@ func TestPolicyVerify(t *testing.T) {
nil,
false,
},
{
"unlock conditions, superfluous signatures",
SpendPolicy{PolicyTypeUnlockConditions{
SignaturesRequired: 0,
}},
1,
[]Signature{key.SignHash(sigHash)},
false,
},
{
"unlock conditions, wrong signature algorithm",
SpendPolicy{PolicyTypeUnlockConditions{
Expand Down Expand Up @@ -223,6 +242,16 @@ func TestPolicyVerify(t *testing.T) {
[]Signature{key.SignHash(sigHash)},
true,
},
{
"unlock conditions, valid with extra pubkeys",
SpendPolicy{PolicyTypeUnlockConditions{
PublicKeys: []UnlockKey{pk.UnlockKey(), PublicKey{1, 2, 3}.UnlockKey(), pk.UnlockKey()},
SignaturesRequired: 2,
}},
1,
[]Signature{key.SignHash(sigHash), key.SignHash(sigHash)},
true,
},
} {
if err := test.p.Verify(test.height, time.Time{}, sigHash, test.sigs, nil); err != nil && test.valid {
t.Fatalf("%v: %v", test.desc, err)
Expand Down
Loading