From: LonelyPale Date: Thu, 11 Nov 2021 09:11:26 +0000 (+0800) Subject: update gm X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=a2524758ec0a53776f22e974ee9635af9c164300;p=bytom%2Fbytom.git update gm --- diff --git a/blockchain/txbuilder/signature_witness.go b/blockchain/txbuilder/signature_witness.go index 67d81b8e..3997bf9c 100644 --- a/blockchain/txbuilder/signature_witness.go +++ b/blockchain/txbuilder/signature_witness.go @@ -1,3 +1,5 @@ +// +build !gm + package txbuilder import ( diff --git a/blockchain/txbuilder/signature_witness_gm.go b/blockchain/txbuilder/signature_witness_gm.go new file mode 100644 index 00000000..c3163632 --- /dev/null +++ b/blockchain/txbuilder/signature_witness_gm.go @@ -0,0 +1,136 @@ +// +build gm + +package txbuilder + +import ( + "context" + "encoding/json" + + log "github.com/sirupsen/logrus" + + "github.com/bytom/bytom/crypto/ed25519/chainkd" + sm3util "github.com/bytom/bytom/crypto/sm3" + chainjson "github.com/bytom/bytom/encoding/json" + "github.com/bytom/bytom/errors" + "github.com/bytom/bytom/protocol/vm" +) + +type ( + // SignatureWitness is a sign struct + SignatureWitness struct { + // Quorum is the number of signatures required. + Quorum int `json:"quorum"` + + // Keys are the identities of the keys to sign with. + Keys []keyID `json:"keys"` + + // Program is the predicate part of the signature program, whose hash is what gets + // signed. If empty, it is computed during Sign from the outputs + // and the current input of the transaction. + Program chainjson.HexBytes `json:"program"` + + // Sigs are signatures of Program made from each of the Keys + // during Sign. + Sigs []chainjson.HexBytes `json:"signatures"` + } + + keyID struct { + XPub chainkd.XPub `json:"xpub"` + DerivationPath []chainjson.HexBytes `json:"derivation_path"` + } +) + +// ErrEmptyProgram is a type of error +var ErrEmptyProgram = errors.New("empty signature program") + +// Sign populates sw.Sigs with as many signatures of the predicate in +// sw.Program as it can from the overlapping set of keys in sw.Keys. +// +// If sw.Program is empty, it is populated with an _inferred_ predicate: +// a program committing to aspects of the current +// transaction. Specifically, the program commits to: +// - the mintime and maxtime of the transaction (if non-zero) +// - the outputID of the current input +// - the assetID, amount, control program of each output. +func (sw *SignatureWitness) sign(ctx context.Context, tpl *Template, index uint32, auth string, signFn SignFunc) error { + // Compute the predicate to sign. This is either a + // txsighash program if tpl.AllowAdditional is false (i.e., the tx is complete + // and no further changes are allowed) or a program enforcing + // constraints derived from the existing outputs and current input. + if len(sw.Program) == 0 { + var err error + sw.Program, err = buildSigProgram(tpl, tpl.SigningInstructions[index].Position) + if err != nil { + return err + } + if len(sw.Program) == 0 { + return ErrEmptyProgram + } + } + if len(sw.Sigs) < len(sw.Keys) { + // Each key in sw.Keys may produce a signature in sw.Sigs. Make + // sure there are enough slots in sw.Sigs and that we preserve any + // sigs already present. + newSigs := make([]chainjson.HexBytes, len(sw.Keys)) + copy(newSigs, sw.Sigs) + sw.Sigs = newSigs + } + var h [32]byte + sm3util.Sum(h[:], sw.Program) + for i, keyID := range sw.Keys { + if len(sw.Sigs[i]) > 0 { + // Already have a signature for this key + continue + } + path := make([][]byte, len(keyID.DerivationPath)) + for i, p := range keyID.DerivationPath { + path[i] = p + } + sigBytes, err := signFn(ctx, keyID.XPub, path, h, auth) + if err != nil { + log.WithFields(log.Fields{"module": logModule, "err": err}).Warningf("computing signature %d", i) + continue + } + + // This break is ordered to avoid signing transaction successfully only once for a multiple-sign account + // that consist of different keys by the same password. Exit immediately when the signature is success, + // it means that only one signature will be successful in the loop for this multiple-sign account. + sw.Sigs[i] = sigBytes + break + } + return nil +} + +func (sw SignatureWitness) materialize(args *[][]byte) error { + // This is the value of N for the CHECKPREDICATE call. The code + // assumes that everything already in the arg list before this call + // to Materialize is input to the signature program, so N is + // len(*args). + *args = append(*args, vm.Uint64Bytes(uint64(len(*args)))) + + var nsigs int + for i := 0; i < len(sw.Sigs) && nsigs < sw.Quorum; i++ { + if len(sw.Sigs[i]) > 0 { + *args = append(*args, sw.Sigs[i]) + nsigs++ + } + } + *args = append(*args, sw.Program) + return nil +} + +// MarshalJSON convert struct to json +func (sw SignatureWitness) MarshalJSON() ([]byte, error) { + obj := struct { + Type string `json:"type"` + Quorum int `json:"quorum"` + Keys []keyID `json:"keys"` + Sigs []chainjson.HexBytes `json:"signatures"` + }{ + Type: "signature", + Quorum: sw.Quorum, + Keys: sw.Keys, + Sigs: sw.Sigs, + } + return json.Marshal(obj) +}