-
Notifications
You must be signed in to change notification settings - Fork 210
/
multisig.go
71 lines (60 loc) · 1.8 KB
/
multisig.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
package multisig
import (
"fmt"
"github.com/oasisprotocol/curve25519-voi/primitives/ed25519"
"github.com/spacemeshos/go-scale"
"github.com/spacemeshos/go-spacemesh/genvm/core"
)
//go:generate scalegen
// MultiSig K/N template.
type MultiSig struct {
Required uint8
PublicKeys []core.PublicKey `scale:"max=10"`
}
func (ms *MultiSig) BaseGas(method uint8) uint64 {
return BaseGas(method, int(ms.Required))
}
func (ms *MultiSig) LoadGas() uint64 {
return LoadGas(len(ms.PublicKeys))
}
func (ms *MultiSig) ExecGas(method uint8) uint64 {
return ExecGas(method, len(ms.PublicKeys))
}
// MaxSpend returns amount specified in the SpendArguments.
func (ms *MultiSig) MaxSpend(method uint8, args any) (uint64, error) {
switch method {
case core.MethodSpawn:
return 0, nil
case core.MethodSpend:
return args.(*SpendArguments).Amount, nil
default:
return 0, fmt.Errorf("%w: unknown method %d", core.ErrMalformed, method)
}
}
// Verify that transaction is signed has k valid signatures.
func (ms *MultiSig) Verify(host core.Host, raw []byte, dec *scale.Decoder) bool {
sig := make(Signatures, ms.Required)
n, err := scale.DecodeStructArray(dec, sig)
if err != nil {
return false
}
body := core.SigningBody(host.GetGenesisID().Bytes(), raw[:len(raw)-n])
batch := ed25519.NewBatchVerifierWithCapacity(int(ms.Required))
last := uint8(0)
for i, part := range sig {
if part.Ref >= uint8(len(ms.PublicKeys)) {
return false
}
if i != 0 && part.Ref <= last {
return false
}
last = part.Ref
batch.Add(ms.PublicKeys[part.Ref][:], body, part.Sig[:])
}
verified, _ := batch.Verify(nil)
return verified
}
// Spend transfers an amount to the address specified in SpendArguments.
func (ms *MultiSig) Spend(host core.Host, args *SpendArguments) error {
return host.Transfer(args.Destination, args.Amount)
}